@diagrammo/dgmo 0.21.1 → 0.23.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 +2230 -503
- package/dist/advanced.d.cts +5731 -0
- package/dist/advanced.d.ts +5731 -0
- package/dist/advanced.js +2226 -503
- package/dist/auto.cjs +2272 -479
- package/dist/auto.d.cts +39 -0
- package/dist/auto.d.ts +39 -0
- package/dist/auto.js +124 -124
- package/dist/auto.mjs +2274 -480
- package/dist/cli.cjs +170 -170
- package/dist/editor.cjs +16 -16
- package/dist/editor.js +16 -16
- package/dist/highlight.cjs +18 -13
- package/dist/highlight.js +18 -13
- package/dist/index.cjs +2253 -465
- package/dist/index.d.cts +339 -0
- package/dist/index.d.ts +339 -0
- package/dist/index.js +2255 -466
- package/dist/internal.cjs +2230 -503
- package/dist/internal.d.cts +5731 -0
- package/dist/internal.d.ts +5731 -0
- package/dist/internal.js +2226 -503
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/gazetteer.json +1 -1
- package/dist/map-data/mountain-ranges.json +1 -1
- package/dist/map-data/water-bodies.json +1 -0
- package/dist/map-data/world-coarse.json +1 -1
- package/dist/map-data/world-detail.json +1 -1
- package/docs/language-reference.md +55 -9
- package/gallery/fixtures/boxes-and-lines.dgmo +6 -4
- package/gallery/fixtures/map-categorical-world.dgmo +16 -0
- package/gallery/fixtures/map-categorical.dgmo +0 -1
- package/gallery/fixtures/map-choropleth.dgmo +0 -1
- package/gallery/fixtures/map-coastline.dgmo +7 -0
- package/gallery/fixtures/map-colorize.dgmo +11 -0
- package/gallery/fixtures/map-direct-color.dgmo +0 -1
- package/gallery/fixtures/map-reference-world.dgmo +11 -0
- package/gallery/fixtures/map-region-scope.dgmo +0 -3
- package/gallery/fixtures/map-route.dgmo +0 -1
- package/package.json +1 -1
- package/src/advanced.ts +12 -1
- package/src/boxes-and-lines/parser.ts +39 -0
- package/src/boxes-and-lines/renderer.ts +205 -20
- package/src/boxes-and-lines/types.ts +9 -0
- package/src/cli.ts +1 -1
- package/src/completion.ts +36 -30
- package/src/cycle/renderer.ts +14 -1
- package/src/d3.ts +20 -6
- package/src/editor/highlight-api.ts +4 -0
- package/src/editor/keywords.ts +16 -16
- package/src/infra/renderer.ts +35 -7
- package/src/map/colorize.ts +54 -0
- package/src/map/context-labels.ts +429 -0
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/README.md +6 -0
- package/src/map/data/gazetteer.json +1 -1
- package/src/map/data/mountain-ranges.json +1 -1
- package/src/map/data/types.ts +34 -0
- package/src/map/data/water-bodies.json +1 -0
- package/src/map/data/world-coarse.json +1 -1
- package/src/map/data/world-detail.json +1 -1
- package/src/map/dimensions.ts +117 -0
- package/src/map/geo-query.ts +21 -3
- package/src/map/geo.ts +47 -1
- package/src/map/layout.ts +1408 -266
- package/src/map/load-data.ts +10 -2
- package/src/map/parser.ts +42 -116
- package/src/map/renderer.ts +604 -14
- package/src/map/resolved-types.ts +16 -2
- package/src/map/resolver.ts +208 -59
- package/src/map/types.ts +30 -32
- package/src/mindmap/renderer.ts +10 -1
- package/src/palettes/atlas.ts +77 -0
- package/src/palettes/blueprint.ts +73 -0
- package/src/palettes/color-utils.ts +58 -1
- package/src/palettes/index.ts +12 -3
- package/src/palettes/slate.ts +73 -0
- package/src/palettes/tidewater.ts +73 -0
- package/src/render.ts +8 -1
- package/src/tech-radar/renderer.ts +3 -0
- package/src/tech-radar/types.ts +3 -0
- package/src/utils/d3-types.ts +5 -0
- package/src/utils/legend-layout.ts +21 -4
- package/src/utils/legend-types.ts +7 -0
- package/src/utils/reserved-key-registry.ts +8 -3
- package/src/palettes/bold.ts +0 -67
package/dist/internal.js
CHANGED
|
@@ -371,18 +371,18 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
371
371
|
const results = [];
|
|
372
372
|
for (let i = 0; i < points.length; i++) {
|
|
373
373
|
const pt = points[i];
|
|
374
|
-
const
|
|
374
|
+
const labelWidth2 = pt.label.length * fontSize * CHAR_WIDTH_RATIO + 8;
|
|
375
375
|
let best = null;
|
|
376
376
|
const directions = [
|
|
377
377
|
{
|
|
378
378
|
// Above
|
|
379
379
|
gen: (offset) => {
|
|
380
|
-
const lx = pt.cx -
|
|
380
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
381
381
|
const ly = pt.cy - offset - labelHeight;
|
|
382
|
-
if (ly < chartBounds.top || lx < chartBounds.left || lx +
|
|
382
|
+
if (ly < chartBounds.top || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
383
383
|
return null;
|
|
384
384
|
return {
|
|
385
|
-
rect: { x: lx, y: ly, w:
|
|
385
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
386
386
|
textX: pt.cx,
|
|
387
387
|
textY: ly + labelHeight / 2,
|
|
388
388
|
anchor: "middle"
|
|
@@ -392,12 +392,12 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
392
392
|
{
|
|
393
393
|
// Below
|
|
394
394
|
gen: (offset) => {
|
|
395
|
-
const lx = pt.cx -
|
|
395
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
396
396
|
const ly = pt.cy + offset;
|
|
397
|
-
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx +
|
|
397
|
+
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
398
398
|
return null;
|
|
399
399
|
return {
|
|
400
|
-
rect: { x: lx, y: ly, w:
|
|
400
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
401
401
|
textX: pt.cx,
|
|
402
402
|
textY: ly + labelHeight / 2,
|
|
403
403
|
anchor: "middle"
|
|
@@ -409,10 +409,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
409
409
|
gen: (offset) => {
|
|
410
410
|
const lx = pt.cx + offset;
|
|
411
411
|
const ly = pt.cy - labelHeight / 2;
|
|
412
|
-
if (lx +
|
|
412
|
+
if (lx + labelWidth2 > chartBounds.right || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
413
413
|
return null;
|
|
414
414
|
return {
|
|
415
|
-
rect: { x: lx, y: ly, w:
|
|
415
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
416
416
|
textX: lx,
|
|
417
417
|
textY: pt.cy,
|
|
418
418
|
anchor: "start"
|
|
@@ -422,13 +422,13 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
422
422
|
{
|
|
423
423
|
// Left
|
|
424
424
|
gen: (offset) => {
|
|
425
|
-
const lx = pt.cx - offset -
|
|
425
|
+
const lx = pt.cx - offset - labelWidth2;
|
|
426
426
|
const ly = pt.cy - labelHeight / 2;
|
|
427
427
|
if (lx < chartBounds.left || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
428
428
|
return null;
|
|
429
429
|
return {
|
|
430
|
-
rect: { x: lx, y: ly, w:
|
|
431
|
-
textX: lx +
|
|
430
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
431
|
+
textX: lx + labelWidth2,
|
|
432
432
|
textY: pt.cy,
|
|
433
433
|
anchor: "end"
|
|
434
434
|
};
|
|
@@ -478,10 +478,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
478
478
|
}
|
|
479
479
|
}
|
|
480
480
|
if (!best) {
|
|
481
|
-
const lx = pt.cx -
|
|
481
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
482
482
|
const ly = pt.cy - minGap - labelHeight;
|
|
483
483
|
best = {
|
|
484
|
-
rect: { x: lx, y: ly, w:
|
|
484
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
485
485
|
textX: pt.cx,
|
|
486
486
|
textY: ly + labelHeight / 2,
|
|
487
487
|
anchor: "middle",
|
|
@@ -858,6 +858,9 @@ var init_reserved_key_registry = __esm({
|
|
|
858
858
|
"value",
|
|
859
859
|
"label",
|
|
860
860
|
"style"
|
|
861
|
+
// `surface:` was removed in the 2026-06-02 defaults-on review — it is no longer
|
|
862
|
+
// a recognized metadata key (the route/edge surface feature was cut; §24B.7).
|
|
863
|
+
// A stray `surface: water` is no longer captured as a reserved key.
|
|
861
864
|
]);
|
|
862
865
|
ORG_REGISTRY = staticRegistry([
|
|
863
866
|
"color",
|
|
@@ -912,9 +915,7 @@ var init_reserved_key_registry = __esm({
|
|
|
912
915
|
BOXES_AND_LINES_REGISTRY = staticRegistry([
|
|
913
916
|
"color",
|
|
914
917
|
"description",
|
|
915
|
-
"
|
|
916
|
-
"split",
|
|
917
|
-
"fanout"
|
|
918
|
+
"value"
|
|
918
919
|
]);
|
|
919
920
|
TIMELINE_REGISTRY = staticRegistry([
|
|
920
921
|
"color",
|
|
@@ -1920,77 +1921,266 @@ function getSegmentColors(palette, count) {
|
|
|
1920
1921
|
(_, i) => hslToHex(Math.round((startHue + i * step) % 360), avgS, avgL)
|
|
1921
1922
|
);
|
|
1922
1923
|
}
|
|
1924
|
+
function politicalTints(palette, count, isDark) {
|
|
1925
|
+
if (count <= 0) return [];
|
|
1926
|
+
const base = isDark ? palette.surface : palette.bg;
|
|
1927
|
+
const c = palette.colors;
|
|
1928
|
+
const swatches = [
|
|
1929
|
+
.../* @__PURE__ */ new Set([
|
|
1930
|
+
c.green,
|
|
1931
|
+
c.yellow,
|
|
1932
|
+
c.orange,
|
|
1933
|
+
c.purple,
|
|
1934
|
+
c.red,
|
|
1935
|
+
c.teal,
|
|
1936
|
+
c.cyan,
|
|
1937
|
+
c.blue
|
|
1938
|
+
])
|
|
1939
|
+
];
|
|
1940
|
+
const bands = isDark ? POLITICAL_TINT_BANDS.dark : POLITICAL_TINT_BANDS.light;
|
|
1941
|
+
const out = [];
|
|
1942
|
+
for (const pct of bands) {
|
|
1943
|
+
if (out.length >= count) break;
|
|
1944
|
+
for (const s of swatches) out.push(mix(s, base, pct));
|
|
1945
|
+
}
|
|
1946
|
+
return out.slice(0, count);
|
|
1947
|
+
}
|
|
1948
|
+
var POLITICAL_TINT_BANDS;
|
|
1923
1949
|
var init_color_utils = __esm({
|
|
1924
1950
|
"src/palettes/color-utils.ts"() {
|
|
1925
1951
|
"use strict";
|
|
1952
|
+
POLITICAL_TINT_BANDS = {
|
|
1953
|
+
light: [32, 48, 64, 80],
|
|
1954
|
+
dark: [44, 58, 72, 86]
|
|
1955
|
+
};
|
|
1926
1956
|
}
|
|
1927
1957
|
});
|
|
1928
1958
|
|
|
1929
|
-
// src/palettes/
|
|
1930
|
-
var
|
|
1931
|
-
var
|
|
1932
|
-
"src/palettes/
|
|
1959
|
+
// src/palettes/atlas.ts
|
|
1960
|
+
var atlasPalette;
|
|
1961
|
+
var init_atlas = __esm({
|
|
1962
|
+
"src/palettes/atlas.ts"() {
|
|
1933
1963
|
"use strict";
|
|
1934
1964
|
init_registry();
|
|
1935
|
-
|
|
1936
|
-
id: "
|
|
1937
|
-
name: "
|
|
1965
|
+
atlasPalette = {
|
|
1966
|
+
id: "atlas",
|
|
1967
|
+
name: "Atlas",
|
|
1938
1968
|
light: {
|
|
1939
|
-
bg: "#
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1969
|
+
bg: "#f3ead3",
|
|
1970
|
+
// warm manila / parchment
|
|
1971
|
+
surface: "#ece0c0",
|
|
1972
|
+
// deeper paper (cards, panels)
|
|
1973
|
+
overlay: "#e8dab8",
|
|
1974
|
+
// popovers, dropdowns
|
|
1975
|
+
border: "#bcaa86",
|
|
1976
|
+
// muted sepia rule line
|
|
1977
|
+
text: "#463a26",
|
|
1978
|
+
// aged sepia-brown ink
|
|
1979
|
+
textMuted: "#7a6a4f",
|
|
1980
|
+
// faded annotation ink
|
|
1981
|
+
textOnFillLight: "#f7f1de",
|
|
1982
|
+
// parchment (light text on dark fills)
|
|
1983
|
+
textOnFillDark: "#3a2e1c",
|
|
1984
|
+
// deep ink (dark text on light fills)
|
|
1985
|
+
primary: "#5b7a99",
|
|
1986
|
+
// pull-down map ocean (steel-blue)
|
|
1987
|
+
secondary: "#7e9a6f",
|
|
1988
|
+
// lowland sage / celadon
|
|
1989
|
+
accent: "#b07f7c",
|
|
1990
|
+
// dusty rose
|
|
1991
|
+
destructive: "#b25a45",
|
|
1992
|
+
// brick / terracotta
|
|
1951
1993
|
colors: {
|
|
1952
|
-
red: "#
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1994
|
+
red: "#bf6a52",
|
|
1995
|
+
// terracotta brick
|
|
1996
|
+
orange: "#cf9a5c",
|
|
1997
|
+
// map tan / ochre
|
|
1998
|
+
yellow: "#cdb35e",
|
|
1999
|
+
// straw / muted lemon
|
|
2000
|
+
green: "#7e9a6f",
|
|
2001
|
+
// sage / celadon lowland
|
|
2002
|
+
blue: "#5b7a99",
|
|
2003
|
+
// steel-blue ocean
|
|
2004
|
+
purple: "#9a7fa6",
|
|
2005
|
+
// dusty lilac / mauve
|
|
2006
|
+
teal: "#6fa094",
|
|
2007
|
+
// muted seafoam
|
|
2008
|
+
cyan: "#79a7b5",
|
|
2009
|
+
// shallow-water blue
|
|
2010
|
+
gray: "#8a7d68",
|
|
2011
|
+
// warm taupe
|
|
2012
|
+
black: "#463a26",
|
|
2013
|
+
// ink
|
|
2014
|
+
white: "#ece0c0"
|
|
2015
|
+
// paper
|
|
1963
2016
|
}
|
|
1964
2017
|
},
|
|
1965
2018
|
dark: {
|
|
1966
|
-
bg: "#
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
2019
|
+
bg: "#1e2a33",
|
|
2020
|
+
// deep map ocean (night globe)
|
|
2021
|
+
surface: "#27353f",
|
|
2022
|
+
// raised ocean
|
|
2023
|
+
overlay: "#2e3d48",
|
|
2024
|
+
// popovers, dropdowns
|
|
2025
|
+
border: "#3d4f5c",
|
|
2026
|
+
// depth-contour line
|
|
2027
|
+
text: "#e8dcc0",
|
|
2028
|
+
// parchment ink, inverted
|
|
2029
|
+
textMuted: "#a89a7d",
|
|
2030
|
+
// faded label
|
|
2031
|
+
textOnFillLight: "#f7f1de",
|
|
2032
|
+
// parchment
|
|
2033
|
+
textOnFillDark: "#1a242c",
|
|
2034
|
+
// deep ocean ink
|
|
2035
|
+
primary: "#7ba0bf",
|
|
2036
|
+
// brighter ocean
|
|
2037
|
+
secondary: "#9bb588",
|
|
2038
|
+
// sage, lifted
|
|
2039
|
+
accent: "#cf9a96",
|
|
2040
|
+
// dusty rose, lifted
|
|
2041
|
+
destructive: "#c9745c",
|
|
2042
|
+
// brick, lifted
|
|
2043
|
+
colors: {
|
|
2044
|
+
red: "#cf7a60",
|
|
2045
|
+
// terracotta
|
|
2046
|
+
orange: "#d9a96a",
|
|
2047
|
+
// tan / ochre
|
|
2048
|
+
yellow: "#d8c074",
|
|
2049
|
+
// straw
|
|
2050
|
+
green: "#9bb588",
|
|
2051
|
+
// sage lowland
|
|
2052
|
+
blue: "#7ba0bf",
|
|
2053
|
+
// ocean
|
|
2054
|
+
purple: "#b59ac0",
|
|
2055
|
+
// lilac / mauve
|
|
2056
|
+
teal: "#85b3a6",
|
|
2057
|
+
// seafoam
|
|
2058
|
+
cyan: "#92bccb",
|
|
2059
|
+
// shallow-water blue
|
|
2060
|
+
gray: "#9a8d76",
|
|
2061
|
+
// warm taupe
|
|
2062
|
+
black: "#27353f",
|
|
2063
|
+
// raised ocean
|
|
2064
|
+
white: "#e8dcc0"
|
|
2065
|
+
// parchment
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
};
|
|
2069
|
+
registerPalette(atlasPalette);
|
|
2070
|
+
}
|
|
2071
|
+
});
|
|
2072
|
+
|
|
2073
|
+
// src/palettes/blueprint.ts
|
|
2074
|
+
var blueprintPalette;
|
|
2075
|
+
var init_blueprint = __esm({
|
|
2076
|
+
"src/palettes/blueprint.ts"() {
|
|
2077
|
+
"use strict";
|
|
2078
|
+
init_registry();
|
|
2079
|
+
blueprintPalette = {
|
|
2080
|
+
id: "blueprint",
|
|
2081
|
+
name: "Blueprint",
|
|
2082
|
+
light: {
|
|
2083
|
+
bg: "#f4f8fb",
|
|
2084
|
+
// pale drafting white (faint cyan)
|
|
2085
|
+
surface: "#e6eef4",
|
|
2086
|
+
// drafting panel
|
|
2087
|
+
overlay: "#dde9f1",
|
|
2088
|
+
// popovers, dropdowns
|
|
2089
|
+
border: "#aac3d6",
|
|
2090
|
+
// pale blue grid line
|
|
2091
|
+
text: "#123a5e",
|
|
2092
|
+
// blueprint navy ink
|
|
2093
|
+
textMuted: "#4f7390",
|
|
2094
|
+
// faint draft note
|
|
2095
|
+
textOnFillLight: "#f4f8fb",
|
|
2096
|
+
// drafting white
|
|
2097
|
+
textOnFillDark: "#0c2f4d",
|
|
2098
|
+
// deep blueprint navy
|
|
2099
|
+
primary: "#1f5e8c",
|
|
2100
|
+
// blueprint blue
|
|
2101
|
+
secondary: "#5b7d96",
|
|
2102
|
+
// steel
|
|
2103
|
+
accent: "#b08a3e",
|
|
2104
|
+
// draftsman's ochre highlight
|
|
2105
|
+
destructive: "#c0504d",
|
|
2106
|
+
// correction red
|
|
2107
|
+
colors: {
|
|
2108
|
+
red: "#c25a4e",
|
|
2109
|
+
// correction red
|
|
2110
|
+
orange: "#c2823e",
|
|
2111
|
+
// ochre
|
|
2112
|
+
yellow: "#c2a843",
|
|
2113
|
+
// pencil gold
|
|
2114
|
+
green: "#4f8a6b",
|
|
2115
|
+
// drafting green
|
|
2116
|
+
blue: "#1f5e8c",
|
|
2117
|
+
// blueprint blue
|
|
2118
|
+
purple: "#6f5e96",
|
|
2119
|
+
// indigo pencil
|
|
2120
|
+
teal: "#3a8a8a",
|
|
2121
|
+
// teal
|
|
2122
|
+
cyan: "#3f8fb5",
|
|
2123
|
+
// cyan
|
|
2124
|
+
gray: "#7e8e98",
|
|
2125
|
+
// graphite
|
|
2126
|
+
black: "#123a5e",
|
|
2127
|
+
// navy ink
|
|
2128
|
+
white: "#e6eef4"
|
|
2129
|
+
// panel
|
|
2130
|
+
}
|
|
2131
|
+
},
|
|
2132
|
+
dark: {
|
|
2133
|
+
bg: "#103a5e",
|
|
2134
|
+
// deep blueprint blue (cyanotype ground)
|
|
2135
|
+
surface: "#16466e",
|
|
2136
|
+
// raised sheet
|
|
2137
|
+
overlay: "#1c5180",
|
|
2138
|
+
// popovers, dropdowns
|
|
2139
|
+
border: "#3a6f96",
|
|
2140
|
+
// grid line
|
|
2141
|
+
text: "#eaf2f8",
|
|
2142
|
+
// chalk white
|
|
2143
|
+
textMuted: "#9fc0d6",
|
|
2144
|
+
// faint chalk note
|
|
2145
|
+
textOnFillLight: "#eaf2f8",
|
|
2146
|
+
// chalk white
|
|
2147
|
+
textOnFillDark: "#0c2f4d",
|
|
2148
|
+
// deep blueprint navy
|
|
2149
|
+
primary: "#7fb8d8",
|
|
2150
|
+
// chalk cyan
|
|
2151
|
+
secondary: "#9fb8c8",
|
|
2152
|
+
// pale steel
|
|
2153
|
+
accent: "#d8c27a",
|
|
2154
|
+
// chalk amber
|
|
2155
|
+
destructive: "#e08a7a",
|
|
2156
|
+
// chalk correction red
|
|
1978
2157
|
colors: {
|
|
1979
|
-
red: "#
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2158
|
+
red: "#e0907e",
|
|
2159
|
+
// chalk red
|
|
2160
|
+
orange: "#e0ab78",
|
|
2161
|
+
// chalk amber
|
|
2162
|
+
yellow: "#e3d089",
|
|
2163
|
+
// chalk gold
|
|
2164
|
+
green: "#93c79e",
|
|
2165
|
+
// chalk green
|
|
2166
|
+
blue: "#8ec3e0",
|
|
2167
|
+
// chalk cyan-blue
|
|
2168
|
+
purple: "#b6a6d8",
|
|
2169
|
+
// chalk indigo
|
|
2170
|
+
teal: "#84c7c2",
|
|
2171
|
+
// chalk teal
|
|
2172
|
+
cyan: "#9fd6e0",
|
|
2173
|
+
// chalk cyan
|
|
2174
|
+
gray: "#aebecb",
|
|
2175
|
+
// chalk graphite
|
|
2176
|
+
black: "#16466e",
|
|
2177
|
+
// raised sheet
|
|
2178
|
+
white: "#eaf2f8"
|
|
2179
|
+
// chalk white
|
|
1990
2180
|
}
|
|
1991
2181
|
}
|
|
1992
2182
|
};
|
|
1993
|
-
registerPalette(
|
|
2183
|
+
registerPalette(blueprintPalette);
|
|
1994
2184
|
}
|
|
1995
2185
|
});
|
|
1996
2186
|
|
|
@@ -2487,6 +2677,120 @@ var init_rose_pine = __esm({
|
|
|
2487
2677
|
}
|
|
2488
2678
|
});
|
|
2489
2679
|
|
|
2680
|
+
// src/palettes/slate.ts
|
|
2681
|
+
var slatePalette;
|
|
2682
|
+
var init_slate = __esm({
|
|
2683
|
+
"src/palettes/slate.ts"() {
|
|
2684
|
+
"use strict";
|
|
2685
|
+
init_registry();
|
|
2686
|
+
slatePalette = {
|
|
2687
|
+
id: "slate",
|
|
2688
|
+
name: "Slate",
|
|
2689
|
+
light: {
|
|
2690
|
+
bg: "#ffffff",
|
|
2691
|
+
// clean slide white
|
|
2692
|
+
surface: "#f3f5f8",
|
|
2693
|
+
// light cool-gray panel
|
|
2694
|
+
overlay: "#eaeef3",
|
|
2695
|
+
// popovers, dropdowns
|
|
2696
|
+
border: "#d4dae1",
|
|
2697
|
+
// hairline rule
|
|
2698
|
+
text: "#1f2933",
|
|
2699
|
+
// near-black slate (softer than pure black)
|
|
2700
|
+
textMuted: "#5b6672",
|
|
2701
|
+
// secondary label
|
|
2702
|
+
textOnFillLight: "#ffffff",
|
|
2703
|
+
// light text on dark fills
|
|
2704
|
+
textOnFillDark: "#1f2933",
|
|
2705
|
+
// dark text on light fills
|
|
2706
|
+
primary: "#3b6ea5",
|
|
2707
|
+
// confident corporate blue
|
|
2708
|
+
secondary: "#5b6672",
|
|
2709
|
+
// slate gray
|
|
2710
|
+
accent: "#3a9188",
|
|
2711
|
+
// muted teal accent
|
|
2712
|
+
destructive: "#c0504d",
|
|
2713
|
+
// brick red
|
|
2714
|
+
colors: {
|
|
2715
|
+
red: "#c0504d",
|
|
2716
|
+
// brick
|
|
2717
|
+
orange: "#cc7a33",
|
|
2718
|
+
// muted amber
|
|
2719
|
+
yellow: "#c9a227",
|
|
2720
|
+
// gold (not neon)
|
|
2721
|
+
green: "#5b9357",
|
|
2722
|
+
// forest / sage
|
|
2723
|
+
blue: "#3b6ea5",
|
|
2724
|
+
// corporate blue
|
|
2725
|
+
purple: "#7d5ba6",
|
|
2726
|
+
// muted violet
|
|
2727
|
+
teal: "#3a9188",
|
|
2728
|
+
// teal
|
|
2729
|
+
cyan: "#4f96c4",
|
|
2730
|
+
// steel cyan
|
|
2731
|
+
gray: "#7e8a97",
|
|
2732
|
+
// cool gray
|
|
2733
|
+
black: "#1f2933",
|
|
2734
|
+
// slate ink
|
|
2735
|
+
white: "#f3f5f8"
|
|
2736
|
+
// panel
|
|
2737
|
+
}
|
|
2738
|
+
},
|
|
2739
|
+
dark: {
|
|
2740
|
+
bg: "#161b22",
|
|
2741
|
+
// deep slate (keynote dark)
|
|
2742
|
+
surface: "#202833",
|
|
2743
|
+
// raised panel
|
|
2744
|
+
overlay: "#29323e",
|
|
2745
|
+
// popovers, dropdowns
|
|
2746
|
+
border: "#38424f",
|
|
2747
|
+
// divider
|
|
2748
|
+
text: "#e6eaef",
|
|
2749
|
+
// off-white
|
|
2750
|
+
textMuted: "#9aa5b1",
|
|
2751
|
+
// secondary label
|
|
2752
|
+
textOnFillLight: "#ffffff",
|
|
2753
|
+
// light text on dark fills
|
|
2754
|
+
textOnFillDark: "#161b22",
|
|
2755
|
+
// dark text on light fills
|
|
2756
|
+
primary: "#5b9bd5",
|
|
2757
|
+
// lifted corporate blue
|
|
2758
|
+
secondary: "#8593a3",
|
|
2759
|
+
// slate gray, lifted
|
|
2760
|
+
accent: "#45b3a3",
|
|
2761
|
+
// teal, lifted
|
|
2762
|
+
destructive: "#e07b6e",
|
|
2763
|
+
// brick, lifted
|
|
2764
|
+
colors: {
|
|
2765
|
+
red: "#e07b6e",
|
|
2766
|
+
// brick
|
|
2767
|
+
orange: "#e0975a",
|
|
2768
|
+
// amber
|
|
2769
|
+
yellow: "#d9bd5a",
|
|
2770
|
+
// gold
|
|
2771
|
+
green: "#74b56e",
|
|
2772
|
+
// forest / sage
|
|
2773
|
+
blue: "#5b9bd5",
|
|
2774
|
+
// corporate blue
|
|
2775
|
+
purple: "#a585c9",
|
|
2776
|
+
// violet
|
|
2777
|
+
teal: "#45b3a3",
|
|
2778
|
+
// teal
|
|
2779
|
+
cyan: "#62b0d9",
|
|
2780
|
+
// steel cyan
|
|
2781
|
+
gray: "#95a1ae",
|
|
2782
|
+
// cool gray
|
|
2783
|
+
black: "#202833",
|
|
2784
|
+
// raised panel
|
|
2785
|
+
white: "#e6eaef"
|
|
2786
|
+
// off-white
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
};
|
|
2790
|
+
registerPalette(slatePalette);
|
|
2791
|
+
}
|
|
2792
|
+
});
|
|
2793
|
+
|
|
2490
2794
|
// src/palettes/solarized.ts
|
|
2491
2795
|
var solarizedPalette;
|
|
2492
2796
|
var init_solarized = __esm({
|
|
@@ -2582,6 +2886,120 @@ var init_solarized = __esm({
|
|
|
2582
2886
|
}
|
|
2583
2887
|
});
|
|
2584
2888
|
|
|
2889
|
+
// src/palettes/tidewater.ts
|
|
2890
|
+
var tidewaterPalette;
|
|
2891
|
+
var init_tidewater = __esm({
|
|
2892
|
+
"src/palettes/tidewater.ts"() {
|
|
2893
|
+
"use strict";
|
|
2894
|
+
init_registry();
|
|
2895
|
+
tidewaterPalette = {
|
|
2896
|
+
id: "tidewater",
|
|
2897
|
+
name: "Tidewater",
|
|
2898
|
+
light: {
|
|
2899
|
+
bg: "#eceff0",
|
|
2900
|
+
// weathered sea-mist paper
|
|
2901
|
+
surface: "#e0e4e3",
|
|
2902
|
+
// worn deck panel
|
|
2903
|
+
overlay: "#dadfdf",
|
|
2904
|
+
// popovers, dropdowns
|
|
2905
|
+
border: "#a9b2b3",
|
|
2906
|
+
// muted slate rule
|
|
2907
|
+
text: "#18313f",
|
|
2908
|
+
// ship's-log navy ink
|
|
2909
|
+
textMuted: "#51636b",
|
|
2910
|
+
// faded log entry
|
|
2911
|
+
textOnFillLight: "#f3f5f3",
|
|
2912
|
+
// weathered white
|
|
2913
|
+
textOnFillDark: "#162c38",
|
|
2914
|
+
// deep navy
|
|
2915
|
+
primary: "#1f4e6b",
|
|
2916
|
+
// deep-sea navy
|
|
2917
|
+
secondary: "#b08a4f",
|
|
2918
|
+
// rope / manila tan
|
|
2919
|
+
accent: "#c69a3e",
|
|
2920
|
+
// brass
|
|
2921
|
+
destructive: "#c1433a",
|
|
2922
|
+
// signal-flag red
|
|
2923
|
+
colors: {
|
|
2924
|
+
red: "#c1433a",
|
|
2925
|
+
// signal-flag red
|
|
2926
|
+
orange: "#cc7a38",
|
|
2927
|
+
// weathered amber
|
|
2928
|
+
yellow: "#d6bf5a",
|
|
2929
|
+
// brass gold
|
|
2930
|
+
green: "#4f8a6b",
|
|
2931
|
+
// sea-glass green
|
|
2932
|
+
blue: "#1f4e6b",
|
|
2933
|
+
// deep-sea navy
|
|
2934
|
+
purple: "#6a5a8c",
|
|
2935
|
+
// twilight harbor
|
|
2936
|
+
teal: "#3d8c8c",
|
|
2937
|
+
// sea-glass teal
|
|
2938
|
+
cyan: "#4f9bb5",
|
|
2939
|
+
// shallow water
|
|
2940
|
+
gray: "#8a8d86",
|
|
2941
|
+
// driftwood gray
|
|
2942
|
+
black: "#18313f",
|
|
2943
|
+
// navy ink
|
|
2944
|
+
white: "#e0e4e3"
|
|
2945
|
+
// deck panel
|
|
2946
|
+
}
|
|
2947
|
+
},
|
|
2948
|
+
dark: {
|
|
2949
|
+
bg: "#0f2230",
|
|
2950
|
+
// night-harbor deep sea
|
|
2951
|
+
surface: "#16303f",
|
|
2952
|
+
// raised hull
|
|
2953
|
+
overlay: "#1d3a4a",
|
|
2954
|
+
// popovers, dropdowns
|
|
2955
|
+
border: "#2c4856",
|
|
2956
|
+
// rigging line
|
|
2957
|
+
text: "#e6ebe8",
|
|
2958
|
+
// weathered white
|
|
2959
|
+
textMuted: "#9aaab0",
|
|
2960
|
+
// faded label
|
|
2961
|
+
textOnFillLight: "#f3f5f3",
|
|
2962
|
+
// weathered white
|
|
2963
|
+
textOnFillDark: "#0f2230",
|
|
2964
|
+
// deep sea
|
|
2965
|
+
primary: "#4f9bc4",
|
|
2966
|
+
// lifted sea blue
|
|
2967
|
+
secondary: "#c9a46a",
|
|
2968
|
+
// rope tan, lifted
|
|
2969
|
+
accent: "#d9b25a",
|
|
2970
|
+
// brass, lifted
|
|
2971
|
+
destructive: "#e06a5e",
|
|
2972
|
+
// signal red, lifted
|
|
2973
|
+
colors: {
|
|
2974
|
+
red: "#e06a5e",
|
|
2975
|
+
// signal-flag red
|
|
2976
|
+
orange: "#df9a52",
|
|
2977
|
+
// amber
|
|
2978
|
+
yellow: "#e0c662",
|
|
2979
|
+
// brass gold
|
|
2980
|
+
green: "#6fb58c",
|
|
2981
|
+
// sea-glass green
|
|
2982
|
+
blue: "#4f9bc4",
|
|
2983
|
+
// sea blue
|
|
2984
|
+
purple: "#9486bf",
|
|
2985
|
+
// twilight harbor
|
|
2986
|
+
teal: "#5cb0ac",
|
|
2987
|
+
// sea-glass teal
|
|
2988
|
+
cyan: "#62b4cf",
|
|
2989
|
+
// shallow water
|
|
2990
|
+
gray: "#9aa39c",
|
|
2991
|
+
// driftwood gray
|
|
2992
|
+
black: "#16303f",
|
|
2993
|
+
// raised hull
|
|
2994
|
+
white: "#e6ebe8"
|
|
2995
|
+
// weathered white
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
};
|
|
2999
|
+
registerPalette(tidewaterPalette);
|
|
3000
|
+
}
|
|
3001
|
+
});
|
|
3002
|
+
|
|
2585
3003
|
// src/palettes/tokyo-night.ts
|
|
2586
3004
|
var tokyoNightPalette;
|
|
2587
3005
|
var init_tokyo_night = __esm({
|
|
@@ -2857,7 +3275,8 @@ var init_monokai = __esm({
|
|
|
2857
3275
|
// src/palettes/index.ts
|
|
2858
3276
|
var palettes_exports = {};
|
|
2859
3277
|
__export(palettes_exports, {
|
|
2860
|
-
|
|
3278
|
+
atlasPalette: () => atlasPalette,
|
|
3279
|
+
blueprintPalette: () => blueprintPalette,
|
|
2861
3280
|
catppuccinPalette: () => catppuccinPalette,
|
|
2862
3281
|
contrastText: () => contrastText,
|
|
2863
3282
|
draculaPalette: () => draculaPalette,
|
|
@@ -2878,7 +3297,9 @@ __export(palettes_exports, {
|
|
|
2878
3297
|
rosePinePalette: () => rosePinePalette,
|
|
2879
3298
|
shade: () => shade,
|
|
2880
3299
|
shapeFill: () => shapeFill,
|
|
3300
|
+
slatePalette: () => slatePalette,
|
|
2881
3301
|
solarizedPalette: () => solarizedPalette,
|
|
3302
|
+
tidewaterPalette: () => tidewaterPalette,
|
|
2882
3303
|
tint: () => tint,
|
|
2883
3304
|
tokyoNightPalette: () => tokyoNightPalette
|
|
2884
3305
|
});
|
|
@@ -2888,17 +3309,21 @@ var init_palettes = __esm({
|
|
|
2888
3309
|
"use strict";
|
|
2889
3310
|
init_registry();
|
|
2890
3311
|
init_color_utils();
|
|
2891
|
-
|
|
3312
|
+
init_atlas();
|
|
3313
|
+
init_blueprint();
|
|
2892
3314
|
init_catppuccin();
|
|
2893
3315
|
init_gruvbox();
|
|
2894
3316
|
init_nord();
|
|
2895
3317
|
init_one_dark();
|
|
2896
3318
|
init_rose_pine();
|
|
3319
|
+
init_slate();
|
|
2897
3320
|
init_solarized();
|
|
3321
|
+
init_tidewater();
|
|
2898
3322
|
init_tokyo_night();
|
|
2899
3323
|
init_dracula();
|
|
2900
3324
|
init_monokai();
|
|
2901
|
-
|
|
3325
|
+
init_atlas();
|
|
3326
|
+
init_blueprint();
|
|
2902
3327
|
init_catppuccin();
|
|
2903
3328
|
init_dracula();
|
|
2904
3329
|
init_gruvbox();
|
|
@@ -2906,9 +3331,15 @@ var init_palettes = __esm({
|
|
|
2906
3331
|
init_nord();
|
|
2907
3332
|
init_one_dark();
|
|
2908
3333
|
init_rose_pine();
|
|
3334
|
+
init_slate();
|
|
2909
3335
|
init_solarized();
|
|
3336
|
+
init_tidewater();
|
|
2910
3337
|
init_tokyo_night();
|
|
2911
3338
|
palettes = {
|
|
3339
|
+
atlas: atlasPalette,
|
|
3340
|
+
blueprint: blueprintPalette,
|
|
3341
|
+
slate: slatePalette,
|
|
3342
|
+
tidewater: tidewaterPalette,
|
|
2912
3343
|
nord: nordPalette,
|
|
2913
3344
|
catppuccin: catppuccinPalette,
|
|
2914
3345
|
solarized: solarizedPalette,
|
|
@@ -2917,8 +3348,7 @@ var init_palettes = __esm({
|
|
|
2917
3348
|
oneDark: oneDarkPalette,
|
|
2918
3349
|
rosePine: rosePinePalette,
|
|
2919
3350
|
dracula: draculaPalette,
|
|
2920
|
-
monokai: monokaiPalette
|
|
2921
|
-
bold: boldPalette
|
|
3351
|
+
monokai: monokaiPalette
|
|
2922
3352
|
};
|
|
2923
3353
|
}
|
|
2924
3354
|
});
|
|
@@ -3428,6 +3858,9 @@ function controlsGroupCapsuleWidth(toggles) {
|
|
|
3428
3858
|
}
|
|
3429
3859
|
return w;
|
|
3430
3860
|
}
|
|
3861
|
+
function isAppHostedControls(config, isExport) {
|
|
3862
|
+
return !isExport && config.controlsHost === "app" && !!config.controlsGroup && config.controlsGroup.toggles.length > 0;
|
|
3863
|
+
}
|
|
3431
3864
|
function buildControlsGroupLayout(config, state) {
|
|
3432
3865
|
const cg = config.controlsGroup;
|
|
3433
3866
|
if (!cg || cg.toggles.length === 0) return void 0;
|
|
@@ -3481,6 +3914,7 @@ function buildControlsGroupLayout(config, state) {
|
|
|
3481
3914
|
function computeLegendLayout(config, state, containerWidth) {
|
|
3482
3915
|
const { groups, controls: configControls, mode } = config;
|
|
3483
3916
|
const isExport = mode === "export";
|
|
3917
|
+
const gated = isAppHostedControls(config, isExport);
|
|
3484
3918
|
const activeGroupName = state.activeGroup?.toLowerCase() ?? null;
|
|
3485
3919
|
if (isExport && !activeGroupName) {
|
|
3486
3920
|
return {
|
|
@@ -3491,7 +3925,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3491
3925
|
pills: []
|
|
3492
3926
|
};
|
|
3493
3927
|
}
|
|
3494
|
-
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3928
|
+
const controlsGroupLayout = isExport || gated ? void 0 : buildControlsGroupLayout(config, state);
|
|
3495
3929
|
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3496
3930
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3497
3931
|
return {
|
|
@@ -8345,8 +8779,8 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8345
8779
|
const pt = points[i];
|
|
8346
8780
|
const ptSize = pt.size ?? symbolSize;
|
|
8347
8781
|
const minGap = ptSize / 2 + 4;
|
|
8348
|
-
const
|
|
8349
|
-
const labelX = pt.px -
|
|
8782
|
+
const labelWidth2 = pt.name.length * fontSize * 0.6 + 8;
|
|
8783
|
+
const labelX = pt.px - labelWidth2 / 2;
|
|
8350
8784
|
let bestLabelY = 0;
|
|
8351
8785
|
let bestOffset = Infinity;
|
|
8352
8786
|
let placed = false;
|
|
@@ -8358,7 +8792,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8358
8792
|
const candidate = {
|
|
8359
8793
|
x: labelX,
|
|
8360
8794
|
y: labelY,
|
|
8361
|
-
w:
|
|
8795
|
+
w: labelWidth2,
|
|
8362
8796
|
h: labelHeight
|
|
8363
8797
|
};
|
|
8364
8798
|
let collision = false;
|
|
@@ -8400,7 +8834,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8400
8834
|
const labelRect = {
|
|
8401
8835
|
x: labelX,
|
|
8402
8836
|
y: bestLabelY,
|
|
8403
|
-
w:
|
|
8837
|
+
w: labelWidth2,
|
|
8404
8838
|
h: labelHeight
|
|
8405
8839
|
};
|
|
8406
8840
|
placedLabels.push(labelRect);
|
|
@@ -8436,7 +8870,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8436
8870
|
shape: {
|
|
8437
8871
|
x: labelX - bgPad,
|
|
8438
8872
|
y: bestLabelY - bgPad,
|
|
8439
|
-
width:
|
|
8873
|
+
width: labelWidth2 + bgPad * 2,
|
|
8440
8874
|
height: labelHeight + bgPad * 2
|
|
8441
8875
|
},
|
|
8442
8876
|
style: { fill: bg },
|
|
@@ -15872,10 +16306,6 @@ function parseMap(content) {
|
|
|
15872
16306
|
handleTag(trimmed, lineNumber);
|
|
15873
16307
|
continue;
|
|
15874
16308
|
}
|
|
15875
|
-
if ((firstWord === "muted" || firstWord === "natural") && trimmed === firstWord) {
|
|
15876
|
-
handleDirective(firstWord, "", lineNumber);
|
|
15877
|
-
continue;
|
|
15878
|
-
}
|
|
15879
16309
|
if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
|
|
15880
16310
|
handleDirective(
|
|
15881
16311
|
firstWord,
|
|
@@ -15922,24 +16352,6 @@ function parseMap(content) {
|
|
|
15922
16352
|
pushWarning(line12, `Duplicate directive "${key}" \u2014 last value wins.`);
|
|
15923
16353
|
};
|
|
15924
16354
|
switch (key) {
|
|
15925
|
-
case "region":
|
|
15926
|
-
dup(d.region);
|
|
15927
|
-
d.region = value;
|
|
15928
|
-
break;
|
|
15929
|
-
case "projection":
|
|
15930
|
-
dup(d.projection);
|
|
15931
|
-
if (value && ![
|
|
15932
|
-
"equirectangular",
|
|
15933
|
-
"natural-earth",
|
|
15934
|
-
"albers-usa",
|
|
15935
|
-
"mercator"
|
|
15936
|
-
].includes(value))
|
|
15937
|
-
pushWarning(
|
|
15938
|
-
line12,
|
|
15939
|
-
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15940
|
-
);
|
|
15941
|
-
d.projection = value;
|
|
15942
|
-
break;
|
|
15943
16355
|
case "region-metric": {
|
|
15944
16356
|
dup(d.regionMetric);
|
|
15945
16357
|
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
@@ -15955,91 +16367,43 @@ function parseMap(content) {
|
|
|
15955
16367
|
dup(d.flowMetric);
|
|
15956
16368
|
d.flowMetric = value;
|
|
15957
16369
|
break;
|
|
15958
|
-
case "
|
|
15959
|
-
dup(d.
|
|
15960
|
-
|
|
15961
|
-
const s = parseScale(value, line12);
|
|
15962
|
-
if (s) d.scale = s;
|
|
15963
|
-
}
|
|
15964
|
-
break;
|
|
15965
|
-
case "region-labels":
|
|
15966
|
-
dup(d.regionLabels);
|
|
15967
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15968
|
-
pushWarning(
|
|
15969
|
-
line12,
|
|
15970
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15971
|
-
);
|
|
15972
|
-
d.regionLabels = value;
|
|
15973
|
-
break;
|
|
15974
|
-
case "poi-labels":
|
|
15975
|
-
dup(d.poiLabels);
|
|
15976
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
15977
|
-
pushWarning(
|
|
15978
|
-
line12,
|
|
15979
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
15980
|
-
);
|
|
15981
|
-
d.poiLabels = value;
|
|
15982
|
-
break;
|
|
15983
|
-
case "default-country":
|
|
15984
|
-
dup(d.defaultCountry);
|
|
15985
|
-
d.defaultCountry = value;
|
|
15986
|
-
break;
|
|
15987
|
-
case "default-state":
|
|
15988
|
-
dup(d.defaultState);
|
|
15989
|
-
d.defaultState = value;
|
|
16370
|
+
case "locale":
|
|
16371
|
+
dup(d.locale);
|
|
16372
|
+
d.locale = value;
|
|
15990
16373
|
break;
|
|
15991
16374
|
case "active-tag":
|
|
15992
16375
|
dup(d.activeTag);
|
|
15993
16376
|
d.activeTag = value;
|
|
15994
16377
|
break;
|
|
16378
|
+
case "caption":
|
|
16379
|
+
dup(d.caption);
|
|
16380
|
+
d.caption = value;
|
|
16381
|
+
break;
|
|
16382
|
+
// ── Cosmetic `no-*` opt-outs: bare flags, idempotent (mirror `no-legend`,
|
|
16383
|
+
// no dup warning); each defaults the feature ON when absent. ──
|
|
15995
16384
|
case "no-legend":
|
|
15996
16385
|
d.noLegend = true;
|
|
15997
16386
|
break;
|
|
15998
|
-
case "no-
|
|
15999
|
-
d.
|
|
16387
|
+
case "no-coastline":
|
|
16388
|
+
d.noCoastline = true;
|
|
16000
16389
|
break;
|
|
16001
|
-
case "relief":
|
|
16002
|
-
d.
|
|
16390
|
+
case "no-relief":
|
|
16391
|
+
d.noRelief = true;
|
|
16003
16392
|
break;
|
|
16004
|
-
case "
|
|
16005
|
-
|
|
16006
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
16007
|
-
pushWarning(
|
|
16008
|
-
line12,
|
|
16009
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
16010
|
-
);
|
|
16011
|
-
d.basemapStyle = key;
|
|
16393
|
+
case "no-context-labels":
|
|
16394
|
+
d.noContextLabels = true;
|
|
16012
16395
|
break;
|
|
16013
|
-
case "
|
|
16014
|
-
|
|
16015
|
-
d.subtitle = value;
|
|
16396
|
+
case "no-region-labels":
|
|
16397
|
+
d.noRegionLabels = true;
|
|
16016
16398
|
break;
|
|
16017
|
-
case "
|
|
16018
|
-
|
|
16019
|
-
|
|
16399
|
+
case "no-poi-labels":
|
|
16400
|
+
d.noPoiLabels = true;
|
|
16401
|
+
break;
|
|
16402
|
+
case "no-colorize":
|
|
16403
|
+
d.noColorize = true;
|
|
16020
16404
|
break;
|
|
16021
16405
|
}
|
|
16022
16406
|
}
|
|
16023
|
-
function parseScale(value, line12) {
|
|
16024
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
16025
|
-
const min = Number(toks[0]);
|
|
16026
|
-
const max = Number(toks[1]);
|
|
16027
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
16028
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
16029
|
-
return null;
|
|
16030
|
-
}
|
|
16031
|
-
const scale = { min, max };
|
|
16032
|
-
if (toks[2] === "center") {
|
|
16033
|
-
const c = Number(toks[3]);
|
|
16034
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
16035
|
-
else
|
|
16036
|
-
pushError(
|
|
16037
|
-
line12,
|
|
16038
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
16039
|
-
);
|
|
16040
|
-
}
|
|
16041
|
-
return scale;
|
|
16042
|
-
}
|
|
16043
16407
|
function handleTag(trimmed, line12) {
|
|
16044
16408
|
const m = matchTagBlockHeading(trimmed);
|
|
16045
16409
|
if (!m) {
|
|
@@ -16239,13 +16603,15 @@ function parseMap(content) {
|
|
|
16239
16603
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16240
16604
|
continue;
|
|
16241
16605
|
}
|
|
16242
|
-
const
|
|
16606
|
+
const isLast = k === links.length - 1;
|
|
16607
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16608
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16243
16609
|
edges.push({
|
|
16244
16610
|
from,
|
|
16245
16611
|
to,
|
|
16246
16612
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16247
16613
|
directed: links[k].directed,
|
|
16248
|
-
style
|
|
16614
|
+
style,
|
|
16249
16615
|
meta,
|
|
16250
16616
|
lineNumber: line12
|
|
16251
16617
|
});
|
|
@@ -16331,22 +16697,19 @@ var init_parser12 = __esm({
|
|
|
16331
16697
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16332
16698
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16333
16699
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16334
|
-
"region",
|
|
16335
|
-
"projection",
|
|
16336
16700
|
"region-metric",
|
|
16337
16701
|
"poi-metric",
|
|
16338
16702
|
"flow-metric",
|
|
16339
|
-
"
|
|
16340
|
-
"region-labels",
|
|
16341
|
-
"poi-labels",
|
|
16342
|
-
"default-country",
|
|
16343
|
-
"default-state",
|
|
16703
|
+
"locale",
|
|
16344
16704
|
"active-tag",
|
|
16705
|
+
"caption",
|
|
16345
16706
|
"no-legend",
|
|
16346
|
-
"no-
|
|
16347
|
-
"relief",
|
|
16348
|
-
"
|
|
16349
|
-
"
|
|
16707
|
+
"no-coastline",
|
|
16708
|
+
"no-relief",
|
|
16709
|
+
"no-context-labels",
|
|
16710
|
+
"no-region-labels",
|
|
16711
|
+
"no-poi-labels",
|
|
16712
|
+
"no-colorize"
|
|
16350
16713
|
]);
|
|
16351
16714
|
}
|
|
16352
16715
|
});
|
|
@@ -16524,6 +16887,21 @@ function parseBoxesAndLines(content) {
|
|
|
16524
16887
|
}
|
|
16525
16888
|
continue;
|
|
16526
16889
|
}
|
|
16890
|
+
if (!contentStarted) {
|
|
16891
|
+
const metricMatch = trimmed.match(/^box-metric\s+(.+)$/i);
|
|
16892
|
+
if (metricMatch) {
|
|
16893
|
+
const { label, colorName } = peelTrailingColorName(
|
|
16894
|
+
metricMatch[1].trim()
|
|
16895
|
+
);
|
|
16896
|
+
result.boxMetric = label;
|
|
16897
|
+
if (colorName !== void 0) result.boxMetricColor = colorName;
|
|
16898
|
+
continue;
|
|
16899
|
+
}
|
|
16900
|
+
if (/^show-values$/i.test(trimmed)) {
|
|
16901
|
+
result.showValues = true;
|
|
16902
|
+
continue;
|
|
16903
|
+
}
|
|
16904
|
+
}
|
|
16527
16905
|
if (!contentStarted) {
|
|
16528
16906
|
const optMatch = trimmed.match(OPTION_NOCOLON_RE);
|
|
16529
16907
|
if (optMatch) {
|
|
@@ -16902,6 +17280,19 @@ function parseNodeLine(trimmed, lineNum, metaAliasMap, diagnostics, nameAliasMap
|
|
|
16902
17280
|
description = [metadata["description"]];
|
|
16903
17281
|
delete metadata["description"];
|
|
16904
17282
|
}
|
|
17283
|
+
let value;
|
|
17284
|
+
if (metadata["value"] !== void 0) {
|
|
17285
|
+
const raw = metadata["value"];
|
|
17286
|
+
const num = Number(raw);
|
|
17287
|
+
if (Number.isFinite(num)) {
|
|
17288
|
+
value = num;
|
|
17289
|
+
} else {
|
|
17290
|
+
diagnostics.push(
|
|
17291
|
+
makeDgmoError(lineNum, `value must be a number (got "${raw}")`, "error")
|
|
17292
|
+
);
|
|
17293
|
+
}
|
|
17294
|
+
delete metadata["value"];
|
|
17295
|
+
}
|
|
16905
17296
|
if (split.alias) {
|
|
16906
17297
|
nameAliasMap?.set(normalizeName(split.alias), label);
|
|
16907
17298
|
}
|
|
@@ -16910,7 +17301,8 @@ function parseNodeLine(trimmed, lineNum, metaAliasMap, diagnostics, nameAliasMap
|
|
|
16910
17301
|
label,
|
|
16911
17302
|
lineNumber: lineNum,
|
|
16912
17303
|
metadata,
|
|
16913
|
-
...description !== void 0 && { description }
|
|
17304
|
+
...description !== void 0 && { description },
|
|
17305
|
+
...value !== void 0 && { value }
|
|
16914
17306
|
};
|
|
16915
17307
|
}
|
|
16916
17308
|
function splitTargetAndMeta(rest, metaAliasMap) {
|
|
@@ -24358,8 +24750,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24358
24750
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24359
24751
|
for (const meta of tagMeta) {
|
|
24360
24752
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24361
|
-
const
|
|
24362
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
24753
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
24754
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24363
24755
|
metaY += sCardMetaLineHeight;
|
|
24364
24756
|
}
|
|
24365
24757
|
for (const detail of card.details) {
|
|
@@ -24703,8 +25095,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24703
25095
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24704
25096
|
for (const meta of tagMeta) {
|
|
24705
25097
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24706
|
-
const
|
|
24707
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
25098
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
25099
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24708
25100
|
metaY += sCardMetaLineHeight;
|
|
24709
25101
|
}
|
|
24710
25102
|
for (const detail of card.details) {
|
|
@@ -25538,8 +25930,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25538
25930
|
}
|
|
25539
25931
|
}
|
|
25540
25932
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25541
|
-
for (const [id,
|
|
25542
|
-
if (
|
|
25933
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25934
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25543
25935
|
}
|
|
25544
25936
|
const indegreeValues = Object.values(indegreeMap);
|
|
25545
25937
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26122,7 +26514,18 @@ function fitLabelToHeader(label, nodeWidth, maxLines) {
|
|
|
26122
26514
|
const truncated = label.length > maxChars ? label.slice(0, maxChars - 1) + "\u2026" : label;
|
|
26123
26515
|
return { lines: [truncated], fontSize: MIN_NODE_FONT_SIZE };
|
|
26124
26516
|
}
|
|
26125
|
-
function nodeColors(node, tagGroups, activeGroupName, palette, isDark, solid) {
|
|
26517
|
+
function nodeColors(node, tagGroups, activeGroupName, palette, isDark, value, solid) {
|
|
26518
|
+
const neutralFill = mix(palette.bg, palette.text, isDark ? 90 : 95);
|
|
26519
|
+
if (value.active) {
|
|
26520
|
+
const fill3 = node.value !== void 0 ? value.fillForValue(node.value) : neutralFill;
|
|
26521
|
+
const stroke3 = value.hue;
|
|
26522
|
+
const text2 = contrastText(
|
|
26523
|
+
fill3,
|
|
26524
|
+
palette.textOnFillLight,
|
|
26525
|
+
palette.textOnFillDark
|
|
26526
|
+
);
|
|
26527
|
+
return { fill: fill3, stroke: stroke3, text: text2 };
|
|
26528
|
+
}
|
|
26126
26529
|
const tagColor = resolveTagColor(
|
|
26127
26530
|
node.metadata,
|
|
26128
26531
|
[...tagGroups],
|
|
@@ -26212,7 +26615,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26212
26615
|
controlsExpanded,
|
|
26213
26616
|
onToggleDescriptions,
|
|
26214
26617
|
onToggleControlsExpand,
|
|
26215
|
-
exportMode = false
|
|
26618
|
+
exportMode = false,
|
|
26619
|
+
controlsHost
|
|
26216
26620
|
} = options ?? {};
|
|
26217
26621
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26218
26622
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26230,21 +26634,65 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26230
26634
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26231
26635
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26232
26636
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26233
|
-
const
|
|
26637
|
+
const nodeValues = parsed.nodes.filter((n) => n.value !== void 0).map((n) => n.value);
|
|
26638
|
+
const hasRamp = nodeValues.length > 0;
|
|
26639
|
+
const allNonNegative = hasRamp && nodeValues.every((v) => v >= 0);
|
|
26640
|
+
const rampMin = allNonNegative ? 0 : Math.min(...nodeValues);
|
|
26641
|
+
const rampMax = Math.max(...nodeValues);
|
|
26642
|
+
const rampHue = resolveColor(parsed.boxMetricColor ?? "", palette) ?? palette.primary;
|
|
26643
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
26644
|
+
const fillForValue = (v) => {
|
|
26645
|
+
const t = rampMax > rampMin ? (v - rampMin) / (rampMax - rampMin) : 1;
|
|
26646
|
+
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
26647
|
+
return mix(rampHue, rampBase, pct);
|
|
26648
|
+
};
|
|
26649
|
+
const VALUE_NAME = hasRamp ? parsed.boxMetric?.trim() || "Value" : null;
|
|
26650
|
+
const matchColorGroup = (v) => {
|
|
26651
|
+
const lv = v.trim().toLowerCase();
|
|
26652
|
+
if (lv === "none") return null;
|
|
26653
|
+
const tg = parsed.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
26654
|
+
if (tg) return tg.name;
|
|
26655
|
+
if (lv === VALUE_NAME?.toLowerCase()) return VALUE_NAME;
|
|
26656
|
+
return v;
|
|
26657
|
+
};
|
|
26658
|
+
const override = activeTagGroup;
|
|
26659
|
+
let activeGroup;
|
|
26660
|
+
if (override !== void 0) {
|
|
26661
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
26662
|
+
} else if (parsed.options["active-tag"] !== void 0) {
|
|
26663
|
+
activeGroup = matchColorGroup(parsed.options["active-tag"]);
|
|
26664
|
+
} else {
|
|
26665
|
+
activeGroup = VALUE_NAME ?? (parsed.tagGroups.length > 0 ? parsed.tagGroups[0].name : null);
|
|
26666
|
+
}
|
|
26667
|
+
const activeIsValue = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
26668
|
+
const valueGroup = VALUE_NAME !== null ? {
|
|
26669
|
+
name: VALUE_NAME,
|
|
26670
|
+
entries: [],
|
|
26671
|
+
gradient: {
|
|
26672
|
+
min: rampMin,
|
|
26673
|
+
max: rampMax,
|
|
26674
|
+
hue: rampHue,
|
|
26675
|
+
base: rampBase
|
|
26676
|
+
}
|
|
26677
|
+
} : null;
|
|
26678
|
+
const legendGroups = [
|
|
26679
|
+
...valueGroup ? [valueGroup] : [],
|
|
26680
|
+
...parsed.tagGroups
|
|
26681
|
+
];
|
|
26682
|
+
const reserveHasDescriptions = parsed.nodes.some(
|
|
26683
|
+
(n) => n.description && n.description.length > 0
|
|
26684
|
+
);
|
|
26685
|
+
const willRenderLegend = legendGroups.length > 0 || reserveHasDescriptions && controlsHost !== "app";
|
|
26686
|
+
const sLegendHeight = willRenderLegend ? sctx.structural(
|
|
26234
26687
|
getMaxLegendReservedHeight(
|
|
26235
26688
|
{
|
|
26236
|
-
groups:
|
|
26689
|
+
groups: legendGroups,
|
|
26237
26690
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26238
26691
|
mode: exportMode ? "export" : "preview"
|
|
26239
26692
|
},
|
|
26240
26693
|
width
|
|
26241
26694
|
)
|
|
26242
|
-
);
|
|
26243
|
-
const activeGroup = resolveActiveTagGroup(
|
|
26244
|
-
parsed.tagGroups,
|
|
26245
|
-
parsed.options["active-tag"],
|
|
26246
|
-
activeTagGroup
|
|
26247
|
-
);
|
|
26695
|
+
) : 0;
|
|
26248
26696
|
const hidden = hiddenTagValues ?? parsed.initialHiddenTagValues;
|
|
26249
26697
|
const nodeMap = /* @__PURE__ */ new Map();
|
|
26250
26698
|
for (const node of parsed.nodes) nodeMap.set(node.label, node);
|
|
@@ -26255,7 +26703,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26255
26703
|
const hasAnyDescriptions = parsed.nodes.some(
|
|
26256
26704
|
(n) => n.description && n.description.length > 0
|
|
26257
26705
|
);
|
|
26258
|
-
const needsLegend =
|
|
26706
|
+
const needsLegend = legendGroups.length > 0 || hasAnyDescriptions && onToggleDescriptions;
|
|
26259
26707
|
const legendH = needsLegend ? sLegendHeight + 8 : 0;
|
|
26260
26708
|
const groupLabelsSet = new Set(layout.groups.map((g) => g.label));
|
|
26261
26709
|
let labelZoneExtension = 0;
|
|
@@ -26461,12 +26909,16 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26461
26909
|
activeGroup,
|
|
26462
26910
|
palette,
|
|
26463
26911
|
isDark,
|
|
26912
|
+
{ active: activeIsValue, hue: rampHue, fillForValue },
|
|
26464
26913
|
parsed.options["solid-fill"] === "on"
|
|
26465
26914
|
);
|
|
26466
26915
|
const nodeG = diagramG.append("g").attr("class", "bl-node").attr("transform", `translate(${ln.x},${ln.y})`).attr("data-line-number", node.lineNumber).attr("data-node-id", node.label).style("cursor", onClickItem ? "pointer" : "default").style("--bl-node-stroke", colors.stroke);
|
|
26467
26916
|
for (const [key, val] of Object.entries(node.metadata)) {
|
|
26468
26917
|
nodeG.attr(`data-tag-${key.toLowerCase()}`, val.toLowerCase());
|
|
26469
26918
|
}
|
|
26919
|
+
if (node.value !== void 0) {
|
|
26920
|
+
nodeG.attr("data-value", node.value);
|
|
26921
|
+
}
|
|
26470
26922
|
if (onClickItem) {
|
|
26471
26923
|
nodeG.on("click", (event) => {
|
|
26472
26924
|
const target = event.target;
|
|
@@ -26550,14 +27002,30 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26550
27002
|
nodeG.append("text").attr("x", 0).attr("y", -totalH / 2 + lineH / 2 + li * lineH).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", fitted.fontSize).attr("font-weight", "600").attr("fill", colors.text).text(fitted.lines[li]);
|
|
26551
27003
|
}
|
|
26552
27004
|
}
|
|
27005
|
+
if (parsed.showValues && node.value !== void 0) {
|
|
27006
|
+
const valueText = String(node.value);
|
|
27007
|
+
const descShown = !!(desc && desc.length > 0 && !hideDescriptions);
|
|
27008
|
+
if (descShown) {
|
|
27009
|
+
const padX = 6;
|
|
27010
|
+
const padY = 5;
|
|
27011
|
+
const bw = valueText.length * VALUE_FONT_SIZE * CHAR_WIDTH_RATIO2 + 8;
|
|
27012
|
+
const bh = VALUE_FONT_SIZE + 4;
|
|
27013
|
+
const bx = ln.width / 2 - bw - 4;
|
|
27014
|
+
const by = -ln.height / 2 + 4;
|
|
27015
|
+
nodeG.append("rect").attr("x", bx).attr("y", by).attr("width", bw).attr("height", bh).attr("rx", 3).attr("fill", palette.bg).attr("opacity", 0.85);
|
|
27016
|
+
nodeG.append("text").attr("class", "bl-node-value").attr("x", bx + bw - padX).attr("y", by + padY).attr("text-anchor", "end").attr("dominant-baseline", "central").attr("font-size", VALUE_FONT_SIZE).attr("font-weight", "600").attr("fill", palette.textMuted).text(valueText);
|
|
27017
|
+
} else {
|
|
27018
|
+
nodeG.append("text").attr("class", "bl-node-value").attr("x", 0).attr("y", ln.height / 2 - VALUE_FONT_SIZE).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", VALUE_FONT_SIZE).attr("font-weight", "600").attr("fill", colors.text).attr("opacity", 0.8).text(valueText);
|
|
27019
|
+
}
|
|
27020
|
+
}
|
|
26553
27021
|
}
|
|
26554
27022
|
const hasDescriptions = parsed.nodes.some(
|
|
26555
27023
|
(n) => n.description && n.description.length > 0
|
|
26556
27024
|
);
|
|
26557
|
-
const hasLegend =
|
|
27025
|
+
const hasLegend = legendGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26558
27026
|
if (hasLegend) {
|
|
26559
27027
|
let controlsGroup;
|
|
26560
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
27028
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26561
27029
|
controlsGroup = {
|
|
26562
27030
|
toggles: [
|
|
26563
27031
|
{
|
|
@@ -26572,10 +27040,17 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26572
27040
|
};
|
|
26573
27041
|
}
|
|
26574
27042
|
const legendConfig = {
|
|
26575
|
-
groups:
|
|
27043
|
+
groups: legendGroups,
|
|
26576
27044
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26577
27045
|
mode: exportMode ? "export" : "preview",
|
|
26578
|
-
|
|
27046
|
+
// Keep inactive sibling tag groups visible as collapsed pills so the user
|
|
27047
|
+
// can click one to flip the active colouring dimension (preview only —
|
|
27048
|
+
// export shows just the active group). Without this, declaring a second
|
|
27049
|
+
// tag group (e.g. Team) leaves it invisible whenever another group is
|
|
27050
|
+
// active. The app's BoxesAndLinesPreview already wires pill clicks.
|
|
27051
|
+
showInactivePills: true,
|
|
27052
|
+
...controlsGroup !== void 0 && { controlsGroup },
|
|
27053
|
+
...controlsHost !== void 0 && { controlsHost }
|
|
26579
27054
|
};
|
|
26580
27055
|
const legendState = {
|
|
26581
27056
|
activeGroup,
|
|
@@ -26620,7 +27095,7 @@ function renderBoxesAndLinesForExport(container, parsed, layout, palette, isDark
|
|
|
26620
27095
|
}
|
|
26621
27096
|
});
|
|
26622
27097
|
}
|
|
26623
|
-
var DIAGRAM_PADDING6, NODE_FONT_SIZE, MIN_NODE_FONT_SIZE, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, COLLAPSE_BAR_HEIGHT3, ARROWHEAD_W2, ARROWHEAD_H2, DESC_FONT_SIZE, DESC_LINE_HEIGHT, MAX_DESC_LINES, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING, GROUP_RX, GROUP_LABEL_FONT_SIZE, GROUP_LABEL_ZONE, lineGeneratorLR, lineGeneratorTB;
|
|
27098
|
+
var DIAGRAM_PADDING6, NODE_FONT_SIZE, MIN_NODE_FONT_SIZE, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, COLLAPSE_BAR_HEIGHT3, ARROWHEAD_W2, ARROWHEAD_H2, DESC_FONT_SIZE, DESC_LINE_HEIGHT, MAX_DESC_LINES, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING, GROUP_RX, GROUP_LABEL_FONT_SIZE, GROUP_LABEL_ZONE, RAMP_FLOOR, VALUE_FONT_SIZE, lineGeneratorLR, lineGeneratorTB;
|
|
26624
27099
|
var init_renderer6 = __esm({
|
|
26625
27100
|
"src/boxes-and-lines/renderer.ts"() {
|
|
26626
27101
|
"use strict";
|
|
@@ -26629,6 +27104,7 @@ var init_renderer6 = __esm({
|
|
|
26629
27104
|
init_legend_layout();
|
|
26630
27105
|
init_title_constants();
|
|
26631
27106
|
init_color_utils();
|
|
27107
|
+
init_colors();
|
|
26632
27108
|
init_tag_groups();
|
|
26633
27109
|
init_inline_markdown();
|
|
26634
27110
|
init_wrapped_desc();
|
|
@@ -26651,6 +27127,8 @@ var init_renderer6 = __esm({
|
|
|
26651
27127
|
GROUP_RX = 8;
|
|
26652
27128
|
GROUP_LABEL_FONT_SIZE = 14;
|
|
26653
27129
|
GROUP_LABEL_ZONE = 32;
|
|
27130
|
+
RAMP_FLOOR = 15;
|
|
27131
|
+
VALUE_FONT_SIZE = 11;
|
|
26654
27132
|
lineGeneratorLR = d3Shape4.line().x((d) => d.x).y((d) => d.y).curve(d3Shape4.curveBasis);
|
|
26655
27133
|
lineGeneratorTB = d3Shape4.line().x((d) => d.x).y((d) => d.y).curve(d3Shape4.curveBasis);
|
|
26656
27134
|
}
|
|
@@ -27822,8 +28300,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27822
28300
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27823
28301
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27824
28302
|
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);
|
|
28303
|
+
const appHosted = options?.controlsHost === "app";
|
|
27825
28304
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27826
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28305
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27827
28306
|
const fixedLegend = !isExport && hasLegend;
|
|
27828
28307
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27829
28308
|
{
|
|
@@ -27917,7 +28396,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27917
28396
|
}),
|
|
27918
28397
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27919
28398
|
mode: options?.exportMode ? "export" : "preview",
|
|
27920
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28399
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28400
|
+
...options?.controlsHost !== void 0 && {
|
|
28401
|
+
controlsHost: options.controlsHost
|
|
28402
|
+
}
|
|
27921
28403
|
};
|
|
27922
28404
|
const legendState = {
|
|
27923
28405
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28360,8 +28842,8 @@ function computeFieldAlignX(children) {
|
|
|
28360
28842
|
for (const child of children) {
|
|
28361
28843
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28362
28844
|
const labelEl = child.children[0];
|
|
28363
|
-
const
|
|
28364
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28845
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28846
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28365
28847
|
labelFieldCount++;
|
|
28366
28848
|
}
|
|
28367
28849
|
}
|
|
@@ -33326,7 +33808,7 @@ function hasRoles(node) {
|
|
|
33326
33808
|
function computeNodeWidth2(node, expanded, options) {
|
|
33327
33809
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33328
33810
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33329
|
-
const
|
|
33811
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33330
33812
|
const allKeys = [];
|
|
33331
33813
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33332
33814
|
if (expanded) {
|
|
@@ -33370,7 +33852,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33370
33852
|
allKeys.push("overflow");
|
|
33371
33853
|
}
|
|
33372
33854
|
}
|
|
33373
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33855
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33374
33856
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33375
33857
|
let maxRowWidth = 0;
|
|
33376
33858
|
if (node.computedRps > 0) {
|
|
@@ -33458,7 +33940,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33458
33940
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33459
33941
|
);
|
|
33460
33942
|
}
|
|
33461
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33943
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33462
33944
|
}
|
|
33463
33945
|
function computeNodeHeight2(node, expanded, options) {
|
|
33464
33946
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -35008,8 +35490,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
35008
35490
|
}
|
|
35009
35491
|
return groups;
|
|
35010
35492
|
}
|
|
35011
|
-
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false) {
|
|
35493
|
+
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false, controlsHost) {
|
|
35012
35494
|
if (legendGroups.length === 0 && !playback) return;
|
|
35495
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
35013
35496
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
35014
35497
|
if (activeGroup) {
|
|
35015
35498
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -35018,14 +35501,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
35018
35501
|
name: g.name,
|
|
35019
35502
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
35020
35503
|
}));
|
|
35021
|
-
if (playback) {
|
|
35504
|
+
if (playback && !appHostedPlayback) {
|
|
35022
35505
|
allGroups.push({ name: "Playback", entries: [] });
|
|
35023
35506
|
}
|
|
35024
35507
|
const legendConfig = {
|
|
35025
35508
|
groups: allGroups,
|
|
35026
35509
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
35027
35510
|
mode: exportMode ? "export" : "preview",
|
|
35028
|
-
showEmptyGroups: true
|
|
35511
|
+
showEmptyGroups: true,
|
|
35512
|
+
...appHostedPlayback && {
|
|
35513
|
+
controlsHost: "app",
|
|
35514
|
+
controlsGroup: {
|
|
35515
|
+
toggles: [
|
|
35516
|
+
{
|
|
35517
|
+
id: "playback",
|
|
35518
|
+
type: "toggle",
|
|
35519
|
+
label: "Playback",
|
|
35520
|
+
active: true,
|
|
35521
|
+
onToggle: () => {
|
|
35522
|
+
}
|
|
35523
|
+
}
|
|
35524
|
+
]
|
|
35525
|
+
}
|
|
35526
|
+
}
|
|
35029
35527
|
};
|
|
35030
35528
|
const legendState = { activeGroup };
|
|
35031
35529
|
renderLegendD3(
|
|
@@ -35076,8 +35574,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
35076
35574
|
}
|
|
35077
35575
|
}
|
|
35078
35576
|
}
|
|
35079
|
-
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes) {
|
|
35577
|
+
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes, controlsHost) {
|
|
35080
35578
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35579
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
35081
35580
|
const ctx = ScaleContext.identity();
|
|
35082
35581
|
const sc = buildScaledConstants(ctx);
|
|
35083
35582
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -35086,7 +35585,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35086
35585
|
palette,
|
|
35087
35586
|
layout.edges
|
|
35088
35587
|
);
|
|
35089
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35588
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
35090
35589
|
const fixedLegend = !exportMode && hasLegend;
|
|
35091
35590
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
35092
35591
|
{
|
|
@@ -35230,7 +35729,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35230
35729
|
isDark,
|
|
35231
35730
|
activeGroup ?? null,
|
|
35232
35731
|
playback ?? void 0,
|
|
35233
|
-
exportMode
|
|
35732
|
+
exportMode,
|
|
35733
|
+
controlsHost
|
|
35234
35734
|
);
|
|
35235
35735
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35236
35736
|
} else {
|
|
@@ -35243,7 +35743,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35243
35743
|
isDark,
|
|
35244
35744
|
activeGroup ?? null,
|
|
35245
35745
|
playback ?? void 0,
|
|
35246
|
-
exportMode
|
|
35746
|
+
exportMode,
|
|
35747
|
+
controlsHost
|
|
35247
35748
|
);
|
|
35248
35749
|
}
|
|
35249
35750
|
}
|
|
@@ -43100,6 +43601,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
43100
43601
|
onToggle: (active) => options.onToggleListing(active)
|
|
43101
43602
|
}
|
|
43102
43603
|
]
|
|
43604
|
+
},
|
|
43605
|
+
...options.controlsHost !== void 0 && {
|
|
43606
|
+
controlsHost: options.controlsHost
|
|
43103
43607
|
}
|
|
43104
43608
|
};
|
|
43105
43609
|
const legendState = {
|
|
@@ -44922,7 +45426,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44922
45426
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44923
45427
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44924
45428
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44925
|
-
const
|
|
45429
|
+
const labelWidth2 = Math.max(
|
|
44926
45430
|
MIN_NODE_WIDTH4,
|
|
44927
45431
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44928
45432
|
);
|
|
@@ -44931,12 +45435,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44931
45435
|
}
|
|
44932
45436
|
if (!hasDesc) {
|
|
44933
45437
|
return {
|
|
44934
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
45438
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44935
45439
|
height: PLAIN_NODE_HEIGHT,
|
|
44936
45440
|
wrappedDesc: []
|
|
44937
45441
|
};
|
|
44938
45442
|
}
|
|
44939
|
-
return chooseDescribedRectDims(node.description,
|
|
45443
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44940
45444
|
});
|
|
44941
45445
|
if (circleNodes) {
|
|
44942
45446
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -45132,10 +45636,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
45132
45636
|
scale
|
|
45133
45637
|
};
|
|
45134
45638
|
}
|
|
45135
|
-
function chooseDescribedRectDims(description,
|
|
45639
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
45136
45640
|
const minW = Math.min(
|
|
45137
45641
|
MAX_NODE_WIDTH3,
|
|
45138
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45642
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
45139
45643
|
);
|
|
45140
45644
|
let best = null;
|
|
45141
45645
|
let bestScore = Infinity;
|
|
@@ -45564,7 +46068,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45564
46068
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45565
46069
|
const showDescriptions = !hideDescriptions;
|
|
45566
46070
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45567
|
-
const
|
|
46071
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
46072
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45568
46073
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45569
46074
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45570
46075
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45601,7 +46106,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45601
46106
|
groups: [],
|
|
45602
46107
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45603
46108
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45604
|
-
controlsGroup
|
|
46109
|
+
controlsGroup,
|
|
46110
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
46111
|
+
controlsHost: renderOptions.controlsHost
|
|
46112
|
+
}
|
|
45605
46113
|
};
|
|
45606
46114
|
const legendState = {
|
|
45607
46115
|
activeGroup: null,
|
|
@@ -45855,7 +46363,7 @@ var init_renderer15 = __esm({
|
|
|
45855
46363
|
});
|
|
45856
46364
|
|
|
45857
46365
|
// src/map/geo.ts
|
|
45858
|
-
import { feature } from "topojson-client";
|
|
46366
|
+
import { feature, neighbors } from "topojson-client";
|
|
45859
46367
|
import { geoBounds, geoArea } from "d3-geo";
|
|
45860
46368
|
function geomObject(topo) {
|
|
45861
46369
|
const key = Object.keys(topo.objects)[0];
|
|
@@ -45873,6 +46381,29 @@ function featureIndex(topo) {
|
|
|
45873
46381
|
}
|
|
45874
46382
|
return idx;
|
|
45875
46383
|
}
|
|
46384
|
+
function buildAdjacency(topo) {
|
|
46385
|
+
const cached = adjacencyCache.get(topo);
|
|
46386
|
+
if (cached) return cached;
|
|
46387
|
+
const geometries = geomObject(topo).geometries;
|
|
46388
|
+
const nb = neighbors(geometries);
|
|
46389
|
+
const sets = /* @__PURE__ */ new Map();
|
|
46390
|
+
geometries.forEach((g, i) => {
|
|
46391
|
+
if (!g.type || g.type === "null") return;
|
|
46392
|
+
let set = sets.get(g.id);
|
|
46393
|
+
if (!set) {
|
|
46394
|
+
set = /* @__PURE__ */ new Set();
|
|
46395
|
+
sets.set(g.id, set);
|
|
46396
|
+
}
|
|
46397
|
+
for (const j of nb[i] ?? []) {
|
|
46398
|
+
const nid = geometries[j]?.id;
|
|
46399
|
+
if (nid && nid !== g.id) set.add(nid);
|
|
46400
|
+
}
|
|
46401
|
+
});
|
|
46402
|
+
const out = /* @__PURE__ */ new Map();
|
|
46403
|
+
for (const [iso, set] of sets) out.set(iso, [...set].sort());
|
|
46404
|
+
adjacencyCache.set(topo, out);
|
|
46405
|
+
return out;
|
|
46406
|
+
}
|
|
45876
46407
|
function decodeFeatures(topo) {
|
|
45877
46408
|
return geomObject(topo).geometries.map((g) => {
|
|
45878
46409
|
const f = feature(topo, g);
|
|
@@ -46068,11 +46599,12 @@ function unionLongitudes(lons) {
|
|
|
46068
46599
|
}
|
|
46069
46600
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
46070
46601
|
}
|
|
46071
|
-
var fold, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
46602
|
+
var fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
46072
46603
|
var init_geo = __esm({
|
|
46073
46604
|
"src/map/geo.ts"() {
|
|
46074
46605
|
"use strict";
|
|
46075
46606
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46607
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46076
46608
|
EDGE_EPS = 1e-9;
|
|
46077
46609
|
DETACH_GAP_DEG = 10;
|
|
46078
46610
|
DETACH_AREA_FRAC = 0.25;
|
|
@@ -46093,6 +46625,12 @@ function looksUS(lat, lon) {
|
|
|
46093
46625
|
if (lat < 15 || lat > 72) return false;
|
|
46094
46626
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
46095
46627
|
}
|
|
46628
|
+
function looksNorthAmericaNeighbor(lat, lon) {
|
|
46629
|
+
return lat >= 14 && lat <= 72 && lon >= -141 && lon <= -52;
|
|
46630
|
+
}
|
|
46631
|
+
function isWholeSphere(bb) {
|
|
46632
|
+
return bb[0][0] <= -179 && bb[1][0] >= 179 && bb[0][1] <= -89 && bb[1][1] >= 89;
|
|
46633
|
+
}
|
|
46096
46634
|
function resolveMap(parsed, data) {
|
|
46097
46635
|
const diagnostics = [...parsed.diagnostics];
|
|
46098
46636
|
const err = (line12, message, code) => {
|
|
@@ -46103,9 +46641,6 @@ function resolveMap(parsed, data) {
|
|
|
46103
46641
|
};
|
|
46104
46642
|
const result = {
|
|
46105
46643
|
title: parsed.title,
|
|
46106
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
46107
|
-
subtitle: parsed.directives.subtitle
|
|
46108
|
-
},
|
|
46109
46644
|
...parsed.directives.caption !== void 0 && {
|
|
46110
46645
|
caption: parsed.directives.caption
|
|
46111
46646
|
},
|
|
@@ -46115,7 +46650,7 @@ function resolveMap(parsed, data) {
|
|
|
46115
46650
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
46116
46651
|
// through; it never resolves a tag value to a palette color (#10).
|
|
46117
46652
|
directives: { ...parsed.directives },
|
|
46118
|
-
basemaps: { world: "
|
|
46653
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
46119
46654
|
regions: [],
|
|
46120
46655
|
pois: [],
|
|
46121
46656
|
edges: [],
|
|
@@ -46124,7 +46659,8 @@ function resolveMap(parsed, data) {
|
|
|
46124
46659
|
[-180, -85],
|
|
46125
46660
|
[180, 85]
|
|
46126
46661
|
],
|
|
46127
|
-
projection: "
|
|
46662
|
+
projection: "equirectangular",
|
|
46663
|
+
poiFrameContainers: [],
|
|
46128
46664
|
diagnostics,
|
|
46129
46665
|
error: parsed.error
|
|
46130
46666
|
};
|
|
@@ -46134,7 +46670,10 @@ function resolveMap(parsed, data) {
|
|
|
46134
46670
|
...[...countryIndex.values()].map((v) => v.name),
|
|
46135
46671
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
46136
46672
|
];
|
|
46137
|
-
const
|
|
46673
|
+
const localeRaw = parsed.directives.locale?.toUpperCase();
|
|
46674
|
+
const localeCountry = localeRaw ? localeRaw.split("-")[0] : void 0;
|
|
46675
|
+
const localeSubdivision = localeRaw && /^[A-Z]{2}-/.test(localeRaw) ? localeRaw : void 0;
|
|
46676
|
+
const usScoped = localeCountry === "US" || parsed.regions.some((r) => {
|
|
46138
46677
|
const f = fold(r.name);
|
|
46139
46678
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
46140
46679
|
}) || parsed.regions.some(
|
|
@@ -46285,7 +46824,7 @@ function resolveMap(parsed, data) {
|
|
|
46285
46824
|
if (!scope)
|
|
46286
46825
|
warn(
|
|
46287
46826
|
line12,
|
|
46288
|
-
`"${name}" is ambiguous \u2014 resolved to the most-populous match.`,
|
|
46827
|
+
`"${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.`,
|
|
46289
46828
|
"W_MAP_AMBIGUOUS_NAME"
|
|
46290
46829
|
);
|
|
46291
46830
|
}
|
|
@@ -46298,17 +46837,21 @@ function resolveMap(parsed, data) {
|
|
|
46298
46837
|
return fold(pos.name);
|
|
46299
46838
|
};
|
|
46300
46839
|
const poiCountries = [];
|
|
46301
|
-
let
|
|
46840
|
+
let anyUsPoi = false;
|
|
46841
|
+
let anyNonNaPoi = false;
|
|
46302
46842
|
const noteCountry = (iso) => {
|
|
46303
46843
|
if (iso) {
|
|
46304
46844
|
poiCountries.push(iso);
|
|
46305
|
-
if (iso
|
|
46845
|
+
if (iso === "US") anyUsPoi = true;
|
|
46846
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
46306
46847
|
}
|
|
46307
46848
|
};
|
|
46308
46849
|
const deferred = [];
|
|
46309
46850
|
for (const p of parsed.pois) {
|
|
46310
46851
|
if (p.pos.kind === "coords") {
|
|
46311
|
-
if (
|
|
46852
|
+
if (looksUS(p.pos.lat, p.pos.lon)) anyUsPoi = true;
|
|
46853
|
+
else if (!looksNorthAmericaNeighbor(p.pos.lat, p.pos.lon))
|
|
46854
|
+
anyNonNaPoi = true;
|
|
46312
46855
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
46313
46856
|
continue;
|
|
46314
46857
|
}
|
|
@@ -46326,14 +46869,15 @@ function resolveMap(parsed, data) {
|
|
|
46326
46869
|
deferred.push(p);
|
|
46327
46870
|
}
|
|
46328
46871
|
}
|
|
46329
|
-
const inferredCountry =
|
|
46872
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46873
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
46330
46874
|
for (const p of deferred) {
|
|
46331
46875
|
if (p.pos.kind !== "name") continue;
|
|
46332
46876
|
const got = lookupName(
|
|
46333
46877
|
p.pos.name,
|
|
46334
46878
|
p.pos.scope,
|
|
46335
46879
|
p.lineNumber,
|
|
46336
|
-
|
|
46880
|
+
inferredScope,
|
|
46337
46881
|
true
|
|
46338
46882
|
);
|
|
46339
46883
|
if (got.kind === "ok") {
|
|
@@ -46403,7 +46947,8 @@ function resolveMap(parsed, data) {
|
|
|
46403
46947
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
46404
46948
|
if (pos.kind === "coords") {
|
|
46405
46949
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
46406
|
-
if (
|
|
46950
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46951
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
46407
46952
|
if (!registry.has(id)) {
|
|
46408
46953
|
registerPoi(
|
|
46409
46954
|
id,
|
|
@@ -46426,7 +46971,7 @@ function resolveMap(parsed, data) {
|
|
|
46426
46971
|
if (registry.has(f)) return f;
|
|
46427
46972
|
const aliased = declaredByName.get(f);
|
|
46428
46973
|
if (aliased) return aliased;
|
|
46429
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46974
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
46430
46975
|
if (got.kind !== "ok") return null;
|
|
46431
46976
|
noteCountry(got.iso);
|
|
46432
46977
|
registerPoi(
|
|
@@ -46483,9 +47028,12 @@ function resolveMap(parsed, data) {
|
|
|
46483
47028
|
}
|
|
46484
47029
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
46485
47030
|
}
|
|
47031
|
+
const hasUsContent = usSubdivisionReferenced || anyUsPoi || localeCountry === "US";
|
|
47032
|
+
const usOriented = !anyNonNaPoi && !regions.some(
|
|
47033
|
+
(r) => r.layer === "country" && !["US", "CA", "MX"].includes(r.iso)
|
|
47034
|
+
) && hasUsContent;
|
|
46486
47035
|
const subdivisions = [];
|
|
46487
|
-
if (usSubdivisionReferenced ||
|
|
46488
|
-
subdivisions.push("us-states");
|
|
47036
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
46489
47037
|
const regionBoxes = [];
|
|
46490
47038
|
for (const ref of referencedRegionIds) {
|
|
46491
47039
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -46503,17 +47051,51 @@ function resolveMap(parsed, data) {
|
|
|
46503
47051
|
[-180, -85],
|
|
46504
47052
|
[180, 85]
|
|
46505
47053
|
];
|
|
46506
|
-
|
|
47054
|
+
const basePad = regions.length > 0 ? REGION_PAD_FRACTION : PAD_FRACTION;
|
|
47055
|
+
let extent2 = unioned ? pad(unioned, basePad) : DEFAULT_EXTENT;
|
|
47056
|
+
const isPoiOnly = pois.length > 0 && regions.length === 0;
|
|
47057
|
+
const containerRegionIds = [];
|
|
47058
|
+
if (isPoiOnly) {
|
|
47059
|
+
const countries = decodeFeatures(data.worldDetail);
|
|
47060
|
+
const states = decodeFeatures(data.usStates);
|
|
47061
|
+
const seen = /* @__PURE__ */ new Set();
|
|
47062
|
+
const containerBoxes = [];
|
|
47063
|
+
for (const p of pois) {
|
|
47064
|
+
const { country, state } = regionAt([p.lon, p.lat], countries, states);
|
|
47065
|
+
const id = state?.iso ?? country?.iso;
|
|
47066
|
+
if (!id || seen.has(id)) continue;
|
|
47067
|
+
seen.add(id);
|
|
47068
|
+
containerRegionIds.push(id);
|
|
47069
|
+
const bb = state ? featureBbox(data.usStates, id) : featureBboxPrimary(data.worldCoarse, id);
|
|
47070
|
+
if (bb && !isWholeSphere(bb)) containerBoxes.push(bb);
|
|
47071
|
+
}
|
|
47072
|
+
const containerUnion = unionExtent(containerBoxes, points);
|
|
47073
|
+
if (containerUnion) extent2 = pad(containerUnion, PAD_FRACTION);
|
|
47074
|
+
}
|
|
47075
|
+
if (isPoiOnly) {
|
|
47076
|
+
const cx = (extent2[0][0] + extent2[1][0]) / 2;
|
|
47077
|
+
const cy = (extent2[0][1] + extent2[1][1]) / 2;
|
|
47078
|
+
const lon = extent2[1][0] - extent2[0][0];
|
|
47079
|
+
const lat = extent2[1][1] - extent2[0][1];
|
|
47080
|
+
const longer = Math.max(lon, lat);
|
|
47081
|
+
if (longer > 0 && longer < POI_ZOOM_FLOOR_DEG) {
|
|
47082
|
+
const k = POI_ZOOM_FLOOR_DEG / longer;
|
|
47083
|
+
const halfLon = lon * k / 2;
|
|
47084
|
+
const halfLat = lat * k / 2;
|
|
47085
|
+
extent2 = [
|
|
47086
|
+
[cx - halfLon, cy - halfLat],
|
|
47087
|
+
[cx + halfLon, cy + halfLat]
|
|
47088
|
+
];
|
|
47089
|
+
}
|
|
47090
|
+
}
|
|
46507
47091
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46508
47092
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46509
47093
|
const span = Math.max(lonSpan, latSpan);
|
|
46510
47094
|
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
46511
|
-
const usDominant = (subdivisions.includes("us-states") || regions.some((r) => r.layer === "us-state")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
46512
47095
|
let projection;
|
|
46513
|
-
|
|
46514
|
-
|
|
46515
|
-
|
|
46516
|
-
} else if (usDominant) {
|
|
47096
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
47097
|
+
projection = "mercator";
|
|
47098
|
+
} else if (usOriented) {
|
|
46517
47099
|
projection = "albers-usa";
|
|
46518
47100
|
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
46519
47101
|
projection = "equirectangular";
|
|
@@ -46531,11 +47113,20 @@ function resolveMap(parsed, data) {
|
|
|
46531
47113
|
result.edges = edges;
|
|
46532
47114
|
result.routes = routes;
|
|
46533
47115
|
result.basemaps = {
|
|
46534
|
-
|
|
47116
|
+
// Tier is intentionally pinned to detail (50m) at ALL scales. Diagrammo maps
|
|
47117
|
+
// are presentational (palette tints, relief hachures, POI hubs), not
|
|
47118
|
+
// survey-grade — recognizability > generalization: 110m coarse drops the
|
|
47119
|
+
// Italian boot to a stump at world scale. `WORLD_SPAN` lives on only for the
|
|
47120
|
+
// projection decision (the `usOriented`/`span > WORLD_SPAN` chain above); it
|
|
47121
|
+
// no longer gates basemap resolution.
|
|
47122
|
+
// `worldCoarse` is still loaded — it's the authoritative name/bbox index
|
|
47123
|
+
// (featureIndex, featureBboxPrimary), not dead code.
|
|
47124
|
+
world: "detail",
|
|
46535
47125
|
subdivisions
|
|
46536
47126
|
};
|
|
46537
47127
|
result.extent = extent2;
|
|
46538
47128
|
result.projection = projection;
|
|
47129
|
+
result.poiFrameContainers = containerRegionIds;
|
|
46539
47130
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
46540
47131
|
return result;
|
|
46541
47132
|
}
|
|
@@ -46572,7 +47163,7 @@ function firstError(diags) {
|
|
|
46572
47163
|
const e = diags.find((d) => d.severity === "error");
|
|
46573
47164
|
return e ? formatDgmoError(e) : null;
|
|
46574
47165
|
}
|
|
46575
|
-
var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES, US_STATE_POSTAL;
|
|
47166
|
+
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;
|
|
46576
47167
|
var init_resolver2 = __esm({
|
|
46577
47168
|
"src/map/resolver.ts"() {
|
|
46578
47169
|
"use strict";
|
|
@@ -46581,8 +47172,11 @@ var init_resolver2 = __esm({
|
|
|
46581
47172
|
WORLD_SPAN = 90;
|
|
46582
47173
|
MERCATOR_MAX_LAT = 80;
|
|
46583
47174
|
PAD_FRACTION = 0.05;
|
|
47175
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46584
47176
|
WORLD_LAT_SOUTH = -58;
|
|
46585
47177
|
WORLD_LAT_NORTH = 78;
|
|
47178
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
47179
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46586
47180
|
REGION_ALIASES = {
|
|
46587
47181
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46588
47182
|
"united states": "united states of america",
|
|
@@ -46660,10 +47254,277 @@ var init_resolver2 = __esm({
|
|
|
46660
47254
|
}
|
|
46661
47255
|
});
|
|
46662
47256
|
|
|
47257
|
+
// src/map/colorize.ts
|
|
47258
|
+
function assignColors(isos, adjacency) {
|
|
47259
|
+
const sorted = [...isos].sort();
|
|
47260
|
+
const byIso = /* @__PURE__ */ new Map();
|
|
47261
|
+
let maxIndex = -1;
|
|
47262
|
+
for (const iso of sorted) {
|
|
47263
|
+
const taken = /* @__PURE__ */ new Set();
|
|
47264
|
+
for (const n of adjacency.get(iso) ?? []) {
|
|
47265
|
+
const c = byIso.get(n);
|
|
47266
|
+
if (c !== void 0) taken.add(c);
|
|
47267
|
+
}
|
|
47268
|
+
let h = 0;
|
|
47269
|
+
while (taken.has(h)) h++;
|
|
47270
|
+
byIso.set(iso, h);
|
|
47271
|
+
if (h > maxIndex) maxIndex = h;
|
|
47272
|
+
}
|
|
47273
|
+
return { byIso, huesNeeded: maxIndex + 1 };
|
|
47274
|
+
}
|
|
47275
|
+
var init_colorize = __esm({
|
|
47276
|
+
"src/map/colorize.ts"() {
|
|
47277
|
+
"use strict";
|
|
47278
|
+
}
|
|
47279
|
+
});
|
|
47280
|
+
|
|
47281
|
+
// src/map/context-labels.ts
|
|
47282
|
+
function tierBand(maxSpanDeg) {
|
|
47283
|
+
if (maxSpanDeg >= 90) return "world";
|
|
47284
|
+
if (maxSpanDeg >= 20) return "continental";
|
|
47285
|
+
if (maxSpanDeg >= 5) return "regional";
|
|
47286
|
+
return "local";
|
|
47287
|
+
}
|
|
47288
|
+
function labelBudget(width, height, band) {
|
|
47289
|
+
const bandCap = {
|
|
47290
|
+
world: 6,
|
|
47291
|
+
continental: 5,
|
|
47292
|
+
regional: 4,
|
|
47293
|
+
local: 3
|
|
47294
|
+
};
|
|
47295
|
+
const area2 = Math.floor(Math.sqrt(Math.max(0, width * height)) / 150);
|
|
47296
|
+
return Math.max(0, Math.min(area2, bandCap[band]));
|
|
47297
|
+
}
|
|
47298
|
+
function waterEligible(tier, kind, band) {
|
|
47299
|
+
switch (band) {
|
|
47300
|
+
case "world":
|
|
47301
|
+
return tier <= 1 && (kind === "ocean" || kind === "sea");
|
|
47302
|
+
case "continental":
|
|
47303
|
+
return tier <= 2;
|
|
47304
|
+
case "regional":
|
|
47305
|
+
return tier <= 3;
|
|
47306
|
+
case "local":
|
|
47307
|
+
return tier <= 4;
|
|
47308
|
+
}
|
|
47309
|
+
}
|
|
47310
|
+
function insideViewport(p, width, height) {
|
|
47311
|
+
return !!p && Number.isFinite(p[0]) && Number.isFinite(p[1]) && p[0] >= 0 && p[0] <= width && p[1] >= 0 && p[1] <= height;
|
|
47312
|
+
}
|
|
47313
|
+
function labelWidth(text, letterSpacing) {
|
|
47314
|
+
const spacing = letterSpacing > 0 ? Math.max(0, text.length - 1) * letterSpacing : 0;
|
|
47315
|
+
return measureLegendText(text, FONT) + spacing + 2 * PADX;
|
|
47316
|
+
}
|
|
47317
|
+
function wrapLabel2(text, letterSpacing) {
|
|
47318
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
47319
|
+
if (words.length <= 1) return [text];
|
|
47320
|
+
const maxLines = words.length >= 4 ? 3 : 2;
|
|
47321
|
+
const n = words.length;
|
|
47322
|
+
let best = null;
|
|
47323
|
+
for (let mask = 0; mask < 1 << n - 1; mask++) {
|
|
47324
|
+
const lines = [];
|
|
47325
|
+
let cur = [words[0]];
|
|
47326
|
+
for (let i = 1; i < n; i++) {
|
|
47327
|
+
if (mask & 1 << i - 1) {
|
|
47328
|
+
lines.push(cur.join(" "));
|
|
47329
|
+
cur = [words[i]];
|
|
47330
|
+
} else cur.push(words[i]);
|
|
47331
|
+
}
|
|
47332
|
+
lines.push(cur.join(" "));
|
|
47333
|
+
if (lines.length > maxLines) continue;
|
|
47334
|
+
const cost = Math.round(
|
|
47335
|
+
Math.max(...lines.map((l) => labelWidth(l, letterSpacing)))
|
|
47336
|
+
);
|
|
47337
|
+
const head = labelWidth(lines[0], letterSpacing);
|
|
47338
|
+
if (!best || cost < best.cost || cost === best.cost && lines.length < best.lines.length || cost === best.cost && lines.length === best.lines.length && head > best.head)
|
|
47339
|
+
best = { lines, cost, head };
|
|
47340
|
+
}
|
|
47341
|
+
return best?.lines ?? [text];
|
|
47342
|
+
}
|
|
47343
|
+
function rectAround(cx, cy, lines, letterSpacing) {
|
|
47344
|
+
const w = Math.max(...lines.map((l) => labelWidth(l, letterSpacing)));
|
|
47345
|
+
const h = (lines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY;
|
|
47346
|
+
return { x: cx - w / 2, y: cy - h / 2, w, h };
|
|
47347
|
+
}
|
|
47348
|
+
function rectFits(r, width, height) {
|
|
47349
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
47350
|
+
}
|
|
47351
|
+
function overlapsPadded(a, b, pad2) {
|
|
47352
|
+
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;
|
|
47353
|
+
}
|
|
47354
|
+
function placeContextLabels(args) {
|
|
47355
|
+
const {
|
|
47356
|
+
projection,
|
|
47357
|
+
dLonSpan,
|
|
47358
|
+
dLatSpan,
|
|
47359
|
+
width,
|
|
47360
|
+
height,
|
|
47361
|
+
waterBodies,
|
|
47362
|
+
countries,
|
|
47363
|
+
palette,
|
|
47364
|
+
project,
|
|
47365
|
+
collides,
|
|
47366
|
+
overLand
|
|
47367
|
+
} = args;
|
|
47368
|
+
void projection;
|
|
47369
|
+
const band = tierBand(Math.max(dLonSpan, dLatSpan));
|
|
47370
|
+
const budget = labelBudget(width, height, band);
|
|
47371
|
+
if (budget <= 0) return [];
|
|
47372
|
+
const waterColor = mix(palette.colors.blue, palette.textMuted, 50);
|
|
47373
|
+
const countryColor = palette.textMuted;
|
|
47374
|
+
const haloColor = palette.bg;
|
|
47375
|
+
const candidates = [];
|
|
47376
|
+
const center = [width / 2, height / 2];
|
|
47377
|
+
for (const e of waterBodies?.entries ?? []) {
|
|
47378
|
+
const [lat, lon, name, tier, kind, alt] = e;
|
|
47379
|
+
if (!waterEligible(tier, kind, band)) continue;
|
|
47380
|
+
const wlines = wrapLabel2(name, WATER_LETTER_SPACING);
|
|
47381
|
+
const anchorsLngLat = [[lon, lat]];
|
|
47382
|
+
for (const a of alt ?? []) anchorsLngLat.push([a[1], a[0]]);
|
|
47383
|
+
let best = null;
|
|
47384
|
+
let bestD = Infinity;
|
|
47385
|
+
let nearestProj = null;
|
|
47386
|
+
let nearestProjD = Infinity;
|
|
47387
|
+
for (const [aLon, aLat] of anchorsLngLat) {
|
|
47388
|
+
const p = project(aLon, aLat);
|
|
47389
|
+
if (!p || !Number.isFinite(p[0]) || !Number.isFinite(p[1])) continue;
|
|
47390
|
+
const d = (p[0] - center[0]) ** 2 + (p[1] - center[1]) ** 2;
|
|
47391
|
+
if (d < nearestProjD) {
|
|
47392
|
+
nearestProjD = d;
|
|
47393
|
+
nearestProj = p;
|
|
47394
|
+
}
|
|
47395
|
+
if (!insideViewport(p, width, height)) continue;
|
|
47396
|
+
if (d < bestD) {
|
|
47397
|
+
bestD = d;
|
|
47398
|
+
best = p;
|
|
47399
|
+
}
|
|
47400
|
+
}
|
|
47401
|
+
if (!best && tier === 0 && nearestProj) {
|
|
47402
|
+
const overX = Math.max(0, -nearestProj[0], nearestProj[0] - width);
|
|
47403
|
+
const overY = Math.max(0, -nearestProj[1], nearestProj[1] - height);
|
|
47404
|
+
if (overX <= width * EDGE_CLAMP_OVERSHOOT && overY <= height * EDGE_CLAMP_OVERSHOOT) {
|
|
47405
|
+
const halfW = Math.max(...wlines.map((l) => labelWidth(l, WATER_LETTER_SPACING))) / 2;
|
|
47406
|
+
const halfH = ((wlines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY) / 2;
|
|
47407
|
+
const m = EDGE_CLAMP_MARGIN;
|
|
47408
|
+
best = [
|
|
47409
|
+
Math.min(Math.max(nearestProj[0], halfW + m), width - halfW - m),
|
|
47410
|
+
Math.min(Math.max(nearestProj[1], halfH + m), height - halfH - m)
|
|
47411
|
+
];
|
|
47412
|
+
}
|
|
47413
|
+
}
|
|
47414
|
+
if (!best) continue;
|
|
47415
|
+
candidates.push({
|
|
47416
|
+
text: name,
|
|
47417
|
+
lines: wlines,
|
|
47418
|
+
cx: best[0],
|
|
47419
|
+
cy: best[1],
|
|
47420
|
+
italic: true,
|
|
47421
|
+
letterSpacing: WATER_LETTER_SPACING,
|
|
47422
|
+
color: waterColor,
|
|
47423
|
+
// Water before any country (×1000), then by tier, then kind, then name.
|
|
47424
|
+
sort: tier * 10 + KIND_ORDER[kind]
|
|
47425
|
+
});
|
|
47426
|
+
}
|
|
47427
|
+
const ranked = countries.map((c) => {
|
|
47428
|
+
const [x0, y0, x1, y1] = c.bbox;
|
|
47429
|
+
const w = x1 - x0;
|
|
47430
|
+
const h = y1 - y0;
|
|
47431
|
+
return { c, w, h, area: w * h };
|
|
47432
|
+
}).filter((r) => Number.isFinite(r.area) && r.area > 0).sort((a, b) => b.area - a.area);
|
|
47433
|
+
let ci = 0;
|
|
47434
|
+
for (const r of ranked) {
|
|
47435
|
+
const { c, w, h } = r;
|
|
47436
|
+
if (w > width * 0.66 || h > height * 0.66) continue;
|
|
47437
|
+
if (!insideViewport(c.anchor, width, height)) continue;
|
|
47438
|
+
const text = c.name;
|
|
47439
|
+
const tw = labelWidth(text, 0);
|
|
47440
|
+
if (tw > w || FONT + 2 * PADY > h) continue;
|
|
47441
|
+
candidates.push({
|
|
47442
|
+
text,
|
|
47443
|
+
lines: [text],
|
|
47444
|
+
cx: c.anchor[0],
|
|
47445
|
+
cy: c.anchor[1],
|
|
47446
|
+
italic: false,
|
|
47447
|
+
letterSpacing: 0,
|
|
47448
|
+
color: countryColor,
|
|
47449
|
+
// Always after every water body (+1e6); larger area = earlier.
|
|
47450
|
+
sort: 1e6 + ci++
|
|
47451
|
+
});
|
|
47452
|
+
}
|
|
47453
|
+
candidates.sort((a, b) => a.sort - b.sort);
|
|
47454
|
+
const placed = [];
|
|
47455
|
+
const placedRects = [];
|
|
47456
|
+
for (const cand of candidates) {
|
|
47457
|
+
if (placed.length >= budget) break;
|
|
47458
|
+
const rect = rectAround(cand.cx, cand.cy, cand.lines, cand.letterSpacing);
|
|
47459
|
+
if (!rectFits(rect, width, height)) continue;
|
|
47460
|
+
if (cand.italic && overLand) {
|
|
47461
|
+
const inset = 2;
|
|
47462
|
+
const top = cand.cy - (cand.lines.length - 1) / 2 * LINE_HEIGHT;
|
|
47463
|
+
const touchesLand = cand.lines.some((line12, li) => {
|
|
47464
|
+
const lw = labelWidth(line12, cand.letterSpacing);
|
|
47465
|
+
const x0 = cand.cx - lw / 2 + inset;
|
|
47466
|
+
const x1 = cand.cx + lw / 2 - inset;
|
|
47467
|
+
const xs = [x0, (x0 + cand.cx) / 2, cand.cx, (cand.cx + x1) / 2, x1];
|
|
47468
|
+
const base = top + li * LINE_HEIGHT;
|
|
47469
|
+
return [base, base - FONT * 0.4, base - FONT * 0.8].some(
|
|
47470
|
+
(y) => xs.some((x) => overLand(x, y))
|
|
47471
|
+
);
|
|
47472
|
+
});
|
|
47473
|
+
if (touchesLand) continue;
|
|
47474
|
+
}
|
|
47475
|
+
if (collides(rect)) continue;
|
|
47476
|
+
if (placedRects.some((r) => overlapsPadded(rect, r, CONTEXT_PAD))) continue;
|
|
47477
|
+
placedRects.push(rect);
|
|
47478
|
+
placed.push({
|
|
47479
|
+
x: cand.cx,
|
|
47480
|
+
y: cand.cy,
|
|
47481
|
+
text: cand.text,
|
|
47482
|
+
anchor: "middle",
|
|
47483
|
+
color: cand.color,
|
|
47484
|
+
// No halo: the bg-coloured outline reads as a ghost box behind the text
|
|
47485
|
+
// over the tinted water/land. Context labels are muted enough to sit
|
|
47486
|
+
// cleanly on the basemap without one.
|
|
47487
|
+
halo: false,
|
|
47488
|
+
haloColor,
|
|
47489
|
+
italic: cand.italic,
|
|
47490
|
+
letterSpacing: cand.letterSpacing,
|
|
47491
|
+
...cand.lines.length > 1 ? { lines: cand.lines } : {},
|
|
47492
|
+
lineNumber: 0
|
|
47493
|
+
});
|
|
47494
|
+
}
|
|
47495
|
+
return placed;
|
|
47496
|
+
}
|
|
47497
|
+
var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, KIND_ORDER;
|
|
47498
|
+
var init_context_labels = __esm({
|
|
47499
|
+
"src/map/context-labels.ts"() {
|
|
47500
|
+
"use strict";
|
|
47501
|
+
init_color_utils();
|
|
47502
|
+
init_legend_constants();
|
|
47503
|
+
FONT = 11;
|
|
47504
|
+
LINE_HEIGHT = FONT + 2;
|
|
47505
|
+
PADX = 4;
|
|
47506
|
+
PADY = 3;
|
|
47507
|
+
WATER_LETTER_SPACING = 1.5;
|
|
47508
|
+
CONTEXT_PAD = 4;
|
|
47509
|
+
EDGE_CLAMP_MARGIN = 8;
|
|
47510
|
+
EDGE_CLAMP_OVERSHOOT = 0.35;
|
|
47511
|
+
KIND_ORDER = {
|
|
47512
|
+
ocean: 0,
|
|
47513
|
+
sea: 1,
|
|
47514
|
+
gulf: 2,
|
|
47515
|
+
bay: 3,
|
|
47516
|
+
strait: 4,
|
|
47517
|
+
channel: 5,
|
|
47518
|
+
sound: 6
|
|
47519
|
+
};
|
|
47520
|
+
}
|
|
47521
|
+
});
|
|
47522
|
+
|
|
46663
47523
|
// src/map/layout.ts
|
|
46664
47524
|
import {
|
|
46665
47525
|
geoPath,
|
|
46666
47526
|
geoNaturalEarth1,
|
|
47527
|
+
geoEqualEarth,
|
|
46667
47528
|
geoEquirectangular,
|
|
46668
47529
|
geoConicEqualArea,
|
|
46669
47530
|
geoMercator,
|
|
@@ -46675,12 +47536,34 @@ function geomObject2(topo) {
|
|
|
46675
47536
|
const key = Object.keys(topo.objects)[0];
|
|
46676
47537
|
return topo.objects[key];
|
|
46677
47538
|
}
|
|
47539
|
+
function mergeFeatures(a, b) {
|
|
47540
|
+
const polysOf = (f) => {
|
|
47541
|
+
const g = f.geometry;
|
|
47542
|
+
if (!g) return null;
|
|
47543
|
+
if (g.type === "Polygon") return [g.coordinates];
|
|
47544
|
+
if (g.type === "MultiPolygon") return g.coordinates;
|
|
47545
|
+
return null;
|
|
47546
|
+
};
|
|
47547
|
+
const pa = polysOf(a);
|
|
47548
|
+
const pb = polysOf(b);
|
|
47549
|
+
if (!pa || !pb) return a;
|
|
47550
|
+
return {
|
|
47551
|
+
...a,
|
|
47552
|
+
geometry: { type: "MultiPolygon", coordinates: [...pa, ...pb] }
|
|
47553
|
+
};
|
|
47554
|
+
}
|
|
46678
47555
|
function decodeLayer(topo) {
|
|
47556
|
+
const cached = decodeCache.get(topo);
|
|
47557
|
+
if (cached) return cached;
|
|
46679
47558
|
const out = /* @__PURE__ */ new Map();
|
|
46680
47559
|
for (const g of geomObject2(topo).geometries) {
|
|
46681
47560
|
const f = feature2(topo, g);
|
|
46682
|
-
|
|
47561
|
+
if (!f.geometry) continue;
|
|
47562
|
+
const tagged = { ...f, id: g.id };
|
|
47563
|
+
const existing = out.get(g.id);
|
|
47564
|
+
out.set(g.id, existing ? mergeFeatures(existing, tagged) : tagged);
|
|
46683
47565
|
}
|
|
47566
|
+
decodeCache.set(topo, out);
|
|
46684
47567
|
return out;
|
|
46685
47568
|
}
|
|
46686
47569
|
function projectionFor(family) {
|
|
@@ -46689,9 +47572,12 @@ function projectionFor(family) {
|
|
|
46689
47572
|
return usConusProjection();
|
|
46690
47573
|
case "mercator":
|
|
46691
47574
|
return geoMercator();
|
|
47575
|
+
case "equal-earth":
|
|
47576
|
+
return geoEqualEarth();
|
|
47577
|
+
case "equirectangular":
|
|
47578
|
+
return geoEquirectangular();
|
|
46692
47579
|
case "natural-earth":
|
|
46693
47580
|
return geoNaturalEarth1();
|
|
46694
|
-
case "equirectangular":
|
|
46695
47581
|
default:
|
|
46696
47582
|
return geoEquirectangular();
|
|
46697
47583
|
}
|
|
@@ -46710,13 +47596,11 @@ function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
|
46710
47596
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46711
47597
|
);
|
|
46712
47598
|
}
|
|
46713
|
-
function
|
|
46714
|
-
const { palette, isDark } = opts;
|
|
46715
|
-
const { width, height } = size;
|
|
47599
|
+
function buildMapProjection(resolved, data) {
|
|
46716
47600
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46717
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47601
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46718
47602
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46719
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47603
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46720
47604
|
if (usCrisp && data.naLand) {
|
|
46721
47605
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46722
47606
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46725,16 +47609,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46725
47609
|
if (!base) continue;
|
|
46726
47610
|
const [[bw, bs], [be, bn]] = geoBounds2(base);
|
|
46727
47611
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46728
|
-
worldLayer.set(iso, cf);
|
|
47612
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46729
47613
|
}
|
|
46730
47614
|
}
|
|
46731
47615
|
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
47616
|
+
const extentOutline = () => {
|
|
47617
|
+
const [[w, s], [e, n]] = resolved.extent;
|
|
47618
|
+
const N = 16;
|
|
47619
|
+
const coords = [];
|
|
47620
|
+
for (let i = 0; i <= N; i++) {
|
|
47621
|
+
const t = i / N;
|
|
47622
|
+
const lon = w + (e - w) * t;
|
|
47623
|
+
const lat = s + (n - s) * t;
|
|
47624
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
47625
|
+
}
|
|
47626
|
+
return {
|
|
47627
|
+
type: "Feature",
|
|
47628
|
+
properties: {},
|
|
47629
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
47630
|
+
};
|
|
47631
|
+
};
|
|
47632
|
+
let fitFeatures;
|
|
47633
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
47634
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
47635
|
+
const neighborPoints = resolved.pois.filter((p) => !inAlaska(p.lon, p.lat) && !inHawaii(p.lon, p.lat)).map((p) => [p.lon, p.lat]);
|
|
47636
|
+
if (neighborPoints.length > 0) {
|
|
47637
|
+
fitFeatures.push({
|
|
47638
|
+
type: "Feature",
|
|
47639
|
+
properties: {},
|
|
47640
|
+
geometry: { type: "MultiPoint", coordinates: neighborPoints }
|
|
47641
|
+
});
|
|
47642
|
+
}
|
|
47643
|
+
for (const r of resolved.regions) {
|
|
47644
|
+
if (r.layer === "country" && (r.iso === "CA" || r.iso === "MX")) {
|
|
47645
|
+
const cf = worldLayer.get(r.iso);
|
|
47646
|
+
if (cf) fitFeatures.push(cf);
|
|
47647
|
+
}
|
|
47648
|
+
}
|
|
47649
|
+
} else {
|
|
47650
|
+
fitFeatures = [extentOutline()];
|
|
47651
|
+
}
|
|
47652
|
+
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
47653
|
+
const projection = projectionFor(resolved.projection);
|
|
47654
|
+
if (resolved.projection !== "albers-usa") {
|
|
47655
|
+
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
47656
|
+
if (centerLon > 180) centerLon -= 360;
|
|
47657
|
+
projection.rotate([-centerLon, 0]);
|
|
47658
|
+
}
|
|
47659
|
+
const fitGB = geoBounds2(fitTarget);
|
|
47660
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
47661
|
+
return {
|
|
47662
|
+
projection,
|
|
47663
|
+
fitTarget,
|
|
47664
|
+
fitIsGlobal,
|
|
47665
|
+
worldLayer,
|
|
47666
|
+
usLayer,
|
|
47667
|
+
usCrisp,
|
|
47668
|
+
wantsUsStates,
|
|
47669
|
+
worldTopo
|
|
47670
|
+
};
|
|
47671
|
+
}
|
|
47672
|
+
function parsePathRings(d) {
|
|
47673
|
+
const rings = [];
|
|
47674
|
+
let cur = [];
|
|
47675
|
+
const re = /([MLZ])([^MLZ]*)/g;
|
|
47676
|
+
let m;
|
|
47677
|
+
while (m = re.exec(d)) {
|
|
47678
|
+
if (m[1] === "Z") {
|
|
47679
|
+
if (cur.length) rings.push(cur);
|
|
47680
|
+
cur = [];
|
|
47681
|
+
continue;
|
|
47682
|
+
}
|
|
47683
|
+
if (m[1] === "M" && cur.length) {
|
|
47684
|
+
rings.push(cur);
|
|
47685
|
+
cur = [];
|
|
47686
|
+
}
|
|
47687
|
+
const nums = m[2].split(/[ ,]+/).map(Number);
|
|
47688
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
47689
|
+
const x = nums[i];
|
|
47690
|
+
const y = nums[i + 1];
|
|
47691
|
+
if (Number.isFinite(x) && Number.isFinite(y)) cur.push([x, y]);
|
|
47692
|
+
}
|
|
47693
|
+
}
|
|
47694
|
+
if (cur.length) rings.push(cur);
|
|
47695
|
+
return rings;
|
|
47696
|
+
}
|
|
47697
|
+
function dropAntimeridianWrapSlivers(d, width, height) {
|
|
47698
|
+
const rings = parsePathRings(d);
|
|
47699
|
+
if (rings.length <= 1) return d;
|
|
47700
|
+
const eps = 0.75;
|
|
47701
|
+
const minArea = 3e-3 * width * height;
|
|
47702
|
+
const ringArea = (r) => {
|
|
47703
|
+
let s = 0;
|
|
47704
|
+
for (let i = 0; i < r.length; i++) {
|
|
47705
|
+
const a = r[i];
|
|
47706
|
+
const b = r[(i + 1) % r.length];
|
|
47707
|
+
s += a[0] * b[1] - b[0] * a[1];
|
|
47708
|
+
}
|
|
47709
|
+
return Math.abs(s) / 2;
|
|
47710
|
+
};
|
|
47711
|
+
const areas = rings.map(ringArea);
|
|
47712
|
+
const maxArea = Math.max(...areas);
|
|
47713
|
+
const onVEdge = (a, b) => Math.abs(a[0]) <= eps && Math.abs(b[0]) <= eps || Math.abs(a[0] - width) <= eps && Math.abs(b[0] - width) <= eps;
|
|
47714
|
+
let dropped = false;
|
|
47715
|
+
const kept = rings.filter((r, idx) => {
|
|
47716
|
+
if (areas[idx] >= maxArea || areas[idx] >= minArea) return true;
|
|
47717
|
+
const touches = r.some((p, i) => onVEdge(p, r[(i + 1) % r.length]));
|
|
47718
|
+
if (touches) {
|
|
47719
|
+
dropped = true;
|
|
47720
|
+
return false;
|
|
47721
|
+
}
|
|
47722
|
+
return true;
|
|
47723
|
+
});
|
|
47724
|
+
if (!dropped) return d;
|
|
47725
|
+
return kept.map(
|
|
47726
|
+
(r) => r.map((p, i) => (i ? "L" : "M") + p[0] + "," + p[1]).join("") + "Z"
|
|
47727
|
+
).join("");
|
|
47728
|
+
}
|
|
47729
|
+
function layoutMap(resolved, data, size, opts) {
|
|
47730
|
+
const { palette, isDark } = opts;
|
|
47731
|
+
const { width, height } = size;
|
|
47732
|
+
const {
|
|
47733
|
+
projection,
|
|
47734
|
+
fitTarget,
|
|
47735
|
+
fitIsGlobal,
|
|
47736
|
+
worldLayer,
|
|
47737
|
+
usLayer,
|
|
47738
|
+
usCrisp,
|
|
47739
|
+
worldTopo
|
|
47740
|
+
} = buildMapProjection(resolved, data);
|
|
46732
47741
|
const usContext = usLayer !== null;
|
|
46733
47742
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46734
47743
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46735
|
-
const
|
|
46736
|
-
const rampMin =
|
|
46737
|
-
const rampMax =
|
|
47744
|
+
const allNonNegative = values.length > 0 && values.every((v) => v >= 0);
|
|
47745
|
+
const rampMin = allNonNegative ? 0 : Math.min(...values);
|
|
47746
|
+
const rampMax = Math.max(...values);
|
|
46738
47747
|
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46739
47748
|
const hasRamp = values.length > 0;
|
|
46740
47749
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
@@ -46755,7 +47764,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46755
47764
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46756
47765
|
}
|
|
46757
47766
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46758
|
-
const mutedBasemap =
|
|
47767
|
+
const mutedBasemap = activeGroup !== null;
|
|
46759
47768
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46760
47769
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
46761
47770
|
const lakeStroke = mix(regionStroke, water, 45);
|
|
@@ -46764,10 +47773,43 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46764
47773
|
palette.bg,
|
|
46765
47774
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46766
47775
|
);
|
|
47776
|
+
const colorizeActive = resolved.directives.noColorize !== true && !hasRamp && resolved.tagGroups.length === 0;
|
|
47777
|
+
const colorByIso = /* @__PURE__ */ new Map();
|
|
47778
|
+
if (colorizeActive) {
|
|
47779
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
47780
|
+
const addEdges = (src) => {
|
|
47781
|
+
for (const [iso, ns] of src) {
|
|
47782
|
+
const cur = adjacency.get(iso);
|
|
47783
|
+
if (cur) cur.push(...ns);
|
|
47784
|
+
else adjacency.set(iso, [...ns]);
|
|
47785
|
+
}
|
|
47786
|
+
};
|
|
47787
|
+
addEdges(buildAdjacency(worldTopo));
|
|
47788
|
+
if (usLayer) {
|
|
47789
|
+
addEdges(buildAdjacency(data.usStates));
|
|
47790
|
+
for (const [country, states] of Object.entries(FOREIGN_BORDER)) {
|
|
47791
|
+
const cn = adjacency.get(country);
|
|
47792
|
+
if (!cn) continue;
|
|
47793
|
+
for (const st of states) {
|
|
47794
|
+
const sn = adjacency.get(st);
|
|
47795
|
+
if (!sn) continue;
|
|
47796
|
+
cn.push(st);
|
|
47797
|
+
sn.push(country);
|
|
47798
|
+
}
|
|
47799
|
+
}
|
|
47800
|
+
}
|
|
47801
|
+
const { byIso, huesNeeded } = assignColors(
|
|
47802
|
+
[...adjacency.keys()],
|
|
47803
|
+
adjacency
|
|
47804
|
+
);
|
|
47805
|
+
const tints = politicalTints(palette, huesNeeded, isDark);
|
|
47806
|
+
for (const [iso, idx] of byIso) colorByIso.set(iso, tints[idx]);
|
|
47807
|
+
}
|
|
47808
|
+
const colorizeStroke = (fill2) => mix(fill2, palette.text, 35);
|
|
46767
47809
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46768
47810
|
const fillForValue = (s) => {
|
|
46769
47811
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
46770
|
-
const pct =
|
|
47812
|
+
const pct = RAMP_FLOOR2 + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR2);
|
|
46771
47813
|
return mix(rampHue, rampBase, pct);
|
|
46772
47814
|
};
|
|
46773
47815
|
const tagFill = (tags, groupName) => {
|
|
@@ -46799,43 +47841,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46799
47841
|
if (activeIsScore) {
|
|
46800
47842
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46801
47843
|
}
|
|
47844
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46802
47845
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46803
47846
|
};
|
|
46804
47847
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46805
|
-
const
|
|
46806
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46807
|
-
const N = 16;
|
|
46808
|
-
const coords = [];
|
|
46809
|
-
for (let i = 0; i <= N; i++) {
|
|
46810
|
-
const t = i / N;
|
|
46811
|
-
const lon = w + (e - w) * t;
|
|
46812
|
-
const lat = s + (n - s) * t;
|
|
46813
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46814
|
-
}
|
|
46815
|
-
return {
|
|
46816
|
-
type: "Feature",
|
|
46817
|
-
properties: {},
|
|
46818
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46819
|
-
};
|
|
46820
|
-
};
|
|
46821
|
-
let fitFeatures;
|
|
46822
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46823
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46824
|
-
} else {
|
|
46825
|
-
fitFeatures = [extentOutline()];
|
|
46826
|
-
}
|
|
46827
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46828
|
-
const projection = projectionFor(resolved.projection);
|
|
46829
|
-
if (resolved.projection !== "albers-usa") {
|
|
46830
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46831
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46832
|
-
projection.rotate([-centerLon, 0]);
|
|
46833
|
-
}
|
|
46834
|
-
const TITLE_GAP = 16;
|
|
47848
|
+
const TITLE_GAP2 = 16;
|
|
46835
47849
|
let topPad = FIT_PAD;
|
|
46836
47850
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46837
47851
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46838
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47852
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46839
47853
|
}
|
|
46840
47854
|
const fitBox = [
|
|
46841
47855
|
[FIT_PAD, topPad],
|
|
@@ -46845,21 +47859,20 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46845
47859
|
]
|
|
46846
47860
|
];
|
|
46847
47861
|
projection.fitExtent(fitBox, fitTarget);
|
|
46848
|
-
const fitGB = geoBounds2(fitTarget);
|
|
46849
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46850
47862
|
let path;
|
|
46851
47863
|
let project;
|
|
46852
47864
|
let stretchParams = null;
|
|
46853
|
-
if (fitIsGlobal) {
|
|
47865
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46854
47866
|
const cb = geoPath(projection).bounds(fitTarget);
|
|
46855
47867
|
const bx0 = cb[0][0];
|
|
46856
47868
|
const by0 = cb[0][1];
|
|
46857
47869
|
const cw = cb[1][0] - bx0;
|
|
46858
47870
|
const ch = cb[1][1] - by0;
|
|
46859
|
-
const
|
|
46860
|
-
const
|
|
46861
|
-
const
|
|
46862
|
-
const
|
|
47871
|
+
const topReserve = resolved.title && resolved.pois.length > 0 ? topPad : 0;
|
|
47872
|
+
const ox = 0;
|
|
47873
|
+
const oy = topReserve;
|
|
47874
|
+
const sx = cw > 0 ? width / cw : 1;
|
|
47875
|
+
const sy = ch > 0 ? (height - topReserve) / ch : 1;
|
|
46863
47876
|
stretchParams = { sx, sy, ox, oy, bx0, by0 };
|
|
46864
47877
|
const stretch = (x, y) => [
|
|
46865
47878
|
ox + (x - bx0) * sx,
|
|
@@ -46892,7 +47905,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46892
47905
|
const insets = [];
|
|
46893
47906
|
const insetRegions = [];
|
|
46894
47907
|
const insetLabelSeeds = [];
|
|
46895
|
-
|
|
47908
|
+
const akRef = resolved.regions.some((r) => r.iso === "US-AK") || resolved.pois.some((p) => inAlaska(p.lon, p.lat));
|
|
47909
|
+
const hiRef = resolved.regions.some((r) => r.iso === "US-HI") || resolved.pois.some((p) => inHawaii(p.lon, p.lat));
|
|
47910
|
+
if (resolved.projection === "albers-usa" && usLayer && (akRef || hiRef)) {
|
|
46896
47911
|
const PAD = 8;
|
|
46897
47912
|
const GAP = 12;
|
|
46898
47913
|
const yB = height - FIT_PAD;
|
|
@@ -46957,8 +47972,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46957
47972
|
);
|
|
46958
47973
|
const d = geoPath(proj)(f) ?? "";
|
|
46959
47974
|
if (!d) return xr;
|
|
47975
|
+
let contextLand;
|
|
47976
|
+
if (iso === "US-AK") {
|
|
47977
|
+
const can = worldLayer.get("CA");
|
|
47978
|
+
const cd = can ? geoPath(proj)(can) ?? "" : "";
|
|
47979
|
+
if (cd)
|
|
47980
|
+
contextLand = {
|
|
47981
|
+
d: cd,
|
|
47982
|
+
fill: colorizeActive ? colorByIso.get("CA") ?? foreignFill : foreignFill
|
|
47983
|
+
};
|
|
47984
|
+
}
|
|
46960
47985
|
const r = regionById.get(iso);
|
|
46961
|
-
let fill2 = neutralFill;
|
|
47986
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46962
47987
|
let lineNumber = -1;
|
|
46963
47988
|
if (r?.layer === "us-state") {
|
|
46964
47989
|
fill2 = regionFill(r);
|
|
@@ -46977,13 +48002,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46977
48002
|
],
|
|
46978
48003
|
// The FITTED inset projection (just fit to this box) — captured so the
|
|
46979
48004
|
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
46980
|
-
projection: proj
|
|
48005
|
+
projection: proj,
|
|
48006
|
+
...contextLand && { contextLand }
|
|
46981
48007
|
});
|
|
46982
48008
|
insetRegions.push({
|
|
46983
48009
|
id: iso,
|
|
46984
48010
|
d,
|
|
46985
48011
|
fill: fill2,
|
|
46986
|
-
stroke: regionStroke,
|
|
48012
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46987
48013
|
lineNumber,
|
|
46988
48014
|
layer: "us-state",
|
|
46989
48015
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46996,13 +48022,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46996
48022
|
}
|
|
46997
48023
|
return xr;
|
|
46998
48024
|
};
|
|
46999
|
-
|
|
47000
|
-
|
|
47001
|
-
alaskaProjection(),
|
|
47002
|
-
|
|
47003
|
-
|
|
47004
|
-
|
|
47005
|
-
|
|
48025
|
+
let akRight = FIT_PAD;
|
|
48026
|
+
if (akRef)
|
|
48027
|
+
akRight = placeInset("US-AK", alaskaProjection(), FIT_PAD, width * 0.15);
|
|
48028
|
+
if (hiRef)
|
|
48029
|
+
placeInset(
|
|
48030
|
+
"US-HI",
|
|
48031
|
+
hawaiiProjection(),
|
|
48032
|
+
akRef ? akRight + 24 : FIT_PAD,
|
|
48033
|
+
width * 0.1
|
|
48034
|
+
);
|
|
47006
48035
|
}
|
|
47007
48036
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
47008
48037
|
const classifyExtent = conusFit ? geoBounds2(fitTarget) : resolved.extent;
|
|
@@ -47018,15 +48047,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47018
48047
|
};
|
|
47019
48048
|
const ringOverlapsView = (ring) => {
|
|
47020
48049
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
48050
|
+
const lons = [];
|
|
47021
48051
|
for (const [rawLon] of ring) {
|
|
47022
48052
|
const lon = normLon(rawLon);
|
|
48053
|
+
lons.push(lon);
|
|
47023
48054
|
if (lon < loMin) loMin = lon;
|
|
47024
48055
|
if (lon > loMax) loMax = lon;
|
|
47025
48056
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
47026
48057
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
47027
48058
|
}
|
|
47028
|
-
|
|
47029
|
-
|
|
48059
|
+
lons.sort((a, b) => a - b);
|
|
48060
|
+
let maxGap = 0;
|
|
48061
|
+
for (let i = 1; i < lons.length; i++)
|
|
48062
|
+
maxGap = Math.max(maxGap, lons[i] - lons[i - 1]);
|
|
48063
|
+
if (lons.length > 1)
|
|
48064
|
+
maxGap = Math.max(maxGap, lons[0] + 360 - lons[lons.length - 1]);
|
|
48065
|
+
const occupiedArc = 360 - maxGap;
|
|
48066
|
+
if (occupiedArc > 270) return false;
|
|
48067
|
+
if (rawMax - rawMin > 180 && occupiedArc < 90) return false;
|
|
47030
48068
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
47031
48069
|
for (const [lon, lat] of ring) {
|
|
47032
48070
|
const p = project(lon, lat);
|
|
@@ -47099,7 +48137,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47099
48137
|
const regions = [];
|
|
47100
48138
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
47101
48139
|
for (const [iso, f] of layerFeatures) {
|
|
47102
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
48140
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
47103
48141
|
continue;
|
|
47104
48142
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
47105
48143
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -47107,11 +48145,13 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47107
48145
|
const r = regionById.get(iso);
|
|
47108
48146
|
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
47109
48147
|
if (!viewF) continue;
|
|
47110
|
-
const
|
|
48148
|
+
const raw = path(viewF) ?? "";
|
|
48149
|
+
const d = fitIsGlobal ? dropAntimeridianWrapSlivers(raw, width, height) : raw;
|
|
47111
48150
|
if (!d) continue;
|
|
47112
48151
|
const isThisLayer = r?.layer === layerKind;
|
|
47113
48152
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
47114
|
-
|
|
48153
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
48154
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
47115
48155
|
let label;
|
|
47116
48156
|
let lineNumber = -1;
|
|
47117
48157
|
let layer = "base";
|
|
@@ -47120,15 +48160,21 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47120
48160
|
lineNumber = r.lineNumber;
|
|
47121
48161
|
layer = layerKind;
|
|
47122
48162
|
label = r.name;
|
|
48163
|
+
} else {
|
|
48164
|
+
label = f.properties?.name;
|
|
47123
48165
|
}
|
|
48166
|
+
const labelAnchor = WORLD_LABEL_ANCHORS[iso];
|
|
48167
|
+
const c = labelAnchor ? project(labelAnchor[0], labelAnchor[1]) : path.centroid(viewF);
|
|
48168
|
+
const hasCentroid = c != null && Number.isFinite(c[0]) && Number.isFinite(c[1]);
|
|
47124
48169
|
regions.push({
|
|
47125
48170
|
id: iso,
|
|
47126
48171
|
d,
|
|
47127
48172
|
fill: fill2,
|
|
47128
|
-
stroke: regionStroke,
|
|
48173
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
47129
48174
|
lineNumber,
|
|
47130
48175
|
layer,
|
|
47131
48176
|
...label !== void 0 && { label },
|
|
48177
|
+
...hasCentroid && { labelX: c[0], labelY: c[1] },
|
|
47132
48178
|
...isThisLayer && r.value !== void 0 && { value: r.value },
|
|
47133
48179
|
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
47134
48180
|
});
|
|
@@ -47153,9 +48199,41 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47153
48199
|
});
|
|
47154
48200
|
}
|
|
47155
48201
|
}
|
|
48202
|
+
const pointInRings = (px, py, rings) => {
|
|
48203
|
+
let inside = false;
|
|
48204
|
+
for (const ring of rings) {
|
|
48205
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
48206
|
+
const [xi, yi] = ring[i];
|
|
48207
|
+
const [xj, yj] = ring[j];
|
|
48208
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
48209
|
+
inside = !inside;
|
|
48210
|
+
}
|
|
48211
|
+
}
|
|
48212
|
+
return inside;
|
|
48213
|
+
};
|
|
48214
|
+
const fillHitTargets = [...regions, ...insetRegions].map((r) => ({
|
|
48215
|
+
fill: r.fill,
|
|
48216
|
+
rings: parsePathRings(r.d)
|
|
48217
|
+
}));
|
|
48218
|
+
const fillAt = (x, y) => {
|
|
48219
|
+
let hit = water;
|
|
48220
|
+
for (const t of fillHitTargets)
|
|
48221
|
+
if (pointInRings(x, y, t.rings)) hit = t.fill;
|
|
48222
|
+
return hit;
|
|
48223
|
+
};
|
|
48224
|
+
const labelOnFill = (fill2) => {
|
|
48225
|
+
const color = contrastRatio(fill2, palette.textOnFillDark) >= contrastRatio(fill2, palette.textOnFillLight) ? palette.textOnFillDark : palette.textOnFillLight;
|
|
48226
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
48227
|
+
return {
|
|
48228
|
+
color,
|
|
48229
|
+
halo: contrastRatio(fill2, color) < REGION_LABEL_HALO_RATIO,
|
|
48230
|
+
haloColor
|
|
48231
|
+
};
|
|
48232
|
+
};
|
|
48233
|
+
const reliefAllowed = resolved.directives.noRelief !== true;
|
|
47156
48234
|
const relief = [];
|
|
47157
48235
|
let reliefHatch = null;
|
|
47158
|
-
if (
|
|
48236
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
47159
48237
|
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
47160
48238
|
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
47161
48239
|
if (!viewF) continue;
|
|
@@ -47171,16 +48249,32 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47171
48249
|
if (relief.length) {
|
|
47172
48250
|
const darkTone = isDark ? palette.bg : palette.text;
|
|
47173
48251
|
const lightTone = isDark ? palette.text : palette.bg;
|
|
47174
|
-
const
|
|
48252
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
48253
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
47175
48254
|
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
47176
48255
|
reliefHatch = {
|
|
47177
|
-
color: mix(tone,
|
|
48256
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
47178
48257
|
spacing: RELIEF_HATCH_SPACING,
|
|
47179
48258
|
width: RELIEF_HATCH_WIDTH
|
|
47180
48259
|
};
|
|
47181
48260
|
}
|
|
47182
48261
|
}
|
|
47183
|
-
|
|
48262
|
+
let coastlineStyle = null;
|
|
48263
|
+
if (resolved.directives.noCoastline !== true) {
|
|
48264
|
+
const minDim = Math.min(width, height);
|
|
48265
|
+
coastlineStyle = {
|
|
48266
|
+
color: mix(regionStroke, water, COASTLINE_STROKE_MIX),
|
|
48267
|
+
// N equal-width rings: distance steps outward by COASTLINE_STEP; opacity
|
|
48268
|
+
// fades linearly from NEAR (innermost) to FAR (outermost).
|
|
48269
|
+
lines: Array.from({ length: COASTLINE_RING_COUNT }, (_, k) => ({
|
|
48270
|
+
d: (COASTLINE_D0 + k * COASTLINE_STEP) * minDim,
|
|
48271
|
+
thickness: COASTLINE_THICKNESS * minDim,
|
|
48272
|
+
opacity: COASTLINE_OPACITY_NEAR + (COASTLINE_OPACITY_FAR - COASTLINE_OPACITY_NEAR) * k / (COASTLINE_RING_COUNT - 1)
|
|
48273
|
+
})),
|
|
48274
|
+
minExtent: (isGlobalView ? COASTLINE_MIN_EXTENT_GLOBAL : COASTLINE_MIN_EXTENT) * minDim
|
|
48275
|
+
};
|
|
48276
|
+
}
|
|
48277
|
+
const riverColor = mix(palette.colors.blue, water, 32);
|
|
47184
48278
|
const rivers = [];
|
|
47185
48279
|
if (data.rivers) {
|
|
47186
48280
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -47236,38 +48330,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47236
48330
|
const xy = project(p.lon, p.lat);
|
|
47237
48331
|
if (xy) projected.push({ p, xy });
|
|
47238
48332
|
}
|
|
47239
|
-
const
|
|
48333
|
+
const placePoi = (e, cx, cy, clusterId) => {
|
|
48334
|
+
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
48335
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
48336
|
+
const num = routeNumberById.get(e.p.id);
|
|
48337
|
+
pois.push({
|
|
48338
|
+
id: e.p.id,
|
|
48339
|
+
cx,
|
|
48340
|
+
cy,
|
|
48341
|
+
r: radiusFor(e.p),
|
|
48342
|
+
fill: fill2,
|
|
48343
|
+
stroke: stroke2,
|
|
48344
|
+
lineNumber: e.p.lineNumber,
|
|
48345
|
+
implicit: !!e.p.implicit,
|
|
48346
|
+
isOrigin: originIds.has(e.p.id),
|
|
48347
|
+
...num !== void 0 && { routeNumber: num },
|
|
48348
|
+
...Object.keys(e.p.tags).length > 0 && { tags: e.p.tags },
|
|
48349
|
+
...clusterId !== void 0 && { clusterId }
|
|
48350
|
+
});
|
|
48351
|
+
};
|
|
48352
|
+
const clusters = [];
|
|
48353
|
+
const connected = /* @__PURE__ */ new Set();
|
|
48354
|
+
for (const e of resolved.edges) {
|
|
48355
|
+
connected.add(e.fromId);
|
|
48356
|
+
connected.add(e.toId);
|
|
48357
|
+
}
|
|
48358
|
+
for (const rt of resolved.routes) {
|
|
48359
|
+
rt.stopIds.forEach((id) => connected.add(id));
|
|
48360
|
+
}
|
|
48361
|
+
const radiusOf = (e) => radiusFor(e.p);
|
|
47240
48362
|
for (const e of projected) {
|
|
47241
|
-
|
|
47242
|
-
|
|
47243
|
-
|
|
47244
|
-
|
|
47245
|
-
|
|
47246
|
-
|
|
47247
|
-
|
|
47248
|
-
|
|
47249
|
-
|
|
47250
|
-
|
|
47251
|
-
|
|
47252
|
-
|
|
47253
|
-
|
|
47254
|
-
|
|
47255
|
-
|
|
47256
|
-
|
|
47257
|
-
|
|
47258
|
-
|
|
47259
|
-
|
|
47260
|
-
|
|
47261
|
-
|
|
47262
|
-
|
|
47263
|
-
|
|
47264
|
-
|
|
47265
|
-
|
|
47266
|
-
|
|
47267
|
-
|
|
47268
|
-
|
|
47269
|
-
|
|
47270
|
-
|
|
48363
|
+
if (connected.has(e.p.id)) placePoi(e, e.xy[0], e.xy[1]);
|
|
48364
|
+
}
|
|
48365
|
+
const groups = [];
|
|
48366
|
+
for (const e of projected) {
|
|
48367
|
+
if (connected.has(e.p.id)) continue;
|
|
48368
|
+
const r = radiusOf(e);
|
|
48369
|
+
const near = groups.find(
|
|
48370
|
+
(g) => g.some(
|
|
48371
|
+
(q) => Math.hypot(q.xy[0] - e.xy[0], q.xy[1] - e.xy[1]) < (r + radiusOf(q)) * STACK_OVERLAP
|
|
48372
|
+
)
|
|
48373
|
+
);
|
|
48374
|
+
if (near) near.push(e);
|
|
48375
|
+
else groups.push([e]);
|
|
48376
|
+
}
|
|
48377
|
+
for (const g of groups) {
|
|
48378
|
+
if (g.length === 1) {
|
|
48379
|
+
placePoi(g[0], g[0].xy[0], g[0].xy[1]);
|
|
48380
|
+
continue;
|
|
48381
|
+
}
|
|
48382
|
+
const clusterId = g[0].p.id;
|
|
48383
|
+
const cx0 = g.reduce((s, e) => s + e.xy[0], 0) / g.length;
|
|
48384
|
+
const cy0 = g.reduce((s, e) => s + e.xy[1], 0) / g.length;
|
|
48385
|
+
const maxR = Math.max(...g.map(radiusOf));
|
|
48386
|
+
const sep = 2 * maxR + STACK_RING_GAP;
|
|
48387
|
+
const ringR = Math.max(
|
|
48388
|
+
COLO_R,
|
|
48389
|
+
sep / (2 * Math.sin(Math.PI / Math.max(g.length, 2)))
|
|
48390
|
+
);
|
|
48391
|
+
const positions = g.map((e, i) => {
|
|
48392
|
+
if (g.length <= STACK_RING_MAX) {
|
|
48393
|
+
const ang2 = -Math.PI / 2 + i * 2 * Math.PI / g.length;
|
|
48394
|
+
return {
|
|
48395
|
+
e,
|
|
48396
|
+
mx: cx0 + Math.cos(ang2) * ringR,
|
|
48397
|
+
my: cy0 + Math.sin(ang2) * ringR
|
|
48398
|
+
};
|
|
48399
|
+
}
|
|
48400
|
+
const ang = i * GOLDEN_ANGLE;
|
|
48401
|
+
const rr = ringR * Math.sqrt((i + 1) / g.length);
|
|
48402
|
+
return { e, mx: cx0 + Math.cos(ang) * rr, my: cy0 + Math.sin(ang) * rr };
|
|
48403
|
+
});
|
|
48404
|
+
let minX = cx0 - maxR;
|
|
48405
|
+
let maxX = cx0 + maxR;
|
|
48406
|
+
let minY = cy0 - maxR;
|
|
48407
|
+
let maxY = cy0 + maxR;
|
|
48408
|
+
for (const { mx, my, e } of positions) {
|
|
48409
|
+
const r = radiusOf(e);
|
|
48410
|
+
minX = Math.min(minX, mx - r);
|
|
48411
|
+
maxX = Math.max(maxX, mx + r);
|
|
48412
|
+
minY = Math.min(minY, my - r);
|
|
48413
|
+
maxY = Math.max(maxY, my + r);
|
|
48414
|
+
}
|
|
48415
|
+
let dx = 0;
|
|
48416
|
+
let dy = 0;
|
|
48417
|
+
if (minX + dx < 2) dx = 2 - minX;
|
|
48418
|
+
if (maxX + dx > width - 2) dx = width - 2 - maxX;
|
|
48419
|
+
if (minY + dy < 2) dy = 2 - minY;
|
|
48420
|
+
if (maxY + dy > height - 2) dy = height - 2 - maxY;
|
|
48421
|
+
const legsOut = [];
|
|
48422
|
+
for (const { e, mx, my } of positions) {
|
|
48423
|
+
const fx = mx + dx;
|
|
48424
|
+
const fy = my + dy;
|
|
48425
|
+
placePoi(e, fx, fy, clusterId);
|
|
48426
|
+
legsOut.push({ x2: fx, y2: fy, color: poiFill(e.p).fill });
|
|
48427
|
+
}
|
|
48428
|
+
clusters.push({
|
|
48429
|
+
id: clusterId,
|
|
48430
|
+
cx: cx0 + dx,
|
|
48431
|
+
cy: cy0 + dy,
|
|
48432
|
+
count: g.length,
|
|
48433
|
+
hitR: ringR + maxR + 6,
|
|
48434
|
+
legs: legsOut
|
|
47271
48435
|
});
|
|
47272
48436
|
}
|
|
47273
48437
|
const legs = [];
|
|
@@ -47317,16 +48481,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47317
48481
|
if (!a || !b) continue;
|
|
47318
48482
|
const mx = (a.cx + b.cx) / 2;
|
|
47319
48483
|
const my = (a.cy + b.cy) / 2;
|
|
48484
|
+
const bow = {
|
|
48485
|
+
curved: leg.style === "arc",
|
|
48486
|
+
offset: 0,
|
|
48487
|
+
labelX: mx,
|
|
48488
|
+
labelY: my - 4
|
|
48489
|
+
};
|
|
48490
|
+
const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
47320
48491
|
legs.push({
|
|
47321
|
-
d: legPath(a, b,
|
|
48492
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
47322
48493
|
width: routeWidthFor(Number(leg.value)),
|
|
47323
48494
|
color: mix(palette.text, palette.bg, 72),
|
|
47324
48495
|
arrow: true,
|
|
47325
48496
|
lineNumber: leg.lineNumber,
|
|
47326
48497
|
...leg.label !== void 0 && {
|
|
47327
48498
|
label: leg.label,
|
|
47328
|
-
labelX:
|
|
47329
|
-
labelY:
|
|
48499
|
+
labelX: bow.labelX,
|
|
48500
|
+
labelY: bow.labelY,
|
|
48501
|
+
labelColor: routeLabelStyle.color,
|
|
48502
|
+
labelHalo: routeLabelStyle.halo,
|
|
48503
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
47330
48504
|
}
|
|
47331
48505
|
});
|
|
47332
48506
|
}
|
|
@@ -47354,20 +48528,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47354
48528
|
const a = poiScreen.get(e.fromId);
|
|
47355
48529
|
const b = poiScreen.get(e.toId);
|
|
47356
48530
|
if (!a || !b) return;
|
|
47357
|
-
const
|
|
47358
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48531
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
47359
48532
|
const mx = (a.cx + b.cx) / 2;
|
|
47360
48533
|
const my = (a.cy + b.cy) / 2;
|
|
48534
|
+
const bow = {
|
|
48535
|
+
curved: e.style === "arc" || n > 1,
|
|
48536
|
+
offset: fanOffset,
|
|
48537
|
+
labelX: mx,
|
|
48538
|
+
labelY: my - 4
|
|
48539
|
+
};
|
|
48540
|
+
const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
47361
48541
|
legs.push({
|
|
47362
|
-
d: legPath(a, b, curved, offset),
|
|
48542
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
47363
48543
|
width: widthFor(e),
|
|
47364
48544
|
color: mix(palette.text, palette.bg, 66),
|
|
47365
48545
|
arrow: e.directed,
|
|
47366
48546
|
lineNumber: e.lineNumber,
|
|
47367
48547
|
...e.label !== void 0 && {
|
|
47368
48548
|
label: e.label,
|
|
47369
|
-
labelX:
|
|
47370
|
-
labelY:
|
|
48549
|
+
labelX: bow.labelX,
|
|
48550
|
+
labelY: bow.labelY,
|
|
48551
|
+
labelColor: edgeLabelStyle.color,
|
|
48552
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48553
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
47371
48554
|
}
|
|
47372
48555
|
});
|
|
47373
48556
|
});
|
|
@@ -47409,48 +48592,73 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47409
48592
|
}
|
|
47410
48593
|
}
|
|
47411
48594
|
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));
|
|
47412
|
-
const
|
|
48595
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48596
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
47413
48597
|
const LABEL_PADX = 6;
|
|
47414
48598
|
const LABEL_PADY = 3;
|
|
47415
|
-
const labelW = (text) => measureLegendText(text,
|
|
47416
|
-
const labelH =
|
|
48599
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48600
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
47417
48601
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
47418
|
-
const color =
|
|
47419
|
-
|
|
47420
|
-
|
|
47421
|
-
|
|
48602
|
+
const { color, haloColor } = labelOnFill(fill2);
|
|
48603
|
+
const halfW = measureLegendText(text, FONT2) / 2;
|
|
48604
|
+
const overflows = [y - FONT2 * 0.55, y - FONT2 * 0.1].some(
|
|
48605
|
+
(sy) => fillAt(x - halfW, sy) !== fill2 || fillAt(x + halfW, sy) !== fill2
|
|
47422
48606
|
);
|
|
47423
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47424
48607
|
labels.push({
|
|
47425
48608
|
x,
|
|
47426
48609
|
y,
|
|
47427
48610
|
text,
|
|
47428
48611
|
anchor: "middle",
|
|
47429
48612
|
color,
|
|
47430
|
-
halo:
|
|
48613
|
+
halo: overflows,
|
|
47431
48614
|
haloColor,
|
|
47432
48615
|
lineNumber
|
|
47433
48616
|
});
|
|
47434
48617
|
};
|
|
47435
|
-
const
|
|
47436
|
-
|
|
47437
|
-
|
|
48618
|
+
const REGION_LABEL_GAP = 2;
|
|
48619
|
+
const regionLabelRect = (cx, cy, text) => {
|
|
48620
|
+
const w = measureLegendText(text, FONT2) + 2 * REGION_LABEL_GAP;
|
|
48621
|
+
return { x: cx - w / 2, y: cy - FONT2 / 2, w, h: FONT2 };
|
|
47438
48622
|
};
|
|
47439
|
-
if (
|
|
47440
|
-
|
|
47441
|
-
|
|
47442
|
-
const
|
|
47443
|
-
if (!
|
|
48623
|
+
if (showRegionLabels) {
|
|
48624
|
+
const frameContainers = new Set(resolved.poiFrameContainers);
|
|
48625
|
+
const entries = regions.map((r) => {
|
|
48626
|
+
const isContainer = frameContainers.has(r.id);
|
|
48627
|
+
if (r.layer === "base" && !isContainer || r.label === void 0)
|
|
48628
|
+
return null;
|
|
48629
|
+
const isUsState = r.layer === "us-state" || r.id.startsWith("US-");
|
|
48630
|
+
const f = isUsState ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
48631
|
+
if (!f) return null;
|
|
47444
48632
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
47445
|
-
const
|
|
47446
|
-
|
|
47447
|
-
const
|
|
48633
|
+
const boxW = x1 - x0;
|
|
48634
|
+
const boxH = y1 - y0;
|
|
48635
|
+
const abbrev = isUsState ? r.id.replace(/^US-/, "") : void 0;
|
|
48636
|
+
const candidates = abbrev !== void 0 ? isCompact ? [abbrev, r.label] : [r.label, abbrev] : [r.label];
|
|
48637
|
+
const anchor = !isUsState ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
47448
48638
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47449
|
-
if (!c || !Number.isFinite(c[0]))
|
|
48639
|
+
if (!c || !Number.isFinite(c[0])) return null;
|
|
48640
|
+
return { r, c, boxW, boxH, area: boxW * boxH, candidates };
|
|
48641
|
+
}).filter((e) => e !== null).sort((a, b) => b.area - a.area || a.r.lineNumber - b.r.lineNumber);
|
|
48642
|
+
const placedRegionRects = [];
|
|
48643
|
+
const POI_LABEL_PAD = 14;
|
|
48644
|
+
const poiObstacles = pois.map((p) => ({
|
|
48645
|
+
x: p.cx - p.r - POI_LABEL_PAD,
|
|
48646
|
+
y: p.cy - p.r - POI_LABEL_PAD,
|
|
48647
|
+
w: 2 * (p.r + POI_LABEL_PAD),
|
|
48648
|
+
h: 2 * (p.r + POI_LABEL_PAD)
|
|
48649
|
+
}));
|
|
48650
|
+
for (const { r, c, boxW, boxH, candidates } of entries) {
|
|
48651
|
+
const text = candidates.find((t) => {
|
|
48652
|
+
if (labelW(t) > boxW || labelH > boxH) return false;
|
|
48653
|
+
const rect = regionLabelRect(c[0], c[1], t);
|
|
48654
|
+
return !placedRegionRects.some((p) => rectsOverlap(rect, p)) && !poiObstacles.some((o) => rectsOverlap(rect, o));
|
|
48655
|
+
});
|
|
48656
|
+
if (text === void 0) continue;
|
|
48657
|
+
placedRegionRects.push(regionLabelRect(c[0], c[1], text));
|
|
47450
48658
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47451
48659
|
}
|
|
47452
48660
|
for (const seed of insetLabelSeeds) {
|
|
47453
|
-
const text =
|
|
48661
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47454
48662
|
const src = regionById.get(seed.iso);
|
|
47455
48663
|
pushRegionLabel(
|
|
47456
48664
|
seed.x,
|
|
@@ -47461,22 +48669,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47461
48669
|
);
|
|
47462
48670
|
}
|
|
47463
48671
|
}
|
|
47464
|
-
|
|
47465
|
-
|
|
47466
|
-
const ordered = [...pois].sort(
|
|
47467
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47468
|
-
);
|
|
48672
|
+
if (resolved.directives.noPoiLabels !== true) {
|
|
48673
|
+
const ordered = [...pois].filter((p) => p.clusterId === void 0).sort((a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1));
|
|
47469
48674
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47470
48675
|
const labelText = (p) => {
|
|
47471
48676
|
const src = poiById.get(p.id);
|
|
47472
48677
|
return src?.label ?? src?.name ?? p.id;
|
|
47473
48678
|
};
|
|
47474
|
-
const poiLabH =
|
|
48679
|
+
const poiLabH = FONT2 * 1.25;
|
|
47475
48680
|
const labelInfo = (p) => {
|
|
47476
48681
|
const text = labelText(p);
|
|
47477
|
-
return { text, w: measureLegendText(text,
|
|
48682
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47478
48683
|
};
|
|
47479
48684
|
const GAP = 3;
|
|
48685
|
+
const clusterMembersById = /* @__PURE__ */ new Map();
|
|
48686
|
+
for (const p of pois) {
|
|
48687
|
+
if (p.clusterId === void 0) continue;
|
|
48688
|
+
const arr = clusterMembersById.get(p.clusterId);
|
|
48689
|
+
if (arr) arr.push(p);
|
|
48690
|
+
else clusterMembersById.set(p.clusterId, [p]);
|
|
48691
|
+
}
|
|
47480
48692
|
const inlineRect = (p, w, side) => {
|
|
47481
48693
|
switch (side) {
|
|
47482
48694
|
case "right":
|
|
@@ -47506,11 +48718,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47506
48718
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47507
48719
|
labels.push({
|
|
47508
48720
|
x,
|
|
47509
|
-
y: rect.y + poiLabH / 2 +
|
|
48721
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47510
48722
|
text,
|
|
47511
48723
|
anchor,
|
|
47512
48724
|
color: palette.text,
|
|
47513
|
-
halo:
|
|
48725
|
+
halo: false,
|
|
47514
48726
|
haloColor: palette.bg,
|
|
47515
48727
|
poiId: p.id,
|
|
47516
48728
|
lineNumber: p.lineNumber
|
|
@@ -47521,43 +48733,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47521
48733
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47522
48734
|
};
|
|
47523
48735
|
const GROUP_R = 30;
|
|
47524
|
-
const
|
|
48736
|
+
const groups2 = [];
|
|
47525
48737
|
for (const p of ordered) {
|
|
47526
|
-
const near =
|
|
48738
|
+
const near = groups2.find(
|
|
47527
48739
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47528
48740
|
);
|
|
47529
48741
|
if (near) near.push(p);
|
|
47530
|
-
else
|
|
48742
|
+
else groups2.push([p]);
|
|
47531
48743
|
}
|
|
47532
48744
|
const ROW_GAP2 = 3;
|
|
47533
48745
|
const step = poiLabH + ROW_GAP2;
|
|
47534
48746
|
const COL_GAP = 16;
|
|
47535
|
-
const
|
|
47536
|
-
|
|
48747
|
+
const makeItems = (group) => group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
48748
|
+
const columnRows = (items, side) => {
|
|
47537
48749
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47538
48750
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47539
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47540
48751
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47541
|
-
const
|
|
47542
|
-
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
48752
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
48753
|
+
const colX = side === "right" ? Math.min(right + COL_GAP, width - 2 - maxW) : Math.max(left - COL_GAP, 2 + maxW);
|
|
47543
48754
|
const totalH = items.length * step;
|
|
47544
48755
|
let startY = cyMid - totalH / 2;
|
|
47545
48756
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47546
|
-
items.
|
|
48757
|
+
return items.map((o, i) => {
|
|
47547
48758
|
const rowCy = startY + i * step + step / 2;
|
|
47548
|
-
|
|
47549
|
-
|
|
47550
|
-
|
|
47551
|
-
|
|
47552
|
-
|
|
47553
|
-
|
|
48759
|
+
return {
|
|
48760
|
+
o,
|
|
48761
|
+
colX,
|
|
48762
|
+
rowCy,
|
|
48763
|
+
rect: {
|
|
48764
|
+
x: side === "right" ? colX : colX - o.w,
|
|
48765
|
+
y: rowCy - poiLabH / 2,
|
|
48766
|
+
w: o.w,
|
|
48767
|
+
h: poiLabH
|
|
48768
|
+
}
|
|
48769
|
+
};
|
|
48770
|
+
});
|
|
48771
|
+
};
|
|
48772
|
+
const wouldColumnBeClean = (items, side) => columnRows(items, side).every(
|
|
48773
|
+
({ rect }) => rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect)
|
|
48774
|
+
);
|
|
48775
|
+
const defaultColumnSide = (items) => {
|
|
48776
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48777
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
48778
|
+
return right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
48779
|
+
};
|
|
48780
|
+
const commitColumn = (items, side, clusterId) => {
|
|
48781
|
+
for (const { o, colX, rowCy, rect } of columnRows(items, side)) {
|
|
48782
|
+
obstacles.push(rect);
|
|
47554
48783
|
labels.push({
|
|
47555
48784
|
x: colX,
|
|
47556
|
-
y: rowCy +
|
|
48785
|
+
y: rowCy + FONT2 / 3,
|
|
47557
48786
|
text: o.text,
|
|
47558
48787
|
anchor: side === "right" ? "start" : "end",
|
|
47559
48788
|
color: palette.text,
|
|
47560
|
-
halo:
|
|
48789
|
+
halo: false,
|
|
47561
48790
|
haloColor: palette.bg,
|
|
47562
48791
|
leader: {
|
|
47563
48792
|
x1: o.p.cx,
|
|
@@ -47567,24 +48796,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47567
48796
|
},
|
|
47568
48797
|
leaderColor: o.p.fill,
|
|
47569
48798
|
poiId: o.p.id,
|
|
47570
|
-
lineNumber: o.p.lineNumber
|
|
48799
|
+
lineNumber: o.p.lineNumber,
|
|
48800
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47571
48801
|
});
|
|
48802
|
+
}
|
|
48803
|
+
};
|
|
48804
|
+
const pushHidden = (p) => {
|
|
48805
|
+
const { text, w } = labelInfo(p);
|
|
48806
|
+
let x = p.cx + p.r + GAP;
|
|
48807
|
+
let anchor = "start";
|
|
48808
|
+
if (x + w > width) {
|
|
48809
|
+
x = p.cx - p.r - GAP - w;
|
|
48810
|
+
anchor = "end";
|
|
48811
|
+
}
|
|
48812
|
+
const y = Math.max(0, Math.min(p.cy - poiLabH / 2, height - poiLabH));
|
|
48813
|
+
labels.push({
|
|
48814
|
+
x: anchor === "start" ? x : x + w,
|
|
48815
|
+
y: y + poiLabH / 2 + FONT2 / 3,
|
|
48816
|
+
text,
|
|
48817
|
+
anchor,
|
|
48818
|
+
color: palette.text,
|
|
48819
|
+
halo: false,
|
|
48820
|
+
haloColor: palette.bg,
|
|
48821
|
+
poiId: p.id,
|
|
48822
|
+
hidden: true,
|
|
48823
|
+
lineNumber: p.lineNumber
|
|
47572
48824
|
});
|
|
47573
48825
|
};
|
|
47574
|
-
for (const
|
|
48826
|
+
for (const [clusterId, members] of clusterMembersById) {
|
|
48827
|
+
if (members.length === 0) continue;
|
|
48828
|
+
const items = makeItems(members);
|
|
48829
|
+
const side = wouldColumnBeClean(items, "right") ? "right" : wouldColumnBeClean(items, "left") ? "left" : defaultColumnSide(items);
|
|
48830
|
+
commitColumn(items, side, clusterId);
|
|
48831
|
+
}
|
|
48832
|
+
const maxExtent = MAX_CLUSTER_EXTENT_FACTOR * Math.min(width, height);
|
|
48833
|
+
const clusterPending = [];
|
|
48834
|
+
for (const g of groups2) {
|
|
48835
|
+
const items = makeItems(g);
|
|
47575
48836
|
if (g.length === 1) {
|
|
47576
|
-
const p =
|
|
47577
|
-
const { text, w } = labelInfo(p);
|
|
48837
|
+
const { p, text, w } = items[0];
|
|
47578
48838
|
const side = ["right", "left", "above", "below"].find(
|
|
47579
48839
|
(s) => inlineFits(p, w, s)
|
|
47580
48840
|
);
|
|
47581
|
-
if (side)
|
|
47582
|
-
|
|
47583
|
-
|
|
48841
|
+
if (side) pushInline(p, text, w, side);
|
|
48842
|
+
else commitColumn(items, defaultColumnSide(items));
|
|
48843
|
+
continue;
|
|
48844
|
+
}
|
|
48845
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
48846
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48847
|
+
const minCy = Math.min(...items.map((o) => o.p.cy));
|
|
48848
|
+
const maxCy = Math.max(...items.map((o) => o.p.cy));
|
|
48849
|
+
const diag = Math.hypot(right - left, maxCy - minCy);
|
|
48850
|
+
if (diag > maxExtent || items.length > MAX_COLUMN_ROWS) {
|
|
48851
|
+
items.forEach((o) => pushHidden(o.p));
|
|
48852
|
+
} else {
|
|
48853
|
+
clusterPending.push(items);
|
|
48854
|
+
}
|
|
48855
|
+
}
|
|
48856
|
+
for (const items of clusterPending) {
|
|
48857
|
+
const side = ["right", "left"].find(
|
|
48858
|
+
(s) => wouldColumnBeClean(items, s)
|
|
48859
|
+
);
|
|
48860
|
+
if (side) commitColumn(items, side);
|
|
48861
|
+
else items.forEach((o) => pushHidden(o.p));
|
|
48862
|
+
}
|
|
48863
|
+
}
|
|
48864
|
+
if (resolved.directives.noContextLabels !== true) {
|
|
48865
|
+
for (const l of labels) {
|
|
48866
|
+
if (l.hidden) continue;
|
|
48867
|
+
const w = labelW(l.text);
|
|
48868
|
+
const x = l.anchor === "start" ? l.x : l.anchor === "end" ? l.x - w : l.x - w / 2;
|
|
48869
|
+
obstacles.push({ x, y: l.y - labelH / 2, w, h: labelH });
|
|
48870
|
+
}
|
|
48871
|
+
for (const box of insets)
|
|
48872
|
+
obstacles.push({ x: box.x, y: box.y, w: box.w, h: box.h });
|
|
48873
|
+
const countryCandidates = [];
|
|
48874
|
+
for (const f of worldLayer.values()) {
|
|
48875
|
+
const iso = typeof f.id === "string" ? f.id : String(f.id ?? "");
|
|
48876
|
+
if (!iso || regionById.has(iso)) continue;
|
|
48877
|
+
let hasReferencedSub = false;
|
|
48878
|
+
for (const k of regionById.keys())
|
|
48879
|
+
if (k.startsWith(iso + "-")) {
|
|
48880
|
+
hasReferencedSub = true;
|
|
48881
|
+
break;
|
|
47584
48882
|
}
|
|
48883
|
+
if (hasReferencedSub) continue;
|
|
48884
|
+
const b = path.bounds(f);
|
|
48885
|
+
const [x0, y0] = b[0];
|
|
48886
|
+
const [x1, y1] = b[1];
|
|
48887
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48888
|
+
const anchorLngLat = WORLD_LABEL_ANCHORS[iso];
|
|
48889
|
+
const a = anchorLngLat ? project(anchorLngLat[0], anchorLngLat[1]) : path.centroid(f);
|
|
48890
|
+
countryCandidates.push({
|
|
48891
|
+
name: f.properties?.name ?? iso,
|
|
48892
|
+
bbox: [x0, y0, x1, y1],
|
|
48893
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48894
|
+
});
|
|
48895
|
+
}
|
|
48896
|
+
const framedStateContainers = (resolved.poiFrameContainers ?? []).some(
|
|
48897
|
+
(id) => id.startsWith("US-")
|
|
48898
|
+
);
|
|
48899
|
+
if (usLayer && framedStateContainers) {
|
|
48900
|
+
const containerSet = new Set(resolved.poiFrameContainers);
|
|
48901
|
+
for (const [iso, f] of usLayer) {
|
|
48902
|
+
if (containerSet.has(iso) || regionById.has(iso)) continue;
|
|
48903
|
+
const viewF = cullFeatureToView(f);
|
|
48904
|
+
if (!viewF) continue;
|
|
48905
|
+
const b = path.bounds(viewF);
|
|
48906
|
+
const [x0, y0] = b[0];
|
|
48907
|
+
const [x1, y1] = b[1];
|
|
48908
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48909
|
+
const a = path.centroid(viewF);
|
|
48910
|
+
countryCandidates.push({
|
|
48911
|
+
name: f.properties?.name ?? iso,
|
|
48912
|
+
bbox: [x0, y0, x1, y1],
|
|
48913
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48914
|
+
});
|
|
47585
48915
|
}
|
|
47586
|
-
placeColumn(g);
|
|
47587
48916
|
}
|
|
48917
|
+
const contextLabels = placeContextLabels({
|
|
48918
|
+
projection: resolved.projection,
|
|
48919
|
+
dLonSpan,
|
|
48920
|
+
dLatSpan,
|
|
48921
|
+
width,
|
|
48922
|
+
height,
|
|
48923
|
+
waterBodies: data.waterBodies,
|
|
48924
|
+
countries: countryCandidates,
|
|
48925
|
+
palette,
|
|
48926
|
+
project,
|
|
48927
|
+
collides,
|
|
48928
|
+
// Water labels must stay over open water — `fillAt` returns the ocean
|
|
48929
|
+
// backdrop colour off-land and a region fill on-land (lakes/states count
|
|
48930
|
+
// as land here, which is the safe side for an ocean name).
|
|
48931
|
+
overLand: (x, y) => fillAt(x, y) !== water
|
|
48932
|
+
});
|
|
48933
|
+
labels.push(...contextLabels);
|
|
47588
48934
|
}
|
|
47589
48935
|
let legend = null;
|
|
47590
48936
|
if (!resolved.directives.noLegend) {
|
|
@@ -47621,58 +48967,102 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47621
48967
|
rivers,
|
|
47622
48968
|
relief,
|
|
47623
48969
|
reliefHatch,
|
|
48970
|
+
coastlineStyle,
|
|
47624
48971
|
legs,
|
|
47625
48972
|
pois,
|
|
48973
|
+
clusters,
|
|
47626
48974
|
labels,
|
|
47627
48975
|
legend,
|
|
47628
48976
|
insets,
|
|
47629
48977
|
insetRegions,
|
|
47630
48978
|
projection,
|
|
47631
|
-
stretch: stretchParams
|
|
48979
|
+
stretch: stretchParams,
|
|
48980
|
+
diagnostics: []
|
|
47632
48981
|
};
|
|
47633
48982
|
}
|
|
47634
|
-
var FIT_PAD,
|
|
48983
|
+
var FIT_PAD, RAMP_FLOOR2, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT2, WORLD_LABEL_ANCHORS, 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;
|
|
47635
48984
|
var init_layout15 = __esm({
|
|
47636
48985
|
"src/map/layout.ts"() {
|
|
47637
48986
|
"use strict";
|
|
47638
48987
|
init_color_utils();
|
|
48988
|
+
init_geo();
|
|
48989
|
+
init_colorize();
|
|
47639
48990
|
init_colors();
|
|
47640
48991
|
init_label_layout();
|
|
47641
48992
|
init_legend_constants();
|
|
47642
48993
|
init_title_constants();
|
|
48994
|
+
init_context_labels();
|
|
47643
48995
|
FIT_PAD = 24;
|
|
47644
|
-
|
|
48996
|
+
RAMP_FLOOR2 = 15;
|
|
47645
48997
|
R_DEFAULT = 6;
|
|
47646
48998
|
R_MIN = 4;
|
|
47647
48999
|
R_MAX = 22;
|
|
47648
49000
|
W_MIN = 1.25;
|
|
47649
49001
|
W_MAX = 8;
|
|
47650
|
-
|
|
47651
|
-
|
|
49002
|
+
FONT2 = 11;
|
|
49003
|
+
WORLD_LABEL_ANCHORS = {
|
|
49004
|
+
US: [-98.5, 39.5]
|
|
49005
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
49006
|
+
};
|
|
49007
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
49008
|
+
MAX_COLUMN_ROWS = 7;
|
|
49009
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
47652
49010
|
LAND_TINT_LIGHT = 12;
|
|
47653
49011
|
LAND_TINT_DARK = 24;
|
|
47654
49012
|
TAG_TINT_LIGHT = 60;
|
|
47655
49013
|
TAG_TINT_DARK = 68;
|
|
47656
|
-
WATER_TINT_LIGHT =
|
|
47657
|
-
WATER_TINT_DARK =
|
|
49014
|
+
WATER_TINT_LIGHT = 24;
|
|
49015
|
+
WATER_TINT_DARK = 24;
|
|
47658
49016
|
RIVER_WIDTH = 1.3;
|
|
49017
|
+
COMPACT_WIDTH_PX = 480;
|
|
47659
49018
|
RELIEF_MIN_AREA = 12;
|
|
47660
49019
|
RELIEF_MIN_DIM = 2;
|
|
47661
|
-
RELIEF_HATCH_SPACING =
|
|
47662
|
-
RELIEF_HATCH_WIDTH = 0.
|
|
47663
|
-
RELIEF_HATCH_STRENGTH =
|
|
49020
|
+
RELIEF_HATCH_SPACING = 1.5;
|
|
49021
|
+
RELIEF_HATCH_WIDTH = 0.2;
|
|
49022
|
+
RELIEF_HATCH_STRENGTH = 26;
|
|
49023
|
+
COASTLINE_RING_COUNT = 5;
|
|
49024
|
+
COASTLINE_D0 = 16e-4;
|
|
49025
|
+
COASTLINE_STEP = 28e-4;
|
|
49026
|
+
COASTLINE_THICKNESS = 14e-4;
|
|
49027
|
+
COASTLINE_OPACITY_NEAR = 0.5;
|
|
49028
|
+
COASTLINE_OPACITY_FAR = 0.1;
|
|
49029
|
+
COASTLINE_MIN_EXTENT = 6e-4;
|
|
49030
|
+
COASTLINE_MIN_EXTENT_GLOBAL = 6e-4;
|
|
49031
|
+
COASTLINE_STROKE_MIX = 32;
|
|
47664
49032
|
FOREIGN_TINT_LIGHT = 30;
|
|
47665
49033
|
FOREIGN_TINT_DARK = 62;
|
|
47666
49034
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47667
49035
|
MUTED_FOREIGN_DARK = 16;
|
|
47668
49036
|
COLO_R = 9;
|
|
47669
49037
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
49038
|
+
STACK_OVERLAP = 1;
|
|
49039
|
+
STACK_RING_MAX = 8;
|
|
49040
|
+
STACK_RING_GAP = 4;
|
|
47670
49041
|
FAN_STEP = 16;
|
|
47671
49042
|
ARC_CURVE_FRAC = 0.18;
|
|
49043
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47672
49044
|
usConusProjection = () => geoConicEqualArea().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47673
49045
|
alaskaProjection = () => geoConicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47674
49046
|
hawaiiProjection = () => geoMercator();
|
|
47675
49047
|
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
49048
|
+
inAlaska = (lon, lat) => lat >= 51 && (lon <= -129 || lon >= 172);
|
|
49049
|
+
inHawaii = (lon, lat) => lat >= 18 && lat <= 23 && lon >= -161 && lon <= -154;
|
|
49050
|
+
FOREIGN_BORDER = {
|
|
49051
|
+
CA: [
|
|
49052
|
+
"US-AK",
|
|
49053
|
+
"US-WA",
|
|
49054
|
+
"US-ID",
|
|
49055
|
+
"US-MT",
|
|
49056
|
+
"US-ND",
|
|
49057
|
+
"US-MN",
|
|
49058
|
+
"US-MI",
|
|
49059
|
+
"US-NY",
|
|
49060
|
+
"US-VT",
|
|
49061
|
+
"US-NH",
|
|
49062
|
+
"US-ME"
|
|
49063
|
+
],
|
|
49064
|
+
MX: ["US-CA", "US-AZ", "US-NM", "US-TX"]
|
|
49065
|
+
};
|
|
47676
49066
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47677
49067
|
"US-AK",
|
|
47678
49068
|
"US-HI",
|
|
@@ -47692,6 +49082,98 @@ __export(renderer_exports16, {
|
|
|
47692
49082
|
renderMapForExport: () => renderMapForExport
|
|
47693
49083
|
});
|
|
47694
49084
|
import * as d3Selection18 from "d3-selection";
|
|
49085
|
+
function pointInRing2(px, py, ring) {
|
|
49086
|
+
let inside = false;
|
|
49087
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
49088
|
+
const [xi, yi] = ring[i];
|
|
49089
|
+
const [xj, yj] = ring[j];
|
|
49090
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
49091
|
+
inside = !inside;
|
|
49092
|
+
}
|
|
49093
|
+
return inside;
|
|
49094
|
+
}
|
|
49095
|
+
function ringToPath(ring) {
|
|
49096
|
+
let d = "";
|
|
49097
|
+
for (let i = 0; i < ring.length; i++)
|
|
49098
|
+
d += (i ? "L" : "M") + ring[i][0] + "," + ring[i][1];
|
|
49099
|
+
return d + "Z";
|
|
49100
|
+
}
|
|
49101
|
+
function polylineToPath(pts) {
|
|
49102
|
+
let d = "";
|
|
49103
|
+
for (let i = 0; i < pts.length; i++)
|
|
49104
|
+
d += (i ? "L" : "M") + pts[i][0] + "," + pts[i][1];
|
|
49105
|
+
return d;
|
|
49106
|
+
}
|
|
49107
|
+
function ringToCoastPaths(ring, frame) {
|
|
49108
|
+
if (!frame) return [ringToPath(ring)];
|
|
49109
|
+
const n = ring.length;
|
|
49110
|
+
const eps = 0.75;
|
|
49111
|
+
const onL = (x) => Math.abs(x) <= eps;
|
|
49112
|
+
const onR = (x) => Math.abs(x - frame.w) <= eps;
|
|
49113
|
+
const onT = (y) => Math.abs(y) <= eps;
|
|
49114
|
+
const onB = (y) => Math.abs(y - frame.h) <= eps;
|
|
49115
|
+
const isFrameEdge = (a, b) => onL(a[0]) && onL(b[0]) || onR(a[0]) && onR(b[0]) || onT(a[1]) && onT(b[1]) || onB(a[1]) && onB(b[1]);
|
|
49116
|
+
let firstBreak = -1;
|
|
49117
|
+
for (let i = 0; i < n; i++)
|
|
49118
|
+
if (isFrameEdge(ring[i], ring[(i + 1) % n])) {
|
|
49119
|
+
firstBreak = i;
|
|
49120
|
+
break;
|
|
49121
|
+
}
|
|
49122
|
+
if (firstBreak === -1) return [ringToPath(ring)];
|
|
49123
|
+
const paths = [];
|
|
49124
|
+
let cur = [];
|
|
49125
|
+
const start = (firstBreak + 1) % n;
|
|
49126
|
+
for (let k = 0; k < n; k++) {
|
|
49127
|
+
const i = (start + k) % n;
|
|
49128
|
+
const a = ring[i];
|
|
49129
|
+
const b = ring[(i + 1) % n];
|
|
49130
|
+
if (isFrameEdge(a, b)) {
|
|
49131
|
+
if (cur.length >= 2) paths.push(polylineToPath(cur));
|
|
49132
|
+
cur = [];
|
|
49133
|
+
continue;
|
|
49134
|
+
}
|
|
49135
|
+
if (cur.length === 0) cur.push(a);
|
|
49136
|
+
cur.push(b);
|
|
49137
|
+
}
|
|
49138
|
+
if (cur.length >= 2) paths.push(polylineToPath(cur));
|
|
49139
|
+
return paths;
|
|
49140
|
+
}
|
|
49141
|
+
function coastlineOuterRings(regions, minExtent, frame) {
|
|
49142
|
+
const paths = [];
|
|
49143
|
+
for (const r of regions) {
|
|
49144
|
+
const rings = parsePathRings(r.d);
|
|
49145
|
+
for (let i = 0; i < rings.length; i++) {
|
|
49146
|
+
const ring = rings[i];
|
|
49147
|
+
if (ring.length < 3) continue;
|
|
49148
|
+
let minX = Infinity;
|
|
49149
|
+
let minY = Infinity;
|
|
49150
|
+
let maxX = -Infinity;
|
|
49151
|
+
let maxY = -Infinity;
|
|
49152
|
+
for (const [x, y] of ring) {
|
|
49153
|
+
if (x < minX) minX = x;
|
|
49154
|
+
if (x > maxX) maxX = x;
|
|
49155
|
+
if (y < minY) minY = y;
|
|
49156
|
+
if (y > maxY) maxY = y;
|
|
49157
|
+
}
|
|
49158
|
+
if (Math.max(maxX - minX, maxY - minY) < minExtent) continue;
|
|
49159
|
+
const [fx, fy] = ring[0];
|
|
49160
|
+
let depth = 0;
|
|
49161
|
+
for (let j = 0; j < rings.length; j++)
|
|
49162
|
+
if (j !== i && pointInRing2(fx, fy, rings[j])) depth++;
|
|
49163
|
+
if (depth % 2 === 1) continue;
|
|
49164
|
+
paths.push(...ringToCoastPaths(ring, frame));
|
|
49165
|
+
}
|
|
49166
|
+
}
|
|
49167
|
+
return paths;
|
|
49168
|
+
}
|
|
49169
|
+
function appendWaterLines(g, outerRings, style, flatWater) {
|
|
49170
|
+
const d = outerRings.join(" ");
|
|
49171
|
+
const linesOuterFirst = [...style.lines].sort((a, b) => b.d - a.d);
|
|
49172
|
+
for (const line12 of linesOuterFirst) {
|
|
49173
|
+
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");
|
|
49174
|
+
g.append("path").attr("d", d).attr("stroke", flatWater).attr("stroke-width", 2 * line12.d).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
49175
|
+
}
|
|
49176
|
+
}
|
|
47695
49177
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47696
49178
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47697
49179
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47704,6 +49186,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47704
49186
|
{
|
|
47705
49187
|
palette,
|
|
47706
49188
|
isDark,
|
|
49189
|
+
// Export-only: forward the contain-fit request from mapExportDimensions so a
|
|
49190
|
+
// clamped/floored (off-aspect) export canvas letterboxes instead of
|
|
49191
|
+
// stretch-distorting. The in-app preview pane passes no exportDims → unset →
|
|
49192
|
+
// keeps the global stretch-fill.
|
|
49193
|
+
preferContain: exportDims?.preferContain ?? false,
|
|
47707
49194
|
...activeGroupOverride !== void 0 && {
|
|
47708
49195
|
activeGroup: activeGroupOverride
|
|
47709
49196
|
}
|
|
@@ -47717,6 +49204,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47717
49204
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47718
49205
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47719
49206
|
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
49207
|
+
if (r.label) p.attr("data-region-name", r.label);
|
|
49208
|
+
if (r.id && r.id !== "lake") p.attr("data-iso", r.id);
|
|
49209
|
+
if (r.labelX !== void 0 && r.labelY !== void 0) {
|
|
49210
|
+
p.attr("data-label-x", r.labelX).attr("data-label-y", r.labelY);
|
|
49211
|
+
}
|
|
47720
49212
|
if (r.layer !== "base") {
|
|
47721
49213
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47722
49214
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47746,28 +49238,112 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47746
49238
|
const landClip = defs.append("clipPath").attr("id", landClipId);
|
|
47747
49239
|
for (const r of layout.regions)
|
|
47748
49240
|
if (r.id !== "lake") landClip.append("path").attr("d", r.d);
|
|
47749
|
-
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");
|
|
49241
|
+
const gRelief = svg.append("g").attr("clip-path", `url(#${landClipId})`).style("pointer-events", "none").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");
|
|
47750
49242
|
for (let y = h.spacing; y < height; y += h.spacing) {
|
|
47751
49243
|
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
47752
49244
|
}
|
|
47753
49245
|
}
|
|
49246
|
+
if (layout.coastlineStyle) {
|
|
49247
|
+
const cs = layout.coastlineStyle;
|
|
49248
|
+
const maskId = "dgmo-map-water-mask";
|
|
49249
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
49250
|
+
mask.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "white");
|
|
49251
|
+
const landD = layout.regions.filter((r) => r.id !== "lake").map((r) => r.d).join(" ");
|
|
49252
|
+
const lakeD = layout.regions.filter((r) => r.id === "lake").map((r) => r.d).join(" ");
|
|
49253
|
+
if (landD) mask.append("path").attr("d", landD).attr("fill", "black");
|
|
49254
|
+
if (lakeD) mask.append("path").attr("d", lakeD).attr("fill", "white");
|
|
49255
|
+
if (layout.insets.length) {
|
|
49256
|
+
const reach = Math.max(0, ...cs.lines.map((l) => l.d + l.thickness));
|
|
49257
|
+
for (const box of layout.insets) {
|
|
49258
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
49259
|
+
mask.append("path").attr("d", d).attr("fill", "black").attr("stroke", "black").attr("stroke-width", 2 * reach).attr("stroke-linejoin", "round");
|
|
49260
|
+
}
|
|
49261
|
+
}
|
|
49262
|
+
const gWater = svg.append("g").attr("class", "dgmo-map-water-lines").attr("fill", "none").style("pointer-events", "none").attr("mask", `url(#${maskId})`);
|
|
49263
|
+
appendWaterLines(
|
|
49264
|
+
gWater,
|
|
49265
|
+
// Pass the canvas frame so edges collinear with it (the antimeridian on a
|
|
49266
|
+
// world map, regional clipExtent cuts) don't get ringed as fake coast —
|
|
49267
|
+
// land runs cleanly to the render-area edge.
|
|
49268
|
+
coastlineOuterRings(layout.regions, cs.minExtent, {
|
|
49269
|
+
w: width,
|
|
49270
|
+
h: height
|
|
49271
|
+
}),
|
|
49272
|
+
cs,
|
|
49273
|
+
layout.background
|
|
49274
|
+
);
|
|
49275
|
+
const byStroke = /* @__PURE__ */ new Map();
|
|
49276
|
+
for (const r of layout.regions) {
|
|
49277
|
+
const arr = byStroke.get(r.stroke);
|
|
49278
|
+
if (arr) arr.push(r.d);
|
|
49279
|
+
else byStroke.set(r.stroke, [r.d]);
|
|
49280
|
+
}
|
|
49281
|
+
for (const [stroke2, ds] of byStroke)
|
|
49282
|
+
gWater.append("path").attr("d", ds.join(" ")).attr("stroke", stroke2).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
49283
|
+
}
|
|
47754
49284
|
if (layout.rivers.length) {
|
|
47755
|
-
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
49285
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none").style("pointer-events", "none");
|
|
47756
49286
|
for (const r of layout.rivers) {
|
|
47757
49287
|
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
47758
49288
|
}
|
|
47759
49289
|
}
|
|
47760
49290
|
if (layout.insets.length) {
|
|
47761
49291
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47762
|
-
|
|
49292
|
+
layout.insets.forEach((box, bi) => {
|
|
47763
49293
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47764
49294
|
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");
|
|
47765
|
-
|
|
49295
|
+
if (box.contextLand) {
|
|
49296
|
+
const clipId = `dgmo-map-inset-clip-${bi}`;
|
|
49297
|
+
defs.append("clipPath").attr("id", clipId).append("path").attr("d", d);
|
|
49298
|
+
insetG.append("path").attr("d", box.contextLand.d).attr("fill", box.contextLand.fill).attr("clip-path", `url(#${clipId})`);
|
|
49299
|
+
}
|
|
49300
|
+
});
|
|
47766
49301
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47767
|
-
|
|
49302
|
+
if (layout.coastlineStyle) {
|
|
49303
|
+
const cs = layout.coastlineStyle;
|
|
49304
|
+
const maskId = "dgmo-map-inset-water-mask";
|
|
49305
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
49306
|
+
for (const box of layout.insets) {
|
|
49307
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
49308
|
+
mask.append("path").attr("d", d).attr("fill", "white");
|
|
49309
|
+
}
|
|
49310
|
+
layout.insets.forEach((box, bi) => {
|
|
49311
|
+
if (box.contextLand)
|
|
49312
|
+
mask.append("path").attr("d", box.contextLand.d).attr("fill", "black").attr("clip-path", `url(#dgmo-map-inset-clip-${bi})`);
|
|
49313
|
+
});
|
|
49314
|
+
for (const r of layout.insetRegions)
|
|
49315
|
+
if (r.id !== "lake")
|
|
49316
|
+
mask.append("path").attr("d", r.d).attr("fill", "black");
|
|
49317
|
+
for (const r of layout.insetRegions)
|
|
49318
|
+
if (r.id === "lake")
|
|
49319
|
+
mask.append("path").attr("d", r.d).attr("fill", "white");
|
|
49320
|
+
const clipId = "dgmo-map-inset-water-clip";
|
|
49321
|
+
const clip = defs.append("clipPath").attr("id", clipId);
|
|
49322
|
+
for (const box of layout.insets) {
|
|
49323
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
49324
|
+
clip.append("path").attr("d", d);
|
|
49325
|
+
}
|
|
49326
|
+
const gInsetWater = insetG.append("g").attr("clip-path", `url(#${clipId})`).append("g").attr("class", "dgmo-map-inset-water-lines").attr("fill", "none").style("pointer-events", "none").attr("mask", `url(#${maskId})`);
|
|
49327
|
+
appendWaterLines(
|
|
49328
|
+
gInsetWater,
|
|
49329
|
+
coastlineOuterRings(layout.insetRegions, cs.minExtent),
|
|
49330
|
+
cs,
|
|
49331
|
+
layout.background
|
|
49332
|
+
);
|
|
49333
|
+
for (const r of layout.insetRegions)
|
|
49334
|
+
gInsetWater.append("path").attr("d", r.d).attr("stroke", r.stroke).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
49335
|
+
}
|
|
49336
|
+
}
|
|
49337
|
+
const wireSync = (sel, lineNumber) => {
|
|
49338
|
+
if (lineNumber < 1) return;
|
|
49339
|
+
sel.attr("data-line-number", lineNumber);
|
|
49340
|
+
if (onClickItem)
|
|
49341
|
+
sel.style("cursor", "pointer").on("click", () => onClickItem(lineNumber));
|
|
49342
|
+
};
|
|
47768
49343
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47769
49344
|
layout.legs.forEach((leg, i) => {
|
|
47770
49345
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
49346
|
+
wireSync(p, leg.lineNumber);
|
|
47771
49347
|
if (leg.arrow) {
|
|
47772
49348
|
const id = `dgmo-map-arrow-${i}`;
|
|
47773
49349
|
const s = arrowSize(leg.width);
|
|
@@ -47775,25 +49351,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47775
49351
|
p.attr("marker-end", `url(#${id})`);
|
|
47776
49352
|
}
|
|
47777
49353
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47778
|
-
emitText(
|
|
49354
|
+
const lt = emitText(
|
|
47779
49355
|
gLegs,
|
|
47780
49356
|
leg.labelX,
|
|
47781
49357
|
leg.labelY ?? 0,
|
|
47782
49358
|
leg.label,
|
|
47783
49359
|
"middle",
|
|
47784
|
-
palette.textMuted,
|
|
47785
|
-
haloColor,
|
|
47786
|
-
true,
|
|
49360
|
+
leg.labelColor ?? palette.textMuted,
|
|
49361
|
+
leg.labelHaloColor ?? haloColor,
|
|
49362
|
+
leg.labelHalo ?? true,
|
|
47787
49363
|
LABEL_FONT - 1
|
|
47788
49364
|
);
|
|
49365
|
+
wireSync(lt, leg.lineNumber);
|
|
47789
49366
|
}
|
|
47790
49367
|
});
|
|
49368
|
+
const gSpider = svg.append("g").attr("class", "dgmo-map-spider");
|
|
49369
|
+
for (const cl of layout.clusters) {
|
|
49370
|
+
if (!exportDims) {
|
|
49371
|
+
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");
|
|
49372
|
+
}
|
|
49373
|
+
for (const leg of cl.legs) {
|
|
49374
|
+
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");
|
|
49375
|
+
}
|
|
49376
|
+
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");
|
|
49377
|
+
}
|
|
47791
49378
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47792
49379
|
for (const poi of layout.pois) {
|
|
47793
49380
|
if (poi.isOrigin) {
|
|
47794
49381
|
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);
|
|
47795
49382
|
}
|
|
47796
49383
|
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);
|
|
49384
|
+
if (poi.clusterId !== void 0)
|
|
49385
|
+
c.attr("data-cluster-member", poi.clusterId);
|
|
47797
49386
|
if (poi.tags) {
|
|
47798
49387
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47799
49388
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47821,12 +49410,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47821
49410
|
}
|
|
47822
49411
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47823
49412
|
for (const lab of layout.labels) {
|
|
49413
|
+
if (lab.hidden) {
|
|
49414
|
+
if (exportDims) continue;
|
|
49415
|
+
emitText(
|
|
49416
|
+
gLabels,
|
|
49417
|
+
lab.x,
|
|
49418
|
+
lab.y,
|
|
49419
|
+
lab.text,
|
|
49420
|
+
lab.anchor,
|
|
49421
|
+
lab.color,
|
|
49422
|
+
lab.haloColor,
|
|
49423
|
+
lab.halo,
|
|
49424
|
+
LABEL_FONT,
|
|
49425
|
+
lab.italic,
|
|
49426
|
+
lab.letterSpacing
|
|
49427
|
+
).attr("data-poi", lab.poiId ?? null).attr("data-poi-hidden", "").style("opacity", 0).style("pointer-events", "none");
|
|
49428
|
+
continue;
|
|
49429
|
+
}
|
|
47824
49430
|
if (lab.leader) {
|
|
47825
49431
|
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(
|
|
47826
49432
|
"stroke",
|
|
47827
49433
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47828
49434
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47829
49435
|
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
49436
|
+
if (lab.clusterMember !== void 0)
|
|
49437
|
+
line12.attr("data-cluster-member", lab.clusterMember);
|
|
49438
|
+
wireSync(line12, lab.lineNumber);
|
|
47830
49439
|
}
|
|
47831
49440
|
const t = emitText(
|
|
47832
49441
|
gLabels,
|
|
@@ -47837,11 +49446,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47837
49446
|
lab.color,
|
|
47838
49447
|
lab.haloColor,
|
|
47839
49448
|
lab.halo,
|
|
47840
|
-
LABEL_FONT
|
|
49449
|
+
LABEL_FONT,
|
|
49450
|
+
lab.italic,
|
|
49451
|
+
lab.letterSpacing,
|
|
49452
|
+
lab.lines
|
|
47841
49453
|
);
|
|
47842
49454
|
if (lab.poiId !== void 0) {
|
|
47843
49455
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47844
49456
|
}
|
|
49457
|
+
if (lab.clusterMember !== void 0) {
|
|
49458
|
+
t.attr("data-cluster-member", lab.clusterMember);
|
|
49459
|
+
}
|
|
49460
|
+
wireSync(t, lab.lineNumber);
|
|
49461
|
+
}
|
|
49462
|
+
if (!exportDims && layout.clusters.length) {
|
|
49463
|
+
const gBadge = svg.append("g").attr("class", "dgmo-map-cluster-badges");
|
|
49464
|
+
for (const cl of layout.clusters) {
|
|
49465
|
+
const g = gBadge.append("g").attr("data-cluster", cl.id).style("opacity", 0).style("pointer-events", "none");
|
|
49466
|
+
const R = 9;
|
|
49467
|
+
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);
|
|
49468
|
+
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);
|
|
49469
|
+
emitText(
|
|
49470
|
+
g,
|
|
49471
|
+
cl.cx,
|
|
49472
|
+
cl.cy + 3,
|
|
49473
|
+
String(cl.count),
|
|
49474
|
+
"middle",
|
|
49475
|
+
palette.text,
|
|
49476
|
+
palette.bg,
|
|
49477
|
+
false,
|
|
49478
|
+
LABEL_FONT
|
|
49479
|
+
);
|
|
49480
|
+
}
|
|
47845
49481
|
}
|
|
47846
49482
|
if (layout.legend) {
|
|
47847
49483
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47878,7 +49514,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47878
49514
|
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);
|
|
47879
49515
|
}
|
|
47880
49516
|
if (layout.subtitle) {
|
|
47881
|
-
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);
|
|
49517
|
+
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);
|
|
47882
49518
|
}
|
|
47883
49519
|
if (layout.caption) {
|
|
47884
49520
|
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);
|
|
@@ -47887,10 +49523,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47887
49523
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47888
49524
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47889
49525
|
}
|
|
47890
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47891
|
-
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color)
|
|
49526
|
+
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize, italic, letterSpacing, lines) {
|
|
49527
|
+
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color);
|
|
49528
|
+
if (lines && lines.length > 1) {
|
|
49529
|
+
const lineHeight = fontSize + 2;
|
|
49530
|
+
const startDy = -((lines.length - 1) / 2) * lineHeight;
|
|
49531
|
+
lines.forEach((ln, i) => {
|
|
49532
|
+
t.append("tspan").attr("x", x).attr("dy", i === 0 ? startDy : lineHeight).text(ln);
|
|
49533
|
+
});
|
|
49534
|
+
} else {
|
|
49535
|
+
t.text(text);
|
|
49536
|
+
}
|
|
49537
|
+
if (italic) t.attr("font-style", "italic");
|
|
49538
|
+
if (letterSpacing) t.attr("letter-spacing", letterSpacing);
|
|
47892
49539
|
if (withHalo) {
|
|
47893
|
-
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width",
|
|
49540
|
+
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);
|
|
47894
49541
|
}
|
|
47895
49542
|
return t;
|
|
47896
49543
|
}
|
|
@@ -47907,6 +49554,56 @@ var init_renderer16 = __esm({
|
|
|
47907
49554
|
}
|
|
47908
49555
|
});
|
|
47909
49556
|
|
|
49557
|
+
// src/map/dimensions.ts
|
|
49558
|
+
var dimensions_exports = {};
|
|
49559
|
+
__export(dimensions_exports, {
|
|
49560
|
+
mapContentAspect: () => mapContentAspect,
|
|
49561
|
+
mapExportDimensions: () => mapExportDimensions
|
|
49562
|
+
});
|
|
49563
|
+
import { geoPath as geoPath2 } from "d3-geo";
|
|
49564
|
+
function mapContentAspect(resolved, data, ref = REF) {
|
|
49565
|
+
const { projection, fitTarget } = buildMapProjection(resolved, data);
|
|
49566
|
+
projection.fitSize([ref, ref], fitTarget);
|
|
49567
|
+
const b = geoPath2(projection).bounds(fitTarget);
|
|
49568
|
+
const w = b[1][0] - b[0][0];
|
|
49569
|
+
const h = b[1][1] - b[0][1];
|
|
49570
|
+
const aspect = w / h;
|
|
49571
|
+
return Number.isFinite(aspect) && aspect > 0 ? aspect : FALLBACK_ASPECT;
|
|
49572
|
+
}
|
|
49573
|
+
function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
49574
|
+
const raw = mapContentAspect(resolved, data);
|
|
49575
|
+
const clamped = Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
|
|
49576
|
+
const width = baseWidth;
|
|
49577
|
+
let height = Math.round(width / clamped);
|
|
49578
|
+
let chromeReserve = 0;
|
|
49579
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
49580
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
49581
|
+
chromeReserve += Math.max(FIT_PAD2, bannerBottom + TITLE_GAP) - FIT_PAD2;
|
|
49582
|
+
}
|
|
49583
|
+
let floored = false;
|
|
49584
|
+
if (height - chromeReserve < MIN_MAP_BAND) {
|
|
49585
|
+
height = Math.round(chromeReserve + MIN_MAP_BAND);
|
|
49586
|
+
floored = true;
|
|
49587
|
+
}
|
|
49588
|
+
const preferContain = clamped !== raw || floored;
|
|
49589
|
+
return { width, height, preferContain };
|
|
49590
|
+
}
|
|
49591
|
+
var FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
|
|
49592
|
+
var init_dimensions = __esm({
|
|
49593
|
+
"src/map/dimensions.ts"() {
|
|
49594
|
+
"use strict";
|
|
49595
|
+
init_title_constants();
|
|
49596
|
+
init_layout15();
|
|
49597
|
+
FIT_PAD2 = 24;
|
|
49598
|
+
TITLE_GAP = 16;
|
|
49599
|
+
ASPECT_MAX = 3;
|
|
49600
|
+
ASPECT_MIN = 0.9;
|
|
49601
|
+
MIN_MAP_BAND = 200;
|
|
49602
|
+
FALLBACK_ASPECT = 1.5;
|
|
49603
|
+
REF = 1e3;
|
|
49604
|
+
}
|
|
49605
|
+
});
|
|
49606
|
+
|
|
47910
49607
|
// src/map/load-data.ts
|
|
47911
49608
|
var load_data_exports = {};
|
|
47912
49609
|
__export(load_data_exports, {
|
|
@@ -47965,12 +49662,17 @@ function loadMapData() {
|
|
|
47965
49662
|
mountainRanges,
|
|
47966
49663
|
naLand,
|
|
47967
49664
|
naLakes,
|
|
49665
|
+
waterBodies,
|
|
47968
49666
|
gazetteer
|
|
47969
49667
|
] = await Promise.all([
|
|
49668
|
+
// worldCoarse (110m) is LOAD-BEARING but NOT a render source: the world
|
|
49669
|
+
// basemap renders from worldDetail (50m) at all scales (resolver pins
|
|
49670
|
+
// basemaps.world = 'detail'). Coarse stays as the authoritative region
|
|
49671
|
+
// name index + dominant-landmass bbox source in resolver.ts. Do not drop it.
|
|
47970
49672
|
readJson(nb, dir, FILES.worldCoarse),
|
|
47971
49673
|
readJson(nb, dir, FILES.worldDetail),
|
|
47972
49674
|
readJson(nb, dir, FILES.usStates),
|
|
47973
|
-
// Lakes/rivers/mountain/NA assets are optional — older bundles may predate them.
|
|
49675
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
47974
49676
|
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
47975
49677
|
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
47976
49678
|
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
@@ -47978,6 +49680,7 @@ function loadMapData() {
|
|
|
47978
49680
|
),
|
|
47979
49681
|
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
47980
49682
|
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49683
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
47981
49684
|
readJson(nb, dir, FILES.gazetteer)
|
|
47982
49685
|
]);
|
|
47983
49686
|
return validate({
|
|
@@ -47989,7 +49692,8 @@ function loadMapData() {
|
|
|
47989
49692
|
...rivers && { rivers },
|
|
47990
49693
|
...mountainRanges && { mountainRanges },
|
|
47991
49694
|
...naLand && { naLand },
|
|
47992
|
-
...naLakes && { naLakes }
|
|
49695
|
+
...naLakes && { naLakes },
|
|
49696
|
+
...waterBodies && { waterBodies }
|
|
47993
49697
|
});
|
|
47994
49698
|
})().catch((e) => {
|
|
47995
49699
|
cache = void 0;
|
|
@@ -48010,6 +49714,7 @@ var init_load_data = __esm({
|
|
|
48010
49714
|
mountainRanges: "mountain-ranges.json",
|
|
48011
49715
|
naLand: "na-land.json",
|
|
48012
49716
|
naLakes: "na-lakes.json",
|
|
49717
|
+
waterBodies: "water-bodies.json",
|
|
48013
49718
|
gazetteer: "gazetteer.json"
|
|
48014
49719
|
};
|
|
48015
49720
|
CANDIDATE_DIRS = [
|
|
@@ -50023,8 +51728,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
50023
51728
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
50024
51729
|
if (lines.length === 0) continue;
|
|
50025
51730
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
50026
|
-
const
|
|
50027
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51731
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51732
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
50028
51733
|
}
|
|
50029
51734
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
50030
51735
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52723,15 +54428,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52723
54428
|
textColor,
|
|
52724
54429
|
onClickItem
|
|
52725
54430
|
);
|
|
52726
|
-
const
|
|
52727
|
-
for (const node of nodes)
|
|
54431
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
54432
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52728
54433
|
for (const link of links) {
|
|
52729
|
-
|
|
52730
|
-
|
|
54434
|
+
neighbors2.get(link.source).add(link.target);
|
|
54435
|
+
neighbors2.get(link.target).add(link.source);
|
|
52731
54436
|
}
|
|
52732
54437
|
const FADE_OPACITY3 = 0.1;
|
|
52733
54438
|
function handleMouseEnter(hovered) {
|
|
52734
|
-
const connected =
|
|
54439
|
+
const connected = neighbors2.get(hovered);
|
|
52735
54440
|
g.selectAll(".arc-link").each(function() {
|
|
52736
54441
|
const el = d3Selection23.select(this);
|
|
52737
54442
|
const src = el.attr("data-source");
|
|
@@ -53639,10 +55344,12 @@ function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, se
|
|
|
53639
55344
|
const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
|
|
53640
55345
|
const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
|
|
53641
55346
|
const innerWidth = width - margin.left - margin.right;
|
|
53642
|
-
const
|
|
53643
|
-
const rowH = Math.min(ctx.structural(28),
|
|
55347
|
+
const availInnerHeight = height - margin.top - margin.bottom;
|
|
55348
|
+
const rowH = Math.min(ctx.structural(28), availInnerHeight / sorted.length);
|
|
55349
|
+
const innerHeight = rowH * sorted.length;
|
|
55350
|
+
const usedHeight = margin.top + innerHeight + margin.bottom;
|
|
53644
55351
|
const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
|
|
53645
|
-
const svg = d3Selection23.select(container).append("svg").attr("width", width).attr("height",
|
|
55352
|
+
const svg = d3Selection23.select(container).append("svg").attr("width", width).attr("height", usedHeight).attr("viewBox", `0 0 ${width} ${usedHeight}`).attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
|
|
53646
55353
|
if (ctx.isBelowFloor) {
|
|
53647
55354
|
svg.attr("width", "100%");
|
|
53648
55355
|
}
|
|
@@ -54722,7 +56429,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54722
56429
|
8,
|
|
54723
56430
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54724
56431
|
);
|
|
54725
|
-
function
|
|
56432
|
+
function wrapLabel3(text, maxChars) {
|
|
54726
56433
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54727
56434
|
const lines = [];
|
|
54728
56435
|
let cur = "";
|
|
@@ -54768,7 +56475,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54768
56475
|
if (!ov.label) continue;
|
|
54769
56476
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54770
56477
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54771
|
-
const lines =
|
|
56478
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54772
56479
|
wrappedOverlapLabels.set(ov, lines);
|
|
54773
56480
|
const dir = predictOverlapDirRaw(idxs);
|
|
54774
56481
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -56206,6 +57913,7 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
56206
57913
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
56207
57914
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
56208
57915
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57916
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
56209
57917
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
56210
57918
|
const mapParsed = parseMap2(content);
|
|
56211
57919
|
let mapData = options?.mapData;
|
|
@@ -56218,14 +57926,15 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
56218
57926
|
}
|
|
56219
57927
|
}
|
|
56220
57928
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
56221
|
-
const
|
|
57929
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57930
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
56222
57931
|
renderMapForExport2(
|
|
56223
57932
|
container2,
|
|
56224
57933
|
mapResolved,
|
|
56225
57934
|
mapData,
|
|
56226
57935
|
effectivePalette2,
|
|
56227
57936
|
theme === "dark",
|
|
56228
|
-
|
|
57937
|
+
dims2
|
|
56229
57938
|
);
|
|
56230
57939
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
56231
57940
|
}
|
|
@@ -57072,7 +58781,8 @@ async function render(content, options) {
|
|
|
57072
58781
|
...options?.c4Container !== void 0 && {
|
|
57073
58782
|
c4Container: options.c4Container
|
|
57074
58783
|
},
|
|
57075
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58784
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58785
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
57076
58786
|
});
|
|
57077
58787
|
if (chartType === "map") {
|
|
57078
58788
|
try {
|
|
@@ -57083,7 +58793,7 @@ async function render(content, options) {
|
|
|
57083
58793
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
57084
58794
|
]
|
|
57085
58795
|
);
|
|
57086
|
-
const data = await loadMapData2();
|
|
58796
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
57087
58797
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
57088
58798
|
} catch {
|
|
57089
58799
|
}
|
|
@@ -57322,8 +59032,8 @@ function detectCycles(parsed) {
|
|
|
57322
59032
|
const parent = /* @__PURE__ */ new Map();
|
|
57323
59033
|
function dfs(nodeId3) {
|
|
57324
59034
|
color.set(nodeId3, 1);
|
|
57325
|
-
const
|
|
57326
|
-
for (const next of
|
|
59035
|
+
const neighbors2 = adj.get(nodeId3) ?? [];
|
|
59036
|
+
for (const next of neighbors2) {
|
|
57327
59037
|
const c = color.get(next) ?? 0;
|
|
57328
59038
|
if (c === 1) {
|
|
57329
59039
|
const lineKey = `${nodeId3}->${next}`;
|
|
@@ -57508,6 +59218,7 @@ init_resolver2();
|
|
|
57508
59218
|
init_load_data();
|
|
57509
59219
|
init_layout15();
|
|
57510
59220
|
init_renderer16();
|
|
59221
|
+
init_dimensions();
|
|
57511
59222
|
|
|
57512
59223
|
// src/map/geo-query.ts
|
|
57513
59224
|
init_parser12();
|
|
@@ -57581,7 +59292,9 @@ function nearestCity(lonLat, gazetteer) {
|
|
|
57581
59292
|
name: c[4],
|
|
57582
59293
|
iso: c[2],
|
|
57583
59294
|
...c[5] !== void 0 && { sub: c[5] },
|
|
57584
|
-
distanceKm: best.dist
|
|
59295
|
+
distanceKm: best.dist,
|
|
59296
|
+
lat: c[0],
|
|
59297
|
+
lon: c[1]
|
|
57585
59298
|
};
|
|
57586
59299
|
}
|
|
57587
59300
|
function roundCoord(n) {
|
|
@@ -57660,7 +59373,7 @@ function createMapGeoQuery(opts) {
|
|
|
57660
59373
|
}
|
|
57661
59374
|
return out;
|
|
57662
59375
|
};
|
|
57663
|
-
return { invert, project, locate, cities };
|
|
59376
|
+
return { invert, project, locate, cities, diagnostics: layout.diagnostics };
|
|
57664
59377
|
}
|
|
57665
59378
|
|
|
57666
59379
|
// src/map/completion.ts
|
|
@@ -58386,9 +60099,12 @@ var GLOBAL_DIRECTIVES = {
|
|
|
58386
60099
|
"gruvbox",
|
|
58387
60100
|
"tokyo-night",
|
|
58388
60101
|
"one-dark",
|
|
58389
|
-
"bold",
|
|
58390
60102
|
"dracula",
|
|
58391
|
-
"monokai"
|
|
60103
|
+
"monokai",
|
|
60104
|
+
"atlas",
|
|
60105
|
+
"blueprint",
|
|
60106
|
+
"slate",
|
|
60107
|
+
"tidewater"
|
|
58392
60108
|
]
|
|
58393
60109
|
},
|
|
58394
60110
|
theme: {
|
|
@@ -58719,7 +60435,9 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
58719
60435
|
withGlobals({
|
|
58720
60436
|
direction: { description: "Layout direction", values: ["LR", "TB"] },
|
|
58721
60437
|
"active-tag": { description: "Active tag group name" },
|
|
58722
|
-
hide: { description: "Hide tag:value pairs" }
|
|
60438
|
+
hide: { description: "Hide tag:value pairs" },
|
|
60439
|
+
"box-metric": { description: "Metric label for the value ramp" },
|
|
60440
|
+
"show-values": { description: "Print box values as text" }
|
|
58723
60441
|
})
|
|
58724
60442
|
],
|
|
58725
60443
|
[
|
|
@@ -58784,18 +60502,12 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
58784
60502
|
],
|
|
58785
60503
|
[
|
|
58786
60504
|
"map",
|
|
58787
|
-
// Geographic map directives (§24B.2/.7).
|
|
58788
|
-
//
|
|
58789
|
-
//
|
|
60505
|
+
// Geographic map directives (§24B.2/.7). Cosmetics are ON by default — the
|
|
60506
|
+
// only switches are bare `no-*` opt-outs, surfaced proactively so a
|
|
60507
|
+
// zero-config map still hints at what can be turned off. `poi`/`route` are
|
|
60508
|
+
// content keywords, not directives; metadata keys (value/label/style) live
|
|
60509
|
+
// in the reserved-key registry.
|
|
58790
60510
|
withGlobals({
|
|
58791
|
-
region: {
|
|
58792
|
-
description: "Basemap: us-states (force US state mesh + scoping) | world (inert \u2014 already the default)",
|
|
58793
|
-
values: ["us-states", "world"]
|
|
58794
|
-
},
|
|
58795
|
-
projection: {
|
|
58796
|
-
description: "Override the auto projection",
|
|
58797
|
-
values: ["equirectangular", "natural-earth", "albers-usa", "mercator"]
|
|
58798
|
-
},
|
|
58799
60511
|
"region-metric": { description: "Label for the region value ramp" },
|
|
58800
60512
|
"poi-metric": {
|
|
58801
60513
|
description: "Label for the POI value (marker size) channel"
|
|
@@ -58803,21 +60515,30 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
58803
60515
|
"flow-metric": {
|
|
58804
60516
|
description: "Label for the edge/leg value (thickness) channel"
|
|
58805
60517
|
},
|
|
58806
|
-
|
|
58807
|
-
|
|
58808
|
-
description: "Subdivision name labels",
|
|
58809
|
-
values: ["full", "abbrev", "off"]
|
|
60518
|
+
locale: {
|
|
60519
|
+
description: "Default country/state for bare place names, e.g. locale US-GA"
|
|
58810
60520
|
},
|
|
58811
|
-
"
|
|
58812
|
-
description: "
|
|
58813
|
-
values: ["off", "auto", "all"]
|
|
60521
|
+
"active-tag": {
|
|
60522
|
+
description: "Which tag group leads when several are present"
|
|
58814
60523
|
},
|
|
58815
|
-
|
|
58816
|
-
"default-state": { description: "ISO subdivision scope" },
|
|
60524
|
+
caption: { description: "Caption line (data-source attribution)" },
|
|
58817
60525
|
"no-legend": { description: "Suppress the legend" },
|
|
58818
|
-
|
|
58819
|
-
|
|
58820
|
-
|
|
60526
|
+
"no-coastline": {
|
|
60527
|
+
description: "Turn off coastal water-lines (on by default)"
|
|
60528
|
+
},
|
|
60529
|
+
"no-relief": {
|
|
60530
|
+
description: "Turn off mountain-range relief shading (on by default)"
|
|
60531
|
+
},
|
|
60532
|
+
"no-context-labels": {
|
|
60533
|
+
description: "Turn off orientation labels for water + nearby countries"
|
|
60534
|
+
},
|
|
60535
|
+
"no-region-labels": {
|
|
60536
|
+
description: "Turn off subdivision name labels (on by default)"
|
|
60537
|
+
},
|
|
60538
|
+
"no-poi-labels": { description: "Turn off POI labels (on by default)" },
|
|
60539
|
+
"no-colorize": {
|
|
60540
|
+
description: "Force plain green-land reference dress (regions are auto-coloured by default)"
|
|
60541
|
+
}
|
|
58821
60542
|
})
|
|
58822
60543
|
]
|
|
58823
60544
|
]);
|
|
@@ -58944,13 +60665,10 @@ var PIPE_METADATA = /* @__PURE__ */ new Map([
|
|
|
58944
60665
|
"boxes-and-lines",
|
|
58945
60666
|
{
|
|
58946
60667
|
node: {
|
|
58947
|
-
description: { description: "Node description text" }
|
|
60668
|
+
description: { description: "Node description text" },
|
|
60669
|
+
value: { description: "Numeric value for the metric ramp" }
|
|
58948
60670
|
},
|
|
58949
|
-
edge: {
|
|
58950
|
-
width: { description: "Edge stroke width in pixels" },
|
|
58951
|
-
split: { description: "Traffic split percentage" },
|
|
58952
|
-
fanout: { description: "Fanout multiplier (integer >= 1)" }
|
|
58953
|
-
}
|
|
60671
|
+
edge: {}
|
|
58954
60672
|
}
|
|
58955
60673
|
],
|
|
58956
60674
|
[
|
|
@@ -60292,7 +62010,8 @@ export {
|
|
|
60292
62010
|
applyCollapseProjection,
|
|
60293
62011
|
applyGroupOrdering,
|
|
60294
62012
|
applyPositionOverrides,
|
|
60295
|
-
|
|
62013
|
+
atlasPalette,
|
|
62014
|
+
blueprintPalette,
|
|
60296
62015
|
buildExtendedChartOption,
|
|
60297
62016
|
buildNoteMessageMap,
|
|
60298
62017
|
buildRenderSequence,
|
|
@@ -60395,6 +62114,8 @@ export {
|
|
|
60395
62114
|
looksLikeState,
|
|
60396
62115
|
makeDgmoError,
|
|
60397
62116
|
mapBackgroundColor,
|
|
62117
|
+
mapContentAspect,
|
|
62118
|
+
mapExportDimensions,
|
|
60398
62119
|
mapNeutralLandColor,
|
|
60399
62120
|
matchesContiguously,
|
|
60400
62121
|
measurePertAnalysisBlock,
|
|
@@ -60530,9 +62251,11 @@ export {
|
|
|
60530
62251
|
shapeFill,
|
|
60531
62252
|
simulateCanonical,
|
|
60532
62253
|
simulateFast,
|
|
62254
|
+
slatePalette,
|
|
60533
62255
|
solarizedPalette,
|
|
60534
62256
|
suggestChartTypes,
|
|
60535
62257
|
themes,
|
|
62258
|
+
tidewaterPalette,
|
|
60536
62259
|
tint,
|
|
60537
62260
|
tokyoNightPalette,
|
|
60538
62261
|
transformLine,
|