@diagrammo/dgmo 0.19.0 → 0.20.1
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/dist/advanced.cjs +948 -321
- package/dist/advanced.d.cts +148 -54
- package/dist/advanced.d.ts +148 -54
- package/dist/advanced.js +949 -321
- package/dist/auto.cjs +930 -317
- package/dist/auto.js +117 -117
- package/dist/auto.mjs +934 -318
- package/dist/cli.cjs +160 -160
- package/dist/index.cjs +929 -316
- package/dist/index.js +933 -317
- package/dist/internal.cjs +948 -321
- package/dist/internal.d.cts +148 -54
- package/dist/internal.d.ts +148 -54
- package/dist/internal.js +949 -321
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/lakes.json +1 -0
- package/dist/map-data/na-lakes.json +1 -0
- package/dist/map-data/na-land.json +1 -0
- package/dist/map-data/rivers.json +1 -0
- package/docs/language-reference.md +12 -7
- package/gallery/fixtures/map-region-scope.dgmo +15 -0
- package/package.json +4 -4
- package/src/advanced.ts +7 -6
- package/src/c4/parser.ts +6 -6
- package/src/completion.ts +6 -2
- package/src/echarts.ts +1 -1
- package/src/infra/parser.ts +10 -10
- package/src/journey-map/parser.ts +1 -1
- package/src/label-layout.ts +36 -0
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/README.md +2 -0
- package/src/map/data/lakes.json +1 -0
- package/src/map/data/na-lakes.json +1 -0
- package/src/map/data/na-land.json +1 -0
- package/src/map/data/rivers.json +1 -0
- package/src/map/layout.ts +1022 -205
- package/src/map/load-data.ts +73 -17
- package/src/map/parser.ts +22 -13
- package/src/map/renderer.ts +200 -219
- package/src/map/resolved-types.ts +18 -1
- package/src/map/resolver.ts +79 -7
- package/src/map/types.ts +4 -0
- package/src/mindmap/parser.ts +1 -1
- package/src/sitemap/parser.ts +1 -1
- package/src/utils/legend-d3.ts +42 -0
- package/src/utils/legend-layout.ts +83 -3
- package/src/utils/legend-svg.ts +1 -8
- package/src/utils/legend-types.ts +44 -1
package/dist/index.js
CHANGED
|
@@ -51,6 +51,33 @@ function rectCircleOverlap(rect, circle) {
|
|
|
51
51
|
const dy = nearestY - circle.cy;
|
|
52
52
|
return dx * dx + dy * dy < circle.r * circle.r;
|
|
53
53
|
}
|
|
54
|
+
function segmentRectOverlap(x0, y0, x1, y1, rect) {
|
|
55
|
+
const dx = x1 - x0;
|
|
56
|
+
const dy = y1 - y0;
|
|
57
|
+
let t0 = 0;
|
|
58
|
+
let t1 = 1;
|
|
59
|
+
const edges = [
|
|
60
|
+
[-dx, x0 - rect.x],
|
|
61
|
+
[dx, rect.x + rect.w - x0],
|
|
62
|
+
[-dy, y0 - rect.y],
|
|
63
|
+
[dy, rect.y + rect.h - y0]
|
|
64
|
+
];
|
|
65
|
+
for (const [p, q] of edges) {
|
|
66
|
+
if (p === 0) {
|
|
67
|
+
if (q < 0) return false;
|
|
68
|
+
} else {
|
|
69
|
+
const t = q / p;
|
|
70
|
+
if (p < 0) {
|
|
71
|
+
if (t > t1) return false;
|
|
72
|
+
if (t > t0) t0 = t;
|
|
73
|
+
} else {
|
|
74
|
+
if (t < t0) return false;
|
|
75
|
+
if (t < t1) t1 = t;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
54
81
|
function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius, fontSize) {
|
|
55
82
|
const labelHeight = fontSize + 4;
|
|
56
83
|
const stepSize = labelHeight + 2;
|
|
@@ -3254,6 +3281,57 @@ var init_legend_constants = __esm({
|
|
|
3254
3281
|
});
|
|
3255
3282
|
|
|
3256
3283
|
// src/utils/legend-layout.ts
|
|
3284
|
+
function fmtRamp(n) {
|
|
3285
|
+
return Number.isInteger(n) ? String(n) : String(Math.round(n * 10) / 10);
|
|
3286
|
+
}
|
|
3287
|
+
function gradientCapsuleWidth(name, gradient) {
|
|
3288
|
+
const pw = pillWidth(name);
|
|
3289
|
+
const minW = measureLegendText(fmtRamp(gradient.min), LEGEND_ENTRY_FONT_SIZE);
|
|
3290
|
+
const maxW = measureLegendText(fmtRamp(gradient.max), LEGEND_ENTRY_FONT_SIZE);
|
|
3291
|
+
return LEGEND_CAPSULE_PAD + pw + 4 + minW + RAMP_LABEL_GAP + RAMP_LEGEND_W + RAMP_LABEL_GAP + maxW + LEGEND_CAPSULE_PAD;
|
|
3292
|
+
}
|
|
3293
|
+
function buildGradientCapsuleLayout(group, gradient) {
|
|
3294
|
+
const pw = pillWidth(group.name);
|
|
3295
|
+
const minText = fmtRamp(gradient.min);
|
|
3296
|
+
const maxText = fmtRamp(gradient.max);
|
|
3297
|
+
const minW = measureLegendText(minText, LEGEND_ENTRY_FONT_SIZE);
|
|
3298
|
+
const gx = LEGEND_CAPSULE_PAD + pw + 4;
|
|
3299
|
+
const minX = gx;
|
|
3300
|
+
const rampX = gx + minW + RAMP_LABEL_GAP;
|
|
3301
|
+
const maxX = rampX + RAMP_LEGEND_W + RAMP_LABEL_GAP;
|
|
3302
|
+
const width = gradientCapsuleWidth(group.name, gradient);
|
|
3303
|
+
return {
|
|
3304
|
+
groupName: group.name,
|
|
3305
|
+
x: 0,
|
|
3306
|
+
y: 0,
|
|
3307
|
+
width,
|
|
3308
|
+
height: LEGEND_HEIGHT,
|
|
3309
|
+
pill: {
|
|
3310
|
+
groupName: group.name,
|
|
3311
|
+
x: LEGEND_CAPSULE_PAD,
|
|
3312
|
+
y: LEGEND_CAPSULE_PAD,
|
|
3313
|
+
width: pw,
|
|
3314
|
+
height: LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2,
|
|
3315
|
+
isActive: true
|
|
3316
|
+
},
|
|
3317
|
+
entries: [],
|
|
3318
|
+
gradient: {
|
|
3319
|
+
rampX,
|
|
3320
|
+
rampY: (LEGEND_HEIGHT - RAMP_LEGEND_H) / 2,
|
|
3321
|
+
rampW: RAMP_LEGEND_W,
|
|
3322
|
+
rampH: RAMP_LEGEND_H,
|
|
3323
|
+
min: gradient.min,
|
|
3324
|
+
max: gradient.max,
|
|
3325
|
+
minText,
|
|
3326
|
+
minX,
|
|
3327
|
+
maxText,
|
|
3328
|
+
maxX,
|
|
3329
|
+
textY: LEGEND_HEIGHT / 2,
|
|
3330
|
+
hue: gradient.hue,
|
|
3331
|
+
base: gradient.base
|
|
3332
|
+
}
|
|
3333
|
+
};
|
|
3334
|
+
}
|
|
3257
3335
|
function pillWidth(name) {
|
|
3258
3336
|
return measureLegendText(name, LEGEND_PILL_FONT_SIZE) + LEGEND_PILL_PAD;
|
|
3259
3337
|
}
|
|
@@ -3396,7 +3474,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3396
3474
|
};
|
|
3397
3475
|
}
|
|
3398
3476
|
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3399
|
-
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0);
|
|
3477
|
+
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3400
3478
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3401
3479
|
return {
|
|
3402
3480
|
height: 0,
|
|
@@ -3475,7 +3553,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3475
3553
|
groupAvailW,
|
|
3476
3554
|
config.capsulePillAddonWidth ?? 0
|
|
3477
3555
|
);
|
|
3478
|
-
} else if (!activeGroupName) {
|
|
3556
|
+
} else if (!activeGroupName || config.showInactivePills) {
|
|
3479
3557
|
const pw = pillWidth(g.name);
|
|
3480
3558
|
pills.push({
|
|
3481
3559
|
groupName: g.name,
|
|
@@ -3513,6 +3591,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3513
3591
|
};
|
|
3514
3592
|
}
|
|
3515
3593
|
function buildCapsuleLayout(group, containerWidth, addonWidth = 0) {
|
|
3594
|
+
if (group.gradient) return buildGradientCapsuleLayout(group, group.gradient);
|
|
3516
3595
|
const pw = pillWidth(group.name);
|
|
3517
3596
|
const info = capsuleWidth(
|
|
3518
3597
|
group.name,
|
|
@@ -3683,7 +3762,7 @@ function getMaxLegendReservedHeight(config, containerWidth) {
|
|
|
3683
3762
|
}
|
|
3684
3763
|
return max;
|
|
3685
3764
|
}
|
|
3686
|
-
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
|
|
3765
|
+
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP, RAMP_LEGEND_W, RAMP_LEGEND_H, RAMP_LABEL_GAP;
|
|
3687
3766
|
var init_legend_layout = __esm({
|
|
3688
3767
|
"src/utils/legend-layout.ts"() {
|
|
3689
3768
|
"use strict";
|
|
@@ -3692,6 +3771,9 @@ var init_legend_layout = __esm({
|
|
|
3692
3771
|
CONTROL_FONT_SIZE = 11;
|
|
3693
3772
|
CONTROL_ICON_GAP = 4;
|
|
3694
3773
|
CONTROL_GAP = 8;
|
|
3774
|
+
RAMP_LEGEND_W = 80;
|
|
3775
|
+
RAMP_LEGEND_H = 8;
|
|
3776
|
+
RAMP_LABEL_GAP = 6;
|
|
3695
3777
|
}
|
|
3696
3778
|
});
|
|
3697
3779
|
|
|
@@ -3779,6 +3861,16 @@ function renderCapsule(parent, capsule, palette, groupBg, pillBorder, _isDark, c
|
|
|
3779
3861
|
g.append("rect").attr("x", pill.x).attr("y", pill.y).attr("width", pill.width).attr("height", pill.height).attr("rx", pill.height / 2).attr("fill", palette.bg);
|
|
3780
3862
|
g.append("rect").attr("x", pill.x).attr("y", pill.y).attr("width", pill.width).attr("height", pill.height).attr("rx", pill.height / 2).attr("fill", "none").attr("stroke", pillBorder).attr("stroke-width", 0.75);
|
|
3781
3863
|
g.append("text").attr("x", pill.x + pill.width / 2).attr("y", LEGEND_HEIGHT / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", 500).attr("fill", palette.text).attr("pointer-events", "none").attr("font-family", FONT_FAMILY).text(capsule.groupName);
|
|
3864
|
+
if (capsule.gradient) {
|
|
3865
|
+
const gr = capsule.gradient;
|
|
3866
|
+
const gradId = `dgmo-legend-ramp-${capsule.groupName.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
3867
|
+
const def = g.append("defs").append("linearGradient").attr("id", gradId);
|
|
3868
|
+
def.append("stop").attr("offset", "0%").attr("stop-color", mix(gr.hue, gr.base, 15));
|
|
3869
|
+
def.append("stop").attr("offset", "100%").attr("stop-color", gr.hue);
|
|
3870
|
+
g.append("text").attr("x", gr.minX).attr("y", gr.textY).attr("dominant-baseline", "central").attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).attr("pointer-events", "none").attr("font-family", FONT_FAMILY).text(gr.minText);
|
|
3871
|
+
g.append("rect").attr("class", "dgmo-legend-gradient-ramp").attr("data-ramp-min", gr.min).attr("data-ramp-max", gr.max).attr("x", gr.rampX).attr("y", gr.rampY).attr("width", gr.rampW).attr("height", gr.rampH).attr("rx", 2).attr("fill", `url(#${gradId})`);
|
|
3872
|
+
g.append("text").attr("x", gr.maxX).attr("y", gr.textY).attr("dominant-baseline", "central").attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).attr("pointer-events", "none").attr("font-family", FONT_FAMILY).text(gr.maxText);
|
|
3873
|
+
}
|
|
3782
3874
|
for (const entry of capsule.entries) {
|
|
3783
3875
|
const entryG = g.append("g").attr("data-legend-entry", entry.value.toLowerCase()).attr("data-series-name", entry.value).style("cursor", "pointer");
|
|
3784
3876
|
entryG.append("circle").attr("cx", entry.dotCx).attr("cy", entry.dotCy).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
|
|
@@ -11270,23 +11362,22 @@ function parseC4(content, palette) {
|
|
|
11270
11362
|
}
|
|
11271
11363
|
}
|
|
11272
11364
|
const parent = findParentElement(indent, stack);
|
|
11273
|
-
|
|
11274
|
-
|
|
11365
|
+
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
11366
|
+
if (parent && descResult.isKeyword) {
|
|
11275
11367
|
if (descResult.needsColon) {
|
|
11276
11368
|
pushError(
|
|
11277
11369
|
lineNumber,
|
|
11278
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11370
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`,
|
|
11279
11371
|
"warning"
|
|
11280
11372
|
);
|
|
11281
11373
|
}
|
|
11282
|
-
const descText = descResult.isKeyword ? descResult.text : trimmed;
|
|
11283
11374
|
let desc = elementDescription.get(parent.element);
|
|
11284
11375
|
if (!desc) {
|
|
11285
11376
|
desc = [];
|
|
11286
11377
|
elementDescription.set(parent.element, desc);
|
|
11287
11378
|
parent.element.description = desc;
|
|
11288
11379
|
}
|
|
11289
|
-
desc.push(
|
|
11380
|
+
desc.push(descResult.text);
|
|
11290
11381
|
} else {
|
|
11291
11382
|
pushError(lineNumber, `Unexpected content: "${trimmed}"`);
|
|
11292
11383
|
}
|
|
@@ -11753,7 +11844,7 @@ function parseSitemap(content, palette) {
|
|
|
11753
11844
|
if (descResult.needsColon) {
|
|
11754
11845
|
pushWarning(
|
|
11755
11846
|
lineNumber,
|
|
11756
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11847
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
11757
11848
|
);
|
|
11758
11849
|
}
|
|
11759
11850
|
const parent = findParentNode(indent, indentStack);
|
|
@@ -12581,23 +12672,22 @@ function parseInfra(content) {
|
|
|
12581
12672
|
}
|
|
12582
12673
|
}
|
|
12583
12674
|
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
12584
|
-
if (descResult.isKeyword
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
|
|
12675
|
+
if (descResult.isKeyword) {
|
|
12676
|
+
if (currentNode.isEdge) {
|
|
12677
|
+
continue;
|
|
12678
|
+
}
|
|
12588
12679
|
if (descResult.needsColon) {
|
|
12589
12680
|
warn(
|
|
12590
12681
|
lineNumber,
|
|
12591
|
-
`Use "description: ${descResult.text}" \u2014
|
|
12682
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
12592
12683
|
);
|
|
12593
12684
|
}
|
|
12594
|
-
|
|
12595
|
-
pushDescription(currentNode, descText);
|
|
12685
|
+
pushDescription(currentNode, descResult.text);
|
|
12596
12686
|
continue;
|
|
12597
12687
|
}
|
|
12598
12688
|
warn(
|
|
12599
12689
|
lineNumber,
|
|
12600
|
-
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or description text.`
|
|
12690
|
+
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or a description (description: text).`
|
|
12601
12691
|
);
|
|
12602
12692
|
continue;
|
|
12603
12693
|
}
|
|
@@ -15734,9 +15824,6 @@ function parseMap(content) {
|
|
|
15734
15824
|
const pushWarning = (line12, message) => {
|
|
15735
15825
|
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15736
15826
|
};
|
|
15737
|
-
const pushInfo = (line12, message) => {
|
|
15738
|
-
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15739
|
-
};
|
|
15740
15827
|
const lines = content.split("\n");
|
|
15741
15828
|
let firstIdx = 0;
|
|
15742
15829
|
while (firstIdx < lines.length) {
|
|
@@ -15866,10 +15953,15 @@ function parseMap(content) {
|
|
|
15866
15953
|
break;
|
|
15867
15954
|
case "projection":
|
|
15868
15955
|
dup(d.projection);
|
|
15869
|
-
if (value && ![
|
|
15956
|
+
if (value && ![
|
|
15957
|
+
"equirectangular",
|
|
15958
|
+
"natural-earth",
|
|
15959
|
+
"albers-usa",
|
|
15960
|
+
"mercator"
|
|
15961
|
+
].includes(value))
|
|
15870
15962
|
pushWarning(
|
|
15871
15963
|
line12,
|
|
15872
|
-
`Unknown projection "${value}" (expected natural-earth | albers-usa | mercator).`
|
|
15964
|
+
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15873
15965
|
);
|
|
15874
15966
|
d.projection = value;
|
|
15875
15967
|
break;
|
|
@@ -16008,17 +16100,21 @@ function parseMap(content) {
|
|
|
16008
16100
|
scoreNum = void 0;
|
|
16009
16101
|
}
|
|
16010
16102
|
}
|
|
16011
|
-
|
|
16012
|
-
|
|
16013
|
-
|
|
16014
|
-
|
|
16015
|
-
|
|
16103
|
+
let regionName = split.name;
|
|
16104
|
+
let regionScope;
|
|
16105
|
+
const rToks = regionName.split(/\s+/);
|
|
16106
|
+
const rLast = rToks[rToks.length - 1];
|
|
16107
|
+
if (rToks.length > 1 && SCOPE_RE.test(rLast)) {
|
|
16108
|
+
regionName = rToks.slice(0, -1).join(" ");
|
|
16109
|
+
regionScope = rLast;
|
|
16110
|
+
}
|
|
16016
16111
|
const region = {
|
|
16017
|
-
name:
|
|
16112
|
+
name: regionName,
|
|
16018
16113
|
tags,
|
|
16019
16114
|
meta,
|
|
16020
16115
|
lineNumber: line12
|
|
16021
16116
|
};
|
|
16117
|
+
if (regionScope !== void 0) region.scope = regionScope;
|
|
16022
16118
|
if (scoreNum !== void 0) region.score = scoreNum;
|
|
16023
16119
|
regions.push(region);
|
|
16024
16120
|
}
|
|
@@ -17142,7 +17238,7 @@ function parseMindmap(content, palette) {
|
|
|
17142
17238
|
if (descResult.needsColon) {
|
|
17143
17239
|
pushWarning(
|
|
17144
17240
|
lineNumber,
|
|
17145
|
-
`Use "description: ${descResult.text}" \u2014
|
|
17241
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
17146
17242
|
);
|
|
17147
17243
|
}
|
|
17148
17244
|
const parent = findMetadataParent2(indent, indentStack);
|
|
@@ -18930,7 +19026,7 @@ function parseJourneyMap(content, palette) {
|
|
|
18930
19026
|
if (descResult.needsColon) {
|
|
18931
19027
|
warn(
|
|
18932
19028
|
lineNumber,
|
|
18933
|
-
`Use "description: ${descResult.text}" \u2014
|
|
19029
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
18934
19030
|
);
|
|
18935
19031
|
}
|
|
18936
19032
|
currentStep.description = descResult.text;
|
|
@@ -45519,7 +45615,9 @@ function resolveMap(parsed, data) {
|
|
|
45519
45615
|
const usScoped = parsed.directives.region === "us-states" || parsed.directives.defaultCountry?.toUpperCase() === "US" || parsed.regions.some((r) => {
|
|
45520
45616
|
const f = fold(r.name);
|
|
45521
45617
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45522
|
-
}) || parsed.
|
|
45618
|
+
}) || parsed.regions.some(
|
|
45619
|
+
(r) => r.scope === "US" || r.scope?.startsWith("US-")
|
|
45620
|
+
) || parsed.pois.some(
|
|
45523
45621
|
(p) => p.pos.kind === "name" && p.pos.scope?.startsWith("US-")
|
|
45524
45622
|
);
|
|
45525
45623
|
const regions = [];
|
|
@@ -45531,7 +45629,30 @@ function resolveMap(parsed, data) {
|
|
|
45531
45629
|
const inCountry = countryIndex.get(f) ?? (REGION_ALIASES[f] ? countryIndex.get(REGION_ALIASES[f]) : void 0);
|
|
45532
45630
|
const inState = usStateIndex.get(f);
|
|
45533
45631
|
let chosen = null;
|
|
45534
|
-
|
|
45632
|
+
const scope = r.scope;
|
|
45633
|
+
if (scope) {
|
|
45634
|
+
const wantsState = scope === "US" || scope.startsWith("US-");
|
|
45635
|
+
if (wantsState && inState) {
|
|
45636
|
+
if (scope.startsWith("US-") && inState.id !== scope) {
|
|
45637
|
+
err(
|
|
45638
|
+
r.lineNumber,
|
|
45639
|
+
`No subdivision "${r.name}" in scope ${scope} (it is ${inState.id}).`,
|
|
45640
|
+
"E_MAP_SCOPE_MISS"
|
|
45641
|
+
);
|
|
45642
|
+
continue;
|
|
45643
|
+
}
|
|
45644
|
+
chosen = { ...inState, layer: "us-state" };
|
|
45645
|
+
} else if (!wantsState && inCountry) {
|
|
45646
|
+
chosen = { ...inCountry, layer: "country" };
|
|
45647
|
+
} else {
|
|
45648
|
+
err(
|
|
45649
|
+
r.lineNumber,
|
|
45650
|
+
`No region "${r.name}" found in scope ${scope}.`,
|
|
45651
|
+
"E_MAP_SCOPE_MISS"
|
|
45652
|
+
);
|
|
45653
|
+
continue;
|
|
45654
|
+
}
|
|
45655
|
+
} else if (inCountry && inState) {
|
|
45535
45656
|
if (usScoped) {
|
|
45536
45657
|
chosen = { ...inState, layer: "us-state" };
|
|
45537
45658
|
} else {
|
|
@@ -45539,7 +45660,7 @@ function resolveMap(parsed, data) {
|
|
|
45539
45660
|
}
|
|
45540
45661
|
warn(
|
|
45541
45662
|
r.lineNumber,
|
|
45542
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}).`,
|
|
45663
|
+
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
|
|
45543
45664
|
"W_MAP_REGION_AMBIGUOUS"
|
|
45544
45665
|
);
|
|
45545
45666
|
} else if (inState) {
|
|
@@ -45711,9 +45832,17 @@ function resolveMap(parsed, data) {
|
|
|
45711
45832
|
};
|
|
45712
45833
|
registerPoi(id, poi, p.lineNumber);
|
|
45713
45834
|
}
|
|
45835
|
+
const declaredByName = /* @__PURE__ */ new Map();
|
|
45836
|
+
for (const p of pois) {
|
|
45837
|
+
const fn = p.name ? fold(p.name) : void 0;
|
|
45838
|
+
if (fn && fn !== p.id && !declaredByName.has(fn))
|
|
45839
|
+
declaredByName.set(fn, p.id);
|
|
45840
|
+
}
|
|
45714
45841
|
const resolveEndpoint2 = (ref, line12) => {
|
|
45715
45842
|
const f = fold(ref);
|
|
45716
45843
|
if (registry.has(f)) return f;
|
|
45844
|
+
const aliased = declaredByName.get(f);
|
|
45845
|
+
if (aliased) return aliased;
|
|
45717
45846
|
const got = lookupName(ref, void 0, line12, inferredCountry, true);
|
|
45718
45847
|
if (got.kind !== "ok") return null;
|
|
45719
45848
|
noteCountry(got.iso);
|
|
@@ -45793,23 +45922,29 @@ function resolveMap(parsed, data) {
|
|
|
45793
45922
|
[-180, -85],
|
|
45794
45923
|
[180, 85]
|
|
45795
45924
|
];
|
|
45796
|
-
|
|
45925
|
+
let extent2 = unioned ? pad(unioned, PAD_FRACTION) : DEFAULT_EXTENT;
|
|
45797
45926
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
45798
45927
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
45799
45928
|
const span = Math.max(lonSpan, latSpan);
|
|
45800
45929
|
const usDominant = (inferredCountry === "US" || subdivisions.includes("us-states")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
45801
45930
|
let projection;
|
|
45802
45931
|
const override = parsed.directives.projection;
|
|
45803
|
-
if (override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
45932
|
+
if (override === "equirectangular" || override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
45804
45933
|
projection = override;
|
|
45805
45934
|
} else if (usDominant) {
|
|
45806
45935
|
projection = "albers-usa";
|
|
45807
45936
|
} else if (span > WORLD_SPAN) {
|
|
45808
|
-
projection = "
|
|
45937
|
+
projection = "equirectangular";
|
|
45809
45938
|
} else if (span < MERCATOR_MAX_SPAN) {
|
|
45810
45939
|
projection = "mercator";
|
|
45811
45940
|
} else {
|
|
45812
|
-
projection = "
|
|
45941
|
+
projection = "equirectangular";
|
|
45942
|
+
}
|
|
45943
|
+
if (lonSpan >= 180) {
|
|
45944
|
+
extent2 = [
|
|
45945
|
+
[-180, Math.min(extent2[0][1], WORLD_LAT_SOUTH)],
|
|
45946
|
+
[180, Math.max(extent2[1][1], WORLD_LAT_NORTH)]
|
|
45947
|
+
];
|
|
45813
45948
|
}
|
|
45814
45949
|
result.regions = regions;
|
|
45815
45950
|
result.pois = pois;
|
|
@@ -45857,7 +45992,7 @@ function firstError(diags) {
|
|
|
45857
45992
|
const e = diags.find((d) => d.severity === "error");
|
|
45858
45993
|
return e ? formatDgmoError(e) : null;
|
|
45859
45994
|
}
|
|
45860
|
-
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, REGION_ALIASES;
|
|
45995
|
+
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES;
|
|
45861
45996
|
var init_resolver2 = __esm({
|
|
45862
45997
|
"src/map/resolver.ts"() {
|
|
45863
45998
|
"use strict";
|
|
@@ -45866,6 +46001,8 @@ var init_resolver2 = __esm({
|
|
|
45866
46001
|
WORLD_SPAN = 90;
|
|
45867
46002
|
MERCATOR_MAX_SPAN = 25;
|
|
45868
46003
|
PAD_FRACTION = 0.05;
|
|
46004
|
+
WORLD_LAT_SOUTH = -58;
|
|
46005
|
+
WORLD_LAT_NORTH = 78;
|
|
45869
46006
|
REGION_ALIASES = {
|
|
45870
46007
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
45871
46008
|
"united states": "united states of america",
|
|
@@ -45895,17 +46032,22 @@ var load_data_exports = {};
|
|
|
45895
46032
|
__export(load_data_exports, {
|
|
45896
46033
|
loadMapData: () => loadMapData
|
|
45897
46034
|
});
|
|
45898
|
-
|
|
45899
|
-
|
|
45900
|
-
import
|
|
45901
|
-
|
|
45902
|
-
|
|
46035
|
+
async function loadNodeBuiltins() {
|
|
46036
|
+
const [{ readFile }, { fileURLToPath }, { dirname, resolve }] = await Promise.all([
|
|
46037
|
+
import("fs/promises"),
|
|
46038
|
+
import("url"),
|
|
46039
|
+
import("path")
|
|
46040
|
+
]);
|
|
46041
|
+
return { readFile, fileURLToPath, dirname, resolve };
|
|
46042
|
+
}
|
|
46043
|
+
async function readJson(nb, dir, name) {
|
|
46044
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
45903
46045
|
}
|
|
45904
|
-
async function firstExistingDir(baseDir) {
|
|
46046
|
+
async function firstExistingDir(nb, baseDir) {
|
|
45905
46047
|
for (const rel of CANDIDATE_DIRS) {
|
|
45906
|
-
const dir = resolve(baseDir, rel);
|
|
46048
|
+
const dir = nb.resolve(baseDir, rel);
|
|
45907
46049
|
try {
|
|
45908
|
-
await readFile(resolve(dir, FILES.gazetteer), "utf8");
|
|
46050
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
45909
46051
|
return dir;
|
|
45910
46052
|
} catch {
|
|
45911
46053
|
}
|
|
@@ -45921,10 +46063,10 @@ function validate(data) {
|
|
|
45921
46063
|
}
|
|
45922
46064
|
return data;
|
|
45923
46065
|
}
|
|
45924
|
-
function moduleBaseDir() {
|
|
46066
|
+
function moduleBaseDir(nb) {
|
|
45925
46067
|
try {
|
|
45926
46068
|
const url = import.meta.url;
|
|
45927
|
-
if (url) return dirname(fileURLToPath(url));
|
|
46069
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
45928
46070
|
} catch {
|
|
45929
46071
|
}
|
|
45930
46072
|
if (typeof __dirname !== "undefined") return __dirname;
|
|
@@ -45932,14 +46074,38 @@ function moduleBaseDir() {
|
|
|
45932
46074
|
}
|
|
45933
46075
|
function loadMapData() {
|
|
45934
46076
|
cache ??= (async () => {
|
|
45935
|
-
const
|
|
45936
|
-
const
|
|
45937
|
-
|
|
45938
|
-
|
|
45939
|
-
|
|
45940
|
-
|
|
46077
|
+
const nb = await loadNodeBuiltins();
|
|
46078
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
46079
|
+
const [
|
|
46080
|
+
worldCoarse,
|
|
46081
|
+
worldDetail,
|
|
46082
|
+
usStates,
|
|
46083
|
+
lakes,
|
|
46084
|
+
rivers,
|
|
46085
|
+
naLand,
|
|
46086
|
+
naLakes,
|
|
46087
|
+
gazetteer
|
|
46088
|
+
] = await Promise.all([
|
|
46089
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
46090
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
46091
|
+
readJson(nb, dir, FILES.usStates),
|
|
46092
|
+
// Lakes/rivers/NA assets are optional — older bundles may predate them.
|
|
46093
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
46094
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
46095
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
46096
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
46097
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
45941
46098
|
]);
|
|
45942
|
-
return validate({
|
|
46099
|
+
return validate({
|
|
46100
|
+
worldCoarse,
|
|
46101
|
+
worldDetail,
|
|
46102
|
+
usStates,
|
|
46103
|
+
gazetteer,
|
|
46104
|
+
...lakes && { lakes },
|
|
46105
|
+
...rivers && { rivers },
|
|
46106
|
+
...naLand && { naLand },
|
|
46107
|
+
...naLakes && { naLakes }
|
|
46108
|
+
});
|
|
45943
46109
|
})().catch((e) => {
|
|
45944
46110
|
cache = void 0;
|
|
45945
46111
|
throw e;
|
|
@@ -45954,6 +46120,10 @@ var init_load_data = __esm({
|
|
|
45954
46120
|
worldCoarse: "world-coarse.json",
|
|
45955
46121
|
worldDetail: "world-detail.json",
|
|
45956
46122
|
usStates: "us-states.json",
|
|
46123
|
+
lakes: "lakes.json",
|
|
46124
|
+
rivers: "rivers.json",
|
|
46125
|
+
naLand: "na-land.json",
|
|
46126
|
+
naLakes: "na-lakes.json",
|
|
45957
46127
|
gazetteer: "gazetteer.json"
|
|
45958
46128
|
};
|
|
45959
46129
|
CANDIDATE_DIRS = [
|
|
@@ -45969,8 +46139,11 @@ var init_load_data = __esm({
|
|
|
45969
46139
|
import {
|
|
45970
46140
|
geoPath,
|
|
45971
46141
|
geoNaturalEarth1,
|
|
45972
|
-
|
|
45973
|
-
|
|
46142
|
+
geoEquirectangular,
|
|
46143
|
+
geoConicEqualArea,
|
|
46144
|
+
geoMercator,
|
|
46145
|
+
geoBounds as geoBounds2,
|
|
46146
|
+
geoTransform
|
|
45974
46147
|
} from "d3-geo";
|
|
45975
46148
|
import { feature as feature2 } from "topojson-client";
|
|
45976
46149
|
function geomObject2(topo) {
|
|
@@ -45988,36 +46161,67 @@ function decodeLayer(topo) {
|
|
|
45988
46161
|
function projectionFor(family) {
|
|
45989
46162
|
switch (family) {
|
|
45990
46163
|
case "albers-usa":
|
|
45991
|
-
return
|
|
46164
|
+
return usConusProjection();
|
|
45992
46165
|
case "mercator":
|
|
45993
46166
|
return geoMercator();
|
|
45994
46167
|
case "natural-earth":
|
|
45995
|
-
default:
|
|
45996
46168
|
return geoNaturalEarth1();
|
|
46169
|
+
case "equirectangular":
|
|
46170
|
+
default:
|
|
46171
|
+
return geoEquirectangular();
|
|
45997
46172
|
}
|
|
45998
46173
|
}
|
|
46174
|
+
function mapBackgroundColor(palette) {
|
|
46175
|
+
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
46176
|
+
}
|
|
45999
46177
|
function layoutMap(resolved, data, size, opts) {
|
|
46000
46178
|
const { palette, isDark } = opts;
|
|
46001
46179
|
const { width, height } = size;
|
|
46002
|
-
const
|
|
46180
|
+
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46181
|
+
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
46182
|
+
const worldTopo = usCrisp ? data.naLand : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46003
46183
|
const worldLayer = decodeLayer(worldTopo);
|
|
46004
|
-
const usLayer =
|
|
46005
|
-
const
|
|
46006
|
-
const
|
|
46184
|
+
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
46185
|
+
const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
|
|
46186
|
+
const neutralFill = mix(palette.colors.green, palette.bg, landTint);
|
|
46187
|
+
const water = mapBackgroundColor(palette);
|
|
46188
|
+
const usContext = usLayer !== null;
|
|
46189
|
+
const foreignFill = mix(
|
|
46190
|
+
palette.colors.gray,
|
|
46191
|
+
palette.bg,
|
|
46192
|
+
isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46193
|
+
);
|
|
46194
|
+
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46007
46195
|
const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
|
|
46008
46196
|
const scaleOverride = resolved.directives.scale;
|
|
46009
46197
|
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
|
|
46010
46198
|
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
|
|
46011
|
-
const rampHue = palette.
|
|
46199
|
+
const rampHue = palette.colors.red;
|
|
46012
46200
|
const hasRamp = scores.length > 0;
|
|
46013
|
-
const
|
|
46014
|
-
|
|
46015
|
-
|
|
46016
|
-
|
|
46201
|
+
const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
|
|
46202
|
+
const matchColorGroup = (v) => {
|
|
46203
|
+
const lv = v.trim().toLowerCase();
|
|
46204
|
+
if (lv === "none") return null;
|
|
46205
|
+
if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
|
|
46206
|
+
return SCORE_NAME;
|
|
46207
|
+
const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
46208
|
+
return tg ? tg.name : v;
|
|
46209
|
+
};
|
|
46210
|
+
const override = opts.activeGroup;
|
|
46211
|
+
let activeGroup;
|
|
46212
|
+
if (override !== void 0) {
|
|
46213
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
46214
|
+
} else if (resolved.directives.activeTag !== void 0) {
|
|
46215
|
+
activeGroup = matchColorGroup(resolved.directives.activeTag);
|
|
46216
|
+
} else {
|
|
46217
|
+
activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46218
|
+
}
|
|
46219
|
+
const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
|
|
46220
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46017
46221
|
const fillForScore = (s) => {
|
|
46018
46222
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
46019
46223
|
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
46020
|
-
return mix(rampHue,
|
|
46224
|
+
return mix(rampHue, rampBase, pct);
|
|
46021
46225
|
};
|
|
46022
46226
|
const tagFill = (tags, groupName) => {
|
|
46023
46227
|
if (!groupName) return null;
|
|
@@ -46031,40 +46235,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46031
46235
|
(e) => e.value.toLowerCase() === val.toLowerCase()
|
|
46032
46236
|
);
|
|
46033
46237
|
if (!entry?.color) return null;
|
|
46034
|
-
return
|
|
46238
|
+
return mix(
|
|
46239
|
+
entry.color,
|
|
46240
|
+
palette.bg,
|
|
46241
|
+
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46242
|
+
);
|
|
46243
|
+
};
|
|
46244
|
+
const regionFill = (r) => {
|
|
46245
|
+
if (activeIsScore) {
|
|
46246
|
+
return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
|
|
46247
|
+
}
|
|
46248
|
+
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46035
46249
|
};
|
|
46036
46250
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46037
|
-
const
|
|
46038
|
-
for (const r of resolved.regions) {
|
|
46039
|
-
const f = r.layer === "us-state" ? usLayer?.get(r.iso) : worldLayer.get(r.iso);
|
|
46040
|
-
if (f) regionFeatures.push(f);
|
|
46041
|
-
}
|
|
46042
|
-
const extentCorners = () => {
|
|
46251
|
+
const extentOutline = () => {
|
|
46043
46252
|
const [[w, s], [e, n]] = resolved.extent;
|
|
46253
|
+
const N = 16;
|
|
46254
|
+
const coords = [];
|
|
46255
|
+
for (let i = 0; i <= N; i++) {
|
|
46256
|
+
const t = i / N;
|
|
46257
|
+
const lon = w + (e - w) * t;
|
|
46258
|
+
const lat = s + (n - s) * t;
|
|
46259
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46260
|
+
}
|
|
46044
46261
|
return {
|
|
46045
46262
|
type: "Feature",
|
|
46046
46263
|
properties: {},
|
|
46047
|
-
geometry: {
|
|
46048
|
-
type: "MultiPoint",
|
|
46049
|
-
coordinates: [
|
|
46050
|
-
[w, s],
|
|
46051
|
-
[e, s],
|
|
46052
|
-
[e, n],
|
|
46053
|
-
[w, n]
|
|
46054
|
-
]
|
|
46055
|
-
}
|
|
46264
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46056
46265
|
};
|
|
46057
46266
|
};
|
|
46058
46267
|
let fitFeatures;
|
|
46059
|
-
if (resolved.projection === "albers-usa") {
|
|
46060
|
-
|
|
46061
|
-
else if (usLayer) fitFeatures = [...usLayer.values()];
|
|
46062
|
-
else {
|
|
46063
|
-
const us = worldLayer.get("US");
|
|
46064
|
-
fitFeatures = us ? [us] : [...worldLayer.values()];
|
|
46065
|
-
}
|
|
46268
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46269
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46066
46270
|
} else {
|
|
46067
|
-
fitFeatures = [
|
|
46271
|
+
fitFeatures = [extentOutline()];
|
|
46068
46272
|
}
|
|
46069
46273
|
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46070
46274
|
const projection = projectionFor(resolved.projection);
|
|
@@ -46073,32 +46277,311 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46073
46277
|
if (centerLon > 180) centerLon -= 360;
|
|
46074
46278
|
projection.rotate([-centerLon, 0]);
|
|
46075
46279
|
}
|
|
46076
|
-
|
|
46280
|
+
const TITLE_GAP = 16;
|
|
46281
|
+
let topPad = FIT_PAD;
|
|
46282
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
46283
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46284
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP);
|
|
46285
|
+
}
|
|
46286
|
+
const fitBox = [
|
|
46287
|
+
[FIT_PAD, topPad],
|
|
46077
46288
|
[
|
|
46078
|
-
|
|
46079
|
-
|
|
46080
|
-
|
|
46081
|
-
|
|
46082
|
-
|
|
46083
|
-
|
|
46084
|
-
|
|
46085
|
-
|
|
46086
|
-
|
|
46087
|
-
|
|
46289
|
+
Math.max(FIT_PAD + 1, width - FIT_PAD),
|
|
46290
|
+
Math.max(topPad + 1, height - FIT_PAD)
|
|
46291
|
+
]
|
|
46292
|
+
];
|
|
46293
|
+
projection.fitExtent(fitBox, fitTarget);
|
|
46294
|
+
const fitGB = geoBounds2(fitTarget);
|
|
46295
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46296
|
+
let path;
|
|
46297
|
+
let project;
|
|
46298
|
+
if (fitIsGlobal) {
|
|
46299
|
+
const cb = geoPath(projection).bounds(fitTarget);
|
|
46300
|
+
const bx0 = cb[0][0];
|
|
46301
|
+
const by0 = cb[0][1];
|
|
46302
|
+
const cw = cb[1][0] - bx0;
|
|
46303
|
+
const ch = cb[1][1] - by0;
|
|
46304
|
+
const ox = fitBox[0][0];
|
|
46305
|
+
const oy = fitBox[0][1];
|
|
46306
|
+
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46307
|
+
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
46308
|
+
const stretch = (x, y) => [
|
|
46309
|
+
ox + (x - bx0) * sx,
|
|
46310
|
+
oy + (y - by0) * sy
|
|
46311
|
+
];
|
|
46312
|
+
const baseProjection = projection;
|
|
46313
|
+
const tx = geoTransform({
|
|
46314
|
+
point(x, y) {
|
|
46315
|
+
const [px, py] = stretch(x, y);
|
|
46316
|
+
this.stream.point(px, py);
|
|
46317
|
+
}
|
|
46318
|
+
});
|
|
46319
|
+
path = geoPath({
|
|
46320
|
+
stream: (s) => baseProjection.stream(
|
|
46321
|
+
tx.stream(s)
|
|
46322
|
+
)
|
|
46323
|
+
});
|
|
46324
|
+
project = (lon, lat) => {
|
|
46325
|
+
const p = baseProjection([lon, lat]);
|
|
46326
|
+
return p ? stretch(p[0], p[1]) : null;
|
|
46327
|
+
};
|
|
46328
|
+
} else {
|
|
46329
|
+
path = geoPath(projection);
|
|
46330
|
+
project = (lon, lat) => projection([lon, lat]) ?? null;
|
|
46331
|
+
}
|
|
46332
|
+
const insets = [];
|
|
46333
|
+
const insetRegions = [];
|
|
46334
|
+
const insetLabelSeeds = [];
|
|
46335
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46336
|
+
const PAD = 8;
|
|
46337
|
+
const GAP = 12;
|
|
46338
|
+
const yB = height - FIT_PAD;
|
|
46339
|
+
const BW = 8;
|
|
46340
|
+
const coast = /* @__PURE__ */ new Map();
|
|
46341
|
+
const addPt = (lon, lat) => {
|
|
46342
|
+
const p = projection([lon, lat]);
|
|
46343
|
+
if (!p) return;
|
|
46344
|
+
const bi = Math.floor(p[0] / BW);
|
|
46345
|
+
const cur = coast.get(bi);
|
|
46346
|
+
if (cur === void 0 || p[1] > cur) coast.set(bi, p[1]);
|
|
46347
|
+
};
|
|
46348
|
+
const walk = (co) => {
|
|
46349
|
+
if (Array.isArray(co) && typeof co[0] === "number")
|
|
46350
|
+
addPt(co[0], co[1]);
|
|
46351
|
+
else if (Array.isArray(co)) for (const c of co) walk(c);
|
|
46352
|
+
};
|
|
46353
|
+
for (const [iso, f] of usLayer) {
|
|
46354
|
+
if (US_NON_CONUS.has(iso)) continue;
|
|
46355
|
+
walk(f.geometry.coordinates);
|
|
46356
|
+
}
|
|
46357
|
+
const at = (x) => {
|
|
46358
|
+
const bi = Math.floor(x / BW);
|
|
46359
|
+
let y = -Infinity;
|
|
46360
|
+
for (let k = bi - 1; k <= bi + 1; k++) {
|
|
46361
|
+
const v = coast.get(k);
|
|
46362
|
+
if (v !== void 0 && v > y) y = v;
|
|
46363
|
+
}
|
|
46364
|
+
return y;
|
|
46365
|
+
};
|
|
46366
|
+
const coastTop = (x0, xr) => {
|
|
46367
|
+
const n = 24;
|
|
46368
|
+
const pts = [];
|
|
46369
|
+
let maxY = -Infinity;
|
|
46370
|
+
for (let i = 0; i <= n; i++) {
|
|
46371
|
+
const x = x0 + (xr - x0) * i / n;
|
|
46372
|
+
const y = at(x);
|
|
46373
|
+
if (y > -Infinity) {
|
|
46374
|
+
pts.push([x, y]);
|
|
46375
|
+
if (y > maxY) maxY = y;
|
|
46376
|
+
}
|
|
46377
|
+
}
|
|
46378
|
+
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46379
|
+
let m = 0;
|
|
46380
|
+
if (pts.length >= 2) {
|
|
46381
|
+
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46382
|
+
for (const [x, y] of pts) {
|
|
46383
|
+
sx += x;
|
|
46384
|
+
sy += y;
|
|
46385
|
+
sxx += x * x;
|
|
46386
|
+
sxy += x * y;
|
|
46387
|
+
}
|
|
46388
|
+
const den = pts.length * sxx - sx * sx;
|
|
46389
|
+
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46390
|
+
}
|
|
46391
|
+
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46392
|
+
let c = -Infinity;
|
|
46393
|
+
for (const [x, y] of pts) {
|
|
46394
|
+
const need = y - m * x + GAP;
|
|
46395
|
+
if (need > c) c = need;
|
|
46396
|
+
}
|
|
46397
|
+
return (x) => m * x + c;
|
|
46398
|
+
};
|
|
46399
|
+
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46400
|
+
const f = usLayer.get(iso);
|
|
46401
|
+
if (!f) return boxX;
|
|
46402
|
+
const x0 = boxX;
|
|
46403
|
+
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46404
|
+
if (iw < 24) return boxX;
|
|
46405
|
+
const xr = x0 + iw + 2 * PAD;
|
|
46406
|
+
const top = coastTop(x0, xr);
|
|
46407
|
+
const yL = top(x0);
|
|
46408
|
+
const yR = top(xr);
|
|
46409
|
+
proj.fitWidth(iw, f);
|
|
46410
|
+
const bb = geoPath(proj).bounds(f);
|
|
46411
|
+
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46412
|
+
const needH = sh + 2 * PAD;
|
|
46413
|
+
let topFit = Math.max(yL, yR);
|
|
46414
|
+
const bottom = Math.min(topFit + needH, yB);
|
|
46415
|
+
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46416
|
+
const lift = topFit - Math.max(yL, yR);
|
|
46417
|
+
const topL = yL + lift;
|
|
46418
|
+
const topR = yR + lift;
|
|
46419
|
+
proj.fitExtent(
|
|
46420
|
+
[
|
|
46421
|
+
[x0 + PAD, topFit + PAD],
|
|
46422
|
+
[xr - PAD, bottom - PAD]
|
|
46423
|
+
],
|
|
46424
|
+
f
|
|
46425
|
+
);
|
|
46426
|
+
const d = geoPath(proj)(f) ?? "";
|
|
46427
|
+
if (!d) return xr;
|
|
46428
|
+
const r = regionById.get(iso);
|
|
46429
|
+
let fill2 = neutralFill;
|
|
46430
|
+
let lineNumber = -1;
|
|
46431
|
+
if (r?.layer === "us-state") {
|
|
46432
|
+
fill2 = regionFill(r);
|
|
46433
|
+
lineNumber = r.lineNumber;
|
|
46434
|
+
}
|
|
46435
|
+
insets.push({
|
|
46436
|
+
x: x0,
|
|
46437
|
+
y: Math.min(topL, topR),
|
|
46438
|
+
w: xr - x0,
|
|
46439
|
+
h: bottom - Math.min(topL, topR),
|
|
46440
|
+
points: [
|
|
46441
|
+
[x0, topL],
|
|
46442
|
+
[xr, topR],
|
|
46443
|
+
[xr, bottom],
|
|
46444
|
+
[x0, bottom]
|
|
46445
|
+
]
|
|
46446
|
+
});
|
|
46447
|
+
insetRegions.push({
|
|
46448
|
+
id: iso,
|
|
46449
|
+
d,
|
|
46450
|
+
fill: fill2,
|
|
46451
|
+
stroke: regionStroke,
|
|
46452
|
+
lineNumber,
|
|
46453
|
+
layer: "us-state",
|
|
46454
|
+
...r?.score !== void 0 && { score: r.score },
|
|
46455
|
+
...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46456
|
+
});
|
|
46457
|
+
const ctr = geoPath(proj).centroid(f);
|
|
46458
|
+
if (Number.isFinite(ctr[0])) {
|
|
46459
|
+
const name = f.properties?.name ?? iso;
|
|
46460
|
+
insetLabelSeeds.push({ x: ctr[0], y: ctr[1], iso, name, lineNumber });
|
|
46461
|
+
}
|
|
46462
|
+
return xr;
|
|
46463
|
+
};
|
|
46464
|
+
const akRight = placeInset(
|
|
46465
|
+
"US-AK",
|
|
46466
|
+
alaskaProjection(),
|
|
46467
|
+
FIT_PAD,
|
|
46468
|
+
width * 0.15
|
|
46469
|
+
);
|
|
46470
|
+
placeInset("US-HI", hawaiiProjection(), akRight + 24, width * 0.1);
|
|
46471
|
+
}
|
|
46472
|
+
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46473
|
+
const cullExtent = conusFit ? geoBounds2(fitTarget) : resolved.extent;
|
|
46474
|
+
const [[exW, exS], [exE, exN]] = cullExtent;
|
|
46475
|
+
const lonSpan = exE - exW;
|
|
46476
|
+
const latSpan = exN - exS;
|
|
46477
|
+
const isGlobalView = lonSpan >= 270 || latSpan >= 130;
|
|
46478
|
+
const padLon = Math.max(8, lonSpan * 0.35);
|
|
46479
|
+
const padLat = Math.max(8, latSpan * 0.35);
|
|
46480
|
+
const vW = exW - padLon;
|
|
46481
|
+
const vE = exE + padLon;
|
|
46482
|
+
const vS = exS - padLat;
|
|
46483
|
+
const vN = exN + padLat;
|
|
46484
|
+
const vLonCenter = (exW + exE) / 2;
|
|
46485
|
+
const normLon = (lon) => {
|
|
46486
|
+
let L = lon;
|
|
46487
|
+
while (L < vLonCenter - 180) L += 360;
|
|
46488
|
+
while (L > vLonCenter + 180) L -= 360;
|
|
46489
|
+
return L;
|
|
46490
|
+
};
|
|
46491
|
+
const ringOverlapsView = (ring) => {
|
|
46492
|
+
let anyIn = false;
|
|
46493
|
+
let loMin = Infinity, loMax = -Infinity, laMin = Infinity, laMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
46494
|
+
for (const [rawLon, lat] of ring) {
|
|
46495
|
+
const lon = normLon(rawLon);
|
|
46496
|
+
if (lon >= vW && lon <= vE && lat >= vS && lat <= vN) anyIn = true;
|
|
46497
|
+
if (lon < loMin) loMin = lon;
|
|
46498
|
+
if (lon > loMax) loMax = lon;
|
|
46499
|
+
if (rawLon < rawMin) rawMin = rawLon;
|
|
46500
|
+
if (rawLon > rawMax) rawMax = rawLon;
|
|
46501
|
+
if (lat < laMin) laMin = lat;
|
|
46502
|
+
if (lat > laMax) laMax = lat;
|
|
46503
|
+
}
|
|
46504
|
+
if (loMax - loMin > 270) return false;
|
|
46505
|
+
if (rawMax - rawMin > 180 && loMax - loMin < 90) return false;
|
|
46506
|
+
if (anyIn) return true;
|
|
46507
|
+
if (loMax - loMin > 180) return false;
|
|
46508
|
+
return !(loMax < vW || loMin > vE || laMax < vS || laMin > vN);
|
|
46509
|
+
};
|
|
46510
|
+
const cullFeatureToView = (f) => {
|
|
46511
|
+
if (isGlobalView) return f;
|
|
46512
|
+
const g = f.geometry;
|
|
46513
|
+
if (!g) return f;
|
|
46514
|
+
if (g.type === "Polygon") {
|
|
46515
|
+
const ring = g.coordinates[0];
|
|
46516
|
+
return ringOverlapsView(ring) ? f : null;
|
|
46517
|
+
}
|
|
46518
|
+
if (g.type === "MultiPolygon") {
|
|
46519
|
+
const polys = g.coordinates;
|
|
46520
|
+
const keep = polys.filter(
|
|
46521
|
+
(p) => ringOverlapsView(p[0])
|
|
46522
|
+
);
|
|
46523
|
+
if (!keep.length) return null;
|
|
46524
|
+
if (keep.length === polys.length) return f;
|
|
46525
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46526
|
+
}
|
|
46527
|
+
return f;
|
|
46528
|
+
};
|
|
46529
|
+
const SEAM_SLIVER_MAX_SPAN = 100;
|
|
46530
|
+
const ringIsFrameFiller = (ring) => {
|
|
46531
|
+
const lons = ring.map(([lon]) => lon).sort((a, b) => a - b);
|
|
46532
|
+
if (lons.length < 2) return false;
|
|
46533
|
+
let maxGap = -1;
|
|
46534
|
+
let gapIdx = 0;
|
|
46535
|
+
for (let i = 1; i < lons.length; i++) {
|
|
46536
|
+
const g = lons[i] - lons[i - 1];
|
|
46537
|
+
if (g > maxGap) {
|
|
46538
|
+
maxGap = g;
|
|
46539
|
+
gapIdx = i;
|
|
46540
|
+
}
|
|
46541
|
+
}
|
|
46542
|
+
const wrapGap = lons[0] + 360 - lons[lons.length - 1];
|
|
46543
|
+
if (wrapGap >= maxGap) return false;
|
|
46544
|
+
const span = 360 - maxGap;
|
|
46545
|
+
const east = lons[gapIdx - 1] + 360;
|
|
46546
|
+
return east > 180 && span < SEAM_SLIVER_MAX_SPAN;
|
|
46547
|
+
};
|
|
46548
|
+
const dropFrameFillers = (f) => {
|
|
46549
|
+
const g = f.geometry;
|
|
46550
|
+
if (!g) return f;
|
|
46551
|
+
if (g.type === "Polygon") {
|
|
46552
|
+
const ring = g.coordinates[0];
|
|
46553
|
+
return ringIsFrameFiller(ring) ? null : f;
|
|
46554
|
+
}
|
|
46555
|
+
if (g.type === "MultiPolygon") {
|
|
46556
|
+
const polys = g.coordinates;
|
|
46557
|
+
const keep = polys.filter(
|
|
46558
|
+
(p) => !ringIsFrameFiller(p[0])
|
|
46559
|
+
);
|
|
46560
|
+
if (!keep.length) return null;
|
|
46561
|
+
if (keep.length === polys.length) return f;
|
|
46562
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46563
|
+
}
|
|
46564
|
+
return f;
|
|
46565
|
+
};
|
|
46088
46566
|
const regions = [];
|
|
46089
|
-
const pushRegionLayer = (layerFeatures, layerKind) => {
|
|
46567
|
+
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46090
46568
|
for (const [iso, f] of layerFeatures) {
|
|
46091
|
-
|
|
46092
|
-
|
|
46569
|
+
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
46570
|
+
continue;
|
|
46571
|
+
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46093
46572
|
const r = regionById.get(iso);
|
|
46573
|
+
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
46574
|
+
if (!viewF) continue;
|
|
46575
|
+
const d = path(viewF) ?? "";
|
|
46576
|
+
if (!d) continue;
|
|
46094
46577
|
const isThisLayer = r?.layer === layerKind;
|
|
46095
|
-
|
|
46578
|
+
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46579
|
+
let fill2 = isForeign ? foreignFill : neutralFill;
|
|
46096
46580
|
let label;
|
|
46097
46581
|
let lineNumber = -1;
|
|
46098
46582
|
let layer = "base";
|
|
46099
46583
|
if (isThisLayer) {
|
|
46100
|
-
|
|
46101
|
-
else fill2 = tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46584
|
+
fill2 = regionFill(r);
|
|
46102
46585
|
lineNumber = r.lineNumber;
|
|
46103
46586
|
layer = layerKind;
|
|
46104
46587
|
label = r.name;
|
|
@@ -46110,12 +46593,42 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46110
46593
|
stroke: regionStroke,
|
|
46111
46594
|
lineNumber,
|
|
46112
46595
|
layer,
|
|
46113
|
-
...label !== void 0 && { label }
|
|
46596
|
+
...label !== void 0 && { label },
|
|
46597
|
+
...isThisLayer && r.score !== void 0 && { score: r.score },
|
|
46598
|
+
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46114
46599
|
});
|
|
46115
46600
|
}
|
|
46116
46601
|
};
|
|
46117
|
-
pushRegionLayer(worldLayer, "country");
|
|
46118
|
-
if (usLayer) pushRegionLayer(usLayer, "us-state");
|
|
46602
|
+
pushRegionLayer(worldLayer, "country", !isGlobalView);
|
|
46603
|
+
if (usLayer) pushRegionLayer(usLayer, "us-state", !conusFit && !isGlobalView);
|
|
46604
|
+
const lakesTopo = usCrisp && data.naLakes ? data.naLakes : data.lakes;
|
|
46605
|
+
if (lakesTopo) {
|
|
46606
|
+
for (const [, f] of decodeLayer(lakesTopo)) {
|
|
46607
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46608
|
+
if (!viewF) continue;
|
|
46609
|
+
const d = path(viewF) ?? "";
|
|
46610
|
+
if (!d) continue;
|
|
46611
|
+
regions.push({
|
|
46612
|
+
id: "lake",
|
|
46613
|
+
d,
|
|
46614
|
+
fill: water,
|
|
46615
|
+
stroke: "none",
|
|
46616
|
+
lineNumber: -1,
|
|
46617
|
+
layer: "base"
|
|
46618
|
+
});
|
|
46619
|
+
}
|
|
46620
|
+
}
|
|
46621
|
+
const riverColor = water;
|
|
46622
|
+
const rivers = [];
|
|
46623
|
+
if (data.rivers) {
|
|
46624
|
+
for (const [, f] of decodeLayer(data.rivers)) {
|
|
46625
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46626
|
+
if (!viewF) continue;
|
|
46627
|
+
const d = path(viewF) ?? "";
|
|
46628
|
+
if (!d) continue;
|
|
46629
|
+
rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
|
|
46630
|
+
}
|
|
46631
|
+
}
|
|
46119
46632
|
const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
46120
46633
|
const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
|
|
46121
46634
|
const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
|
|
@@ -46136,8 +46649,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46136
46649
|
if (hex) return { fill: hex, stroke: mix(hex, palette.text, 18) };
|
|
46137
46650
|
}
|
|
46138
46651
|
return {
|
|
46139
|
-
fill: palette.
|
|
46140
|
-
stroke: mix(palette.
|
|
46652
|
+
fill: palette.colors.orange,
|
|
46653
|
+
stroke: mix(palette.colors.orange, palette.text, 18)
|
|
46141
46654
|
};
|
|
46142
46655
|
};
|
|
46143
46656
|
const routeNumberById = /* @__PURE__ */ new Map();
|
|
@@ -46175,7 +46688,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46175
46688
|
cy += Math.sin(ang) * COLO_R;
|
|
46176
46689
|
}
|
|
46177
46690
|
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
46178
|
-
poiScreen.set(e.p.id, { cx, cy });
|
|
46691
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
46179
46692
|
const num = routeNumberById.get(e.p.id);
|
|
46180
46693
|
pois.push({
|
|
46181
46694
|
id: e.p.id,
|
|
@@ -46192,17 +46705,36 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46192
46705
|
});
|
|
46193
46706
|
}
|
|
46194
46707
|
const legs = [];
|
|
46708
|
+
const RIM_GAP = 1.5;
|
|
46195
46709
|
const legPath = (a, b, curved, offset) => {
|
|
46196
|
-
if (!curved && offset === 0) return `M${a.cx},${a.cy}L${b.cx},${b.cy}`;
|
|
46197
46710
|
const mx = (a.cx + b.cx) / 2;
|
|
46198
46711
|
const my = (a.cy + b.cy) / 2;
|
|
46199
46712
|
const dx = b.cx - a.cx;
|
|
46200
46713
|
const dy = b.cy - a.cy;
|
|
46201
46714
|
const len = Math.hypot(dx, dy) || 1;
|
|
46715
|
+
const trimA = Math.min(a.r + RIM_GAP, len * 0.45);
|
|
46716
|
+
const trimB = Math.min(b.r + RIM_GAP, len * 0.45);
|
|
46717
|
+
if (!curved && offset === 0) {
|
|
46718
|
+
const ux = dx / len;
|
|
46719
|
+
const uy = dy / len;
|
|
46720
|
+
const ax2 = a.cx + ux * trimA;
|
|
46721
|
+
const ay2 = a.cy + uy * trimA;
|
|
46722
|
+
const bx2 = b.cx - ux * trimB;
|
|
46723
|
+
const by2 = b.cy - uy * trimB;
|
|
46724
|
+
return `M${ax2},${ay2}L${bx2},${by2}`;
|
|
46725
|
+
}
|
|
46202
46726
|
const nx = -dy / len;
|
|
46203
46727
|
const ny = dx / len;
|
|
46204
46728
|
const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
|
|
46205
|
-
|
|
46729
|
+
const px = mx + nx * bow;
|
|
46730
|
+
const py = my + ny * bow;
|
|
46731
|
+
const ta = Math.hypot(px - a.cx, py - a.cy) || 1;
|
|
46732
|
+
const tb = Math.hypot(b.cx - px, b.cy - py) || 1;
|
|
46733
|
+
const ax = a.cx + (px - a.cx) / ta * trimA;
|
|
46734
|
+
const ay = a.cy + (py - a.cy) / ta * trimA;
|
|
46735
|
+
const bx = b.cx - (b.cx - px) / tb * trimB;
|
|
46736
|
+
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
46737
|
+
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
46206
46738
|
};
|
|
46207
46739
|
for (const rt of resolved.routes) {
|
|
46208
46740
|
const curved = rt.meta["style"] === "arc";
|
|
@@ -46213,7 +46745,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46213
46745
|
legs.push({
|
|
46214
46746
|
d: legPath(a, b, curved, 0),
|
|
46215
46747
|
width: W_MIN,
|
|
46216
|
-
color: mix(palette.text, palette.bg,
|
|
46748
|
+
color: mix(palette.text, palette.bg, 72),
|
|
46217
46749
|
arrow: true,
|
|
46218
46750
|
lineNumber: rt.lineNumber
|
|
46219
46751
|
});
|
|
@@ -46249,7 +46781,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46249
46781
|
legs.push({
|
|
46250
46782
|
d: legPath(a, b, curved, offset),
|
|
46251
46783
|
width: widthFor(e),
|
|
46252
|
-
color: mix(palette.text, palette.bg,
|
|
46784
|
+
color: mix(palette.text, palette.bg, 66),
|
|
46253
46785
|
arrow: e.directed,
|
|
46254
46786
|
lineNumber: e.lineNumber,
|
|
46255
46787
|
...e.label !== void 0 && {
|
|
@@ -46261,38 +46793,92 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46261
46793
|
});
|
|
46262
46794
|
}
|
|
46263
46795
|
const labels = [];
|
|
46264
|
-
const pinList = [];
|
|
46265
46796
|
const obstacles = [];
|
|
46266
46797
|
const markers = pois.map((p) => ({
|
|
46267
46798
|
cx: p.cx,
|
|
46268
46799
|
cy: p.cy,
|
|
46269
46800
|
r: p.r
|
|
46270
46801
|
}));
|
|
46271
|
-
const
|
|
46802
|
+
const legSegments = [];
|
|
46803
|
+
for (const leg of legs) {
|
|
46804
|
+
const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
46805
|
+
leg.d
|
|
46806
|
+
);
|
|
46807
|
+
if (!m) continue;
|
|
46808
|
+
const x0 = +m[1];
|
|
46809
|
+
const y0 = +m[2];
|
|
46810
|
+
if (m[3] !== void 0) {
|
|
46811
|
+
legSegments.push([x0, y0, +m[3], +m[4]]);
|
|
46812
|
+
} else {
|
|
46813
|
+
const cx = +m[5];
|
|
46814
|
+
const cy = +m[6];
|
|
46815
|
+
const ex = +m[7];
|
|
46816
|
+
const ey = +m[8];
|
|
46817
|
+
const N = 8;
|
|
46818
|
+
let px = x0;
|
|
46819
|
+
let py = y0;
|
|
46820
|
+
for (let i = 1; i <= N; i++) {
|
|
46821
|
+
const t = i / N;
|
|
46822
|
+
const u = 1 - t;
|
|
46823
|
+
const qx = u * u * x0 + 2 * u * t * cx + t * t * ex;
|
|
46824
|
+
const qy = u * u * y0 + 2 * u * t * cy + t * t * ey;
|
|
46825
|
+
legSegments.push([px, py, qx, qy]);
|
|
46826
|
+
px = qx;
|
|
46827
|
+
py = qy;
|
|
46828
|
+
}
|
|
46829
|
+
}
|
|
46830
|
+
}
|
|
46831
|
+
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));
|
|
46272
46832
|
const regionLabelMode = resolved.directives.regionLabels ?? "off";
|
|
46833
|
+
const LABEL_PADX = 6;
|
|
46834
|
+
const LABEL_PADY = 3;
|
|
46835
|
+
const labelW = (text) => measureLegendText(text, FONT) + 2 * LABEL_PADX;
|
|
46836
|
+
const labelH = FONT + 2 * LABEL_PADY;
|
|
46837
|
+
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
46838
|
+
const color = contrastText(
|
|
46839
|
+
fill2,
|
|
46840
|
+
palette.textOnFillLight,
|
|
46841
|
+
palette.textOnFillDark
|
|
46842
|
+
);
|
|
46843
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
46844
|
+
labels.push({
|
|
46845
|
+
x,
|
|
46846
|
+
y,
|
|
46847
|
+
text,
|
|
46848
|
+
anchor: "middle",
|
|
46849
|
+
color,
|
|
46850
|
+
halo: true,
|
|
46851
|
+
haloColor,
|
|
46852
|
+
lineNumber
|
|
46853
|
+
});
|
|
46854
|
+
};
|
|
46855
|
+
const WORLD_LABEL_ANCHORS = {
|
|
46856
|
+
US: [-98.5, 39.5]
|
|
46857
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
46858
|
+
};
|
|
46273
46859
|
if (regionLabelMode === "full" || regionLabelMode === "abbrev") {
|
|
46274
46860
|
for (const r of regions) {
|
|
46275
46861
|
if (r.layer === "base" || r.label === void 0) continue;
|
|
46276
46862
|
const f = r.layer === "us-state" ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
46277
46863
|
if (!f) continue;
|
|
46278
46864
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
46279
|
-
if ((x1 - x0) * (y1 - y0) < TINY_REGION_AREA) continue;
|
|
46280
|
-
const c = path.centroid(f);
|
|
46281
|
-
if (!Number.isFinite(c[0])) continue;
|
|
46282
46865
|
const text = regionLabelMode === "abbrev" ? r.id.replace(/^US-/, "") : r.label;
|
|
46283
|
-
|
|
46284
|
-
|
|
46285
|
-
|
|
46866
|
+
if (labelW(text) > x1 - x0 || labelH > y1 - y0) continue;
|
|
46867
|
+
const anchor = r.layer !== "us-state" ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
46868
|
+
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
46869
|
+
if (!c || !Number.isFinite(c[0])) continue;
|
|
46870
|
+
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
46871
|
+
}
|
|
46872
|
+
for (const seed of insetLabelSeeds) {
|
|
46873
|
+
const text = regionLabelMode === "abbrev" ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
46874
|
+
const src = regionById.get(seed.iso);
|
|
46875
|
+
pushRegionLabel(
|
|
46876
|
+
seed.x,
|
|
46877
|
+
seed.y,
|
|
46286
46878
|
text,
|
|
46287
|
-
|
|
46288
|
-
|
|
46289
|
-
|
|
46290
|
-
palette.textOnFillLight,
|
|
46291
|
-
palette.textOnFillDark
|
|
46292
|
-
),
|
|
46293
|
-
halo: true,
|
|
46294
|
-
lineNumber: r.lineNumber
|
|
46295
|
-
});
|
|
46879
|
+
src ? regionFill(src) : neutralFill,
|
|
46880
|
+
seed.lineNumber
|
|
46881
|
+
);
|
|
46296
46882
|
}
|
|
46297
46883
|
}
|
|
46298
46884
|
const poiLabelMode = resolved.directives.poiLabels ?? "auto";
|
|
@@ -46305,68 +46891,106 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46305
46891
|
const src = poiById.get(p.id);
|
|
46306
46892
|
return src?.label ?? src?.name ?? p.id;
|
|
46307
46893
|
};
|
|
46308
|
-
|
|
46309
|
-
|
|
46894
|
+
const poiLabH = FONT * 1.25;
|
|
46895
|
+
const labelInfo = (p) => {
|
|
46310
46896
|
const text = labelText(p);
|
|
46311
|
-
|
|
46312
|
-
|
|
46313
|
-
|
|
46314
|
-
|
|
46315
|
-
|
|
46897
|
+
return { text, w: measureLegendText(text, FONT) };
|
|
46898
|
+
};
|
|
46899
|
+
const pushInline = (p, text, w, side) => {
|
|
46900
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46901
|
+
obstacles.push({
|
|
46902
|
+
x: side === "right" ? tx : tx - w,
|
|
46903
|
+
y: p.cy - poiLabH / 2,
|
|
46904
|
+
w,
|
|
46905
|
+
h: poiLabH
|
|
46906
|
+
});
|
|
46907
|
+
labels.push({
|
|
46908
|
+
x: tx,
|
|
46909
|
+
y: p.cy + FONT / 3,
|
|
46910
|
+
text,
|
|
46911
|
+
anchor: side === "right" ? "start" : "end",
|
|
46912
|
+
color: palette.text,
|
|
46913
|
+
halo: true,
|
|
46914
|
+
haloColor: palette.bg,
|
|
46915
|
+
poiId: p.id,
|
|
46916
|
+
lineNumber: p.lineNumber
|
|
46917
|
+
});
|
|
46918
|
+
};
|
|
46919
|
+
const inlineFits = (p, w, side) => {
|
|
46920
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46921
|
+
const rect = {
|
|
46922
|
+
x: side === "right" ? tx : tx - w,
|
|
46923
|
+
y: p.cy - poiLabH / 2,
|
|
46924
|
+
w,
|
|
46925
|
+
h: poiLabH
|
|
46926
|
+
};
|
|
46927
|
+
return rect.x >= 0 && rect.x + rect.w <= width && !collides(rect);
|
|
46928
|
+
};
|
|
46929
|
+
const GROUP_R = 30;
|
|
46930
|
+
const groups = [];
|
|
46931
|
+
for (const p of ordered) {
|
|
46932
|
+
const near = groups.find(
|
|
46933
|
+
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
46934
|
+
);
|
|
46935
|
+
if (near) near.push(p);
|
|
46936
|
+
else groups.push([p]);
|
|
46937
|
+
}
|
|
46938
|
+
const ROW_GAP2 = 3;
|
|
46939
|
+
const step = poiLabH + ROW_GAP2;
|
|
46940
|
+
const COL_GAP = 16;
|
|
46941
|
+
const placeColumn = (group) => {
|
|
46942
|
+
const items = group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
46943
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
46944
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
46945
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
46946
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
46947
|
+
const side = right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
46948
|
+
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
46949
|
+
const totalH = items.length * step;
|
|
46950
|
+
let startY = cyMid - totalH / 2;
|
|
46951
|
+
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
46952
|
+
items.forEach((o, i) => {
|
|
46953
|
+
const rowCy = startY + i * step + step / 2;
|
|
46954
|
+
obstacles.push({
|
|
46955
|
+
x: side === "right" ? colX : colX - o.w,
|
|
46956
|
+
y: rowCy - poiLabH / 2,
|
|
46957
|
+
w: o.w,
|
|
46958
|
+
h: poiLabH
|
|
46959
|
+
});
|
|
46316
46960
|
labels.push({
|
|
46317
|
-
x:
|
|
46318
|
-
y:
|
|
46319
|
-
text,
|
|
46320
|
-
anchor: "start",
|
|
46961
|
+
x: colX,
|
|
46962
|
+
y: rowCy + FONT / 3,
|
|
46963
|
+
text: o.text,
|
|
46964
|
+
anchor: side === "right" ? "start" : "end",
|
|
46321
46965
|
color: palette.text,
|
|
46322
46966
|
halo: true,
|
|
46323
|
-
|
|
46967
|
+
haloColor: palette.bg,
|
|
46968
|
+
leader: {
|
|
46969
|
+
x1: o.p.cx,
|
|
46970
|
+
y1: o.p.cy,
|
|
46971
|
+
x2: side === "right" ? colX - 2 : colX + 2,
|
|
46972
|
+
y2: rowCy
|
|
46973
|
+
},
|
|
46974
|
+
leaderColor: o.p.fill,
|
|
46975
|
+
poiId: o.p.id,
|
|
46976
|
+
lineNumber: o.p.lineNumber
|
|
46324
46977
|
});
|
|
46325
|
-
|
|
46326
|
-
|
|
46327
|
-
|
|
46328
|
-
|
|
46329
|
-
|
|
46330
|
-
|
|
46331
|
-
|
|
46332
|
-
|
|
46333
|
-
|
|
46334
|
-
|
|
46335
|
-
|
|
46336
|
-
|
|
46337
|
-
|
|
46338
|
-
if (rect.x < 0 || rect.x + rect.w > width || rect.y < 0 || rect.y + rect.h > height) {
|
|
46339
|
-
continue;
|
|
46340
|
-
}
|
|
46341
|
-
if (collides(rect)) continue;
|
|
46342
|
-
obstacles.push(rect);
|
|
46343
|
-
labels.push({
|
|
46344
|
-
x: cx,
|
|
46345
|
-
y: cy + FONT / 3,
|
|
46346
|
-
text,
|
|
46347
|
-
anchor: dx >= 0 ? "start" : "end",
|
|
46348
|
-
color: palette.text,
|
|
46349
|
-
halo: true,
|
|
46350
|
-
leader: { x1: p.cx, y1: p.cy, x2: cx, y2: cy },
|
|
46351
|
-
lineNumber: p.lineNumber
|
|
46352
|
-
});
|
|
46353
|
-
placed = true;
|
|
46354
|
-
break;
|
|
46978
|
+
});
|
|
46979
|
+
};
|
|
46980
|
+
for (const g of groups) {
|
|
46981
|
+
if (g.length === 1) {
|
|
46982
|
+
const p = g[0];
|
|
46983
|
+
const { text, w } = labelInfo(p);
|
|
46984
|
+
if (inlineFits(p, w, "right")) {
|
|
46985
|
+
pushInline(p, text, w, "right");
|
|
46986
|
+
continue;
|
|
46987
|
+
}
|
|
46988
|
+
if (inlineFits(p, w, "left")) {
|
|
46989
|
+
pushInline(p, text, w, "left");
|
|
46990
|
+
continue;
|
|
46355
46991
|
}
|
|
46356
46992
|
}
|
|
46357
|
-
|
|
46358
|
-
pinCounter += 1;
|
|
46359
|
-
pinList.push({ pin: pinCounter, label: text });
|
|
46360
|
-
labels.push({
|
|
46361
|
-
x: p.cx + p.r + 2,
|
|
46362
|
-
y: p.cy - p.r,
|
|
46363
|
-
text: String(pinCounter),
|
|
46364
|
-
anchor: "start",
|
|
46365
|
-
color: palette.text,
|
|
46366
|
-
halo: true,
|
|
46367
|
-
pin: pinCounter,
|
|
46368
|
-
lineNumber: p.lineNumber
|
|
46369
|
-
});
|
|
46993
|
+
placeColumn(g);
|
|
46370
46994
|
}
|
|
46371
46995
|
}
|
|
46372
46996
|
let legend = null;
|
|
@@ -46375,8 +46999,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46375
46999
|
name: g.name,
|
|
46376
47000
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
46377
47001
|
}));
|
|
46378
|
-
|
|
46379
|
-
if (hasAnything) {
|
|
47002
|
+
if (tagGroups.length > 0 || hasRamp) {
|
|
46380
47003
|
legend = {
|
|
46381
47004
|
tagGroups,
|
|
46382
47005
|
activeGroup,
|
|
@@ -46387,20 +47010,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46387
47010
|
},
|
|
46388
47011
|
min: rampMin,
|
|
46389
47012
|
max: rampMax,
|
|
46390
|
-
hue: rampHue
|
|
46391
|
-
|
|
46392
|
-
},
|
|
46393
|
-
...sizeVals.length > 0 && {
|
|
46394
|
-
size: {
|
|
46395
|
-
...resolved.directives.sizeMetric !== void 0 && {
|
|
46396
|
-
metric: resolved.directives.sizeMetric
|
|
46397
|
-
},
|
|
46398
|
-
min: sizeMin,
|
|
46399
|
-
max: sizeMax
|
|
47013
|
+
hue: rampHue,
|
|
47014
|
+
base: rampBase
|
|
46400
47015
|
}
|
|
46401
|
-
},
|
|
46402
|
-
...weightVals.length > 0 && {
|
|
46403
|
-
weight: { min: wMin, max: wMax }
|
|
46404
47016
|
}
|
|
46405
47017
|
};
|
|
46406
47018
|
}
|
|
@@ -46408,26 +47020,28 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46408
47020
|
return {
|
|
46409
47021
|
width,
|
|
46410
47022
|
height,
|
|
46411
|
-
background:
|
|
47023
|
+
background: water,
|
|
46412
47024
|
title: resolved.title,
|
|
46413
47025
|
...resolved.subtitle !== void 0 && { subtitle: resolved.subtitle },
|
|
46414
47026
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
46415
47027
|
regions,
|
|
47028
|
+
rivers,
|
|
46416
47029
|
legs,
|
|
46417
47030
|
pois,
|
|
46418
47031
|
labels,
|
|
46419
|
-
|
|
46420
|
-
|
|
47032
|
+
legend,
|
|
47033
|
+
insets,
|
|
47034
|
+
insetRegions
|
|
46421
47035
|
};
|
|
46422
47036
|
}
|
|
46423
|
-
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT,
|
|
47037
|
+
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT, COLO_EPS, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT, RIVER_WIDTH, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, COLO_R, GOLDEN_ANGLE, FAN_STEP, ARC_CURVE_FRAC, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, US_NON_CONUS;
|
|
46424
47038
|
var init_layout15 = __esm({
|
|
46425
47039
|
"src/map/layout.ts"() {
|
|
46426
47040
|
"use strict";
|
|
46427
47041
|
init_color_utils();
|
|
46428
|
-
init_tag_groups();
|
|
46429
47042
|
init_label_layout();
|
|
46430
47043
|
init_legend_constants();
|
|
47044
|
+
init_title_constants();
|
|
46431
47045
|
FIT_PAD = 24;
|
|
46432
47046
|
RAMP_FLOOR = 15;
|
|
46433
47047
|
R_DEFAULT = 6;
|
|
@@ -46436,23 +47050,32 @@ var init_layout15 = __esm({
|
|
|
46436
47050
|
W_MIN = 1.25;
|
|
46437
47051
|
W_MAX = 8;
|
|
46438
47052
|
FONT = 11;
|
|
46439
|
-
LEADER_STEP = 14;
|
|
46440
47053
|
COLO_EPS = 1.5;
|
|
47054
|
+
LAND_TINT_LIGHT = 58;
|
|
47055
|
+
LAND_TINT_DARK = 75;
|
|
47056
|
+
TAG_TINT_LIGHT = 60;
|
|
47057
|
+
TAG_TINT_DARK = 68;
|
|
47058
|
+
WATER_TINT = 55;
|
|
47059
|
+
RIVER_WIDTH = 1.3;
|
|
47060
|
+
FOREIGN_TINT_LIGHT = 30;
|
|
47061
|
+
FOREIGN_TINT_DARK = 62;
|
|
46441
47062
|
COLO_R = 9;
|
|
46442
47063
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
46443
47064
|
FAN_STEP = 16;
|
|
46444
|
-
TINY_REGION_AREA = 600;
|
|
46445
47065
|
ARC_CURVE_FRAC = 0.18;
|
|
46446
|
-
|
|
46447
|
-
|
|
46448
|
-
|
|
46449
|
-
|
|
46450
|
-
|
|
46451
|
-
|
|
46452
|
-
|
|
46453
|
-
|
|
46454
|
-
|
|
46455
|
-
|
|
47066
|
+
usConusProjection = () => geoConicEqualArea().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47067
|
+
alaskaProjection = () => geoConicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47068
|
+
hawaiiProjection = () => geoMercator();
|
|
47069
|
+
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
47070
|
+
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47071
|
+
"US-AK",
|
|
47072
|
+
"US-HI",
|
|
47073
|
+
"US-AS",
|
|
47074
|
+
"US-GU",
|
|
47075
|
+
"US-MP",
|
|
47076
|
+
"US-PR",
|
|
47077
|
+
"US-VI"
|
|
47078
|
+
]);
|
|
46456
47079
|
}
|
|
46457
47080
|
});
|
|
46458
47081
|
|
|
@@ -46463,7 +47086,7 @@ __export(renderer_exports16, {
|
|
|
46463
47086
|
renderMapForExport: () => renderMapForExport
|
|
46464
47087
|
});
|
|
46465
47088
|
import * as d3Selection18 from "d3-selection";
|
|
46466
|
-
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims) {
|
|
47089
|
+
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
46467
47090
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
46468
47091
|
const width = exportDims?.width ?? container.clientWidth;
|
|
46469
47092
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -46474,27 +47097,29 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46474
47097
|
{ width, height },
|
|
46475
47098
|
{
|
|
46476
47099
|
palette,
|
|
46477
|
-
isDark
|
|
47100
|
+
isDark,
|
|
47101
|
+
...activeGroupOverride !== void 0 && {
|
|
47102
|
+
activeGroup: activeGroupOverride
|
|
47103
|
+
}
|
|
46478
47104
|
}
|
|
46479
47105
|
);
|
|
46480
|
-
const svg = d3Selection18.select(container).append("svg").attr("width", width).attr("height", height).attr("viewBox", `0 0 ${width} ${height}`).attr("preserveAspectRatio", "xMidYMin meet").attr("xmlns", "http://www.w3.org/2000/svg").style("font-family", FONT_FAMILY);
|
|
47106
|
+
const svg = d3Selection18.select(container).append("svg").attr("width", width).attr("height", height).attr("viewBox", `0 0 ${width} ${height}`).attr("preserveAspectRatio", "xMidYMin meet").attr("xmlns", "http://www.w3.org/2000/svg").style("font-family", FONT_FAMILY).style("background", layout.background);
|
|
46481
47107
|
svg.append("rect").attr("width", width).attr("height", height).attr("fill", layout.background);
|
|
46482
|
-
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
46483
47108
|
const defs = svg.append("defs");
|
|
46484
|
-
|
|
46485
|
-
const haloColor =
|
|
46486
|
-
if (layout.title) {
|
|
46487
|
-
svg.append("text").attr("x", width / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("fill", palette.text).text(layout.title);
|
|
46488
|
-
}
|
|
46489
|
-
if (layout.subtitle) {
|
|
46490
|
-
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).text(layout.subtitle);
|
|
46491
|
-
}
|
|
46492
|
-
if (layout.caption) {
|
|
46493
|
-
svg.append("text").attr("x", width / 2).attr("y", height - 8).attr("text-anchor", "middle").attr("font-size", LABEL_FONT).attr("fill", palette.textMuted).text(layout.caption);
|
|
46494
|
-
}
|
|
47109
|
+
const arrowSize = (w) => Math.min(15, 7 + w * 0.95);
|
|
47110
|
+
const haloColor = palette.bg;
|
|
46495
47111
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
46496
|
-
|
|
46497
|
-
const p =
|
|
47112
|
+
const drawRegion = (g, r, strokeWidth) => {
|
|
47113
|
+
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
47114
|
+
if (r.layer !== "base") {
|
|
47115
|
+
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47116
|
+
if (r.score !== void 0) p.attr("data-score", r.score);
|
|
47117
|
+
if (r.tags) {
|
|
47118
|
+
for (const [group, value] of Object.entries(r.tags)) {
|
|
47119
|
+
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
47120
|
+
}
|
|
47121
|
+
}
|
|
47122
|
+
}
|
|
46498
47123
|
if (r.lineNumber >= 0) {
|
|
46499
47124
|
p.attr("data-line-number", r.lineNumber);
|
|
46500
47125
|
if (onClickItem) {
|
|
@@ -46504,11 +47129,31 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46504
47129
|
);
|
|
46505
47130
|
}
|
|
46506
47131
|
}
|
|
47132
|
+
};
|
|
47133
|
+
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
47134
|
+
if (layout.rivers.length) {
|
|
47135
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47136
|
+
for (const r of layout.rivers) {
|
|
47137
|
+
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
47138
|
+
}
|
|
47139
|
+
}
|
|
47140
|
+
if (layout.insets.length) {
|
|
47141
|
+
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47142
|
+
for (const box of layout.insets) {
|
|
47143
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47144
|
+
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");
|
|
47145
|
+
}
|
|
47146
|
+
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
46507
47147
|
}
|
|
46508
47148
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
46509
|
-
|
|
47149
|
+
layout.legs.forEach((leg, i) => {
|
|
46510
47150
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
46511
|
-
if (leg.arrow)
|
|
47151
|
+
if (leg.arrow) {
|
|
47152
|
+
const id = `dgmo-map-arrow-${i}`;
|
|
47153
|
+
const s = arrowSize(leg.width);
|
|
47154
|
+
defs.append("marker").attr("id", id).attr("viewBox", "0 0 10 10").attr("refX", 10).attr("refY", 5).attr("markerUnits", "userSpaceOnUse").attr("markerWidth", s).attr("markerHeight", s).attr("orient", "auto-start-reverse").append("path").attr("d", "M0,0L10,5L0,10z").attr("fill", leg.color);
|
|
47155
|
+
p.attr("marker-end", `url(#${id})`);
|
|
47156
|
+
}
|
|
46512
47157
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
46513
47158
|
emitText(
|
|
46514
47159
|
gLegs,
|
|
@@ -46522,13 +47167,13 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46522
47167
|
LABEL_FONT - 1
|
|
46523
47168
|
);
|
|
46524
47169
|
}
|
|
46525
|
-
}
|
|
47170
|
+
});
|
|
46526
47171
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
46527
47172
|
for (const poi of layout.pois) {
|
|
46528
47173
|
if (poi.isOrigin) {
|
|
46529
47174
|
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);
|
|
46530
47175
|
}
|
|
46531
|
-
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);
|
|
47176
|
+
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);
|
|
46532
47177
|
if (onClickItem) {
|
|
46533
47178
|
c.style("cursor", "pointer").on(
|
|
46534
47179
|
"click",
|
|
@@ -46552,48 +47197,66 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46552
47197
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
46553
47198
|
for (const lab of layout.labels) {
|
|
46554
47199
|
if (lab.leader) {
|
|
46555
|
-
gLabels.append("line").attr("x1", lab.leader.x1).attr("y1", lab.leader.y1).attr("x2", lab.leader.x2).attr("y2", lab.leader.y2).attr(
|
|
47200
|
+
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(
|
|
47201
|
+
"stroke",
|
|
47202
|
+
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47203
|
+
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47204
|
+
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
46556
47205
|
}
|
|
46557
|
-
|
|
46558
|
-
gLabels.append("rect").attr("x", lab.x - 1).attr("y", lab.y - LABEL_FONT).attr("width", LABEL_FONT * 1.3).attr("height", LABEL_FONT * 1.3).attr("rx", 2).attr("fill", palette.surface).attr("stroke", palette.border);
|
|
46559
|
-
}
|
|
46560
|
-
emitText(
|
|
47206
|
+
const t = emitText(
|
|
46561
47207
|
gLabels,
|
|
46562
47208
|
lab.x,
|
|
46563
47209
|
lab.y,
|
|
46564
47210
|
lab.text,
|
|
46565
47211
|
lab.anchor,
|
|
46566
47212
|
lab.color,
|
|
46567
|
-
haloColor,
|
|
47213
|
+
lab.haloColor,
|
|
46568
47214
|
lab.halo,
|
|
46569
47215
|
LABEL_FONT
|
|
46570
47216
|
);
|
|
46571
|
-
|
|
46572
|
-
|
|
46573
|
-
|
|
46574
|
-
"transform",
|
|
46575
|
-
`translate(12, ${height - layout.pinList.length * 14 - 8})`
|
|
46576
|
-
);
|
|
46577
|
-
layout.pinList.forEach((entry, i) => {
|
|
46578
|
-
gPins.append("text").attr("x", 0).attr("y", i * 14).attr("font-size", LABEL_FONT - 1).attr("fill", palette.textMuted).text(`${entry.pin} \u2014 ${entry.label}`);
|
|
46579
|
-
});
|
|
47217
|
+
if (lab.poiId !== void 0) {
|
|
47218
|
+
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47219
|
+
}
|
|
46580
47220
|
}
|
|
46581
47221
|
if (layout.legend) {
|
|
46582
47222
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
46583
47223
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
46584
|
-
const
|
|
47224
|
+
const ramp = layout.legend.ramp;
|
|
47225
|
+
const scoreGroup = ramp ? {
|
|
47226
|
+
name: ramp.metric?.trim() || "Score",
|
|
47227
|
+
entries: [],
|
|
47228
|
+
gradient: {
|
|
47229
|
+
min: ramp.min,
|
|
47230
|
+
max: ramp.max,
|
|
47231
|
+
hue: ramp.hue,
|
|
47232
|
+
base: ramp.base
|
|
47233
|
+
}
|
|
47234
|
+
} : null;
|
|
47235
|
+
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47236
|
+
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
46585
47237
|
if (groups.length > 0) {
|
|
46586
47238
|
const config = {
|
|
46587
|
-
groups
|
|
47239
|
+
groups,
|
|
46588
47240
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
46589
47241
|
mode: exportDims ? "export" : "preview",
|
|
46590
|
-
showEmptyGroups: false
|
|
47242
|
+
showEmptyGroups: false,
|
|
47243
|
+
// Keep inactive siblings visible as pills so the user can click to flip
|
|
47244
|
+
// the active colouring dimension (preview only — export shows just the
|
|
47245
|
+
// active group).
|
|
47246
|
+
showInactivePills: true
|
|
46591
47247
|
};
|
|
46592
47248
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
46593
47249
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
46594
47250
|
}
|
|
46595
|
-
|
|
46596
|
-
|
|
47251
|
+
}
|
|
47252
|
+
if (layout.title) {
|
|
47253
|
+
svg.append("text").attr("x", width / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("fill", palette.text).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.title);
|
|
47254
|
+
}
|
|
47255
|
+
if (layout.subtitle) {
|
|
47256
|
+
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);
|
|
47257
|
+
}
|
|
47258
|
+
if (layout.caption) {
|
|
47259
|
+
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);
|
|
46597
47260
|
}
|
|
46598
47261
|
}
|
|
46599
47262
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
@@ -46604,54 +47267,7 @@ function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
|
46604
47267
|
if (withHalo) {
|
|
46605
47268
|
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7);
|
|
46606
47269
|
}
|
|
46607
|
-
|
|
46608
|
-
function emitExtraLegend(svg, layout, palette, height, bottomGap) {
|
|
46609
|
-
const { legend } = layout;
|
|
46610
|
-
if (!legend) return;
|
|
46611
|
-
if (!legend.ramp && !legend.size && !legend.weight) return;
|
|
46612
|
-
const blocks = [];
|
|
46613
|
-
const g = svg.append("g").attr("class", "dgmo-map-legend-keys").attr("transform", `translate(12, ${height - 56 - bottomGap})`);
|
|
46614
|
-
let xCursor = 0;
|
|
46615
|
-
if (legend.ramp) {
|
|
46616
|
-
const ramp = legend.ramp;
|
|
46617
|
-
blocks.push(() => {
|
|
46618
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46619
|
-
const gradId = "dgmo-map-ramp";
|
|
46620
|
-
const grad = block.append("defs").append("linearGradient").attr("id", gradId).attr("x1", "0%").attr("x2", "100%");
|
|
46621
|
-
grad.append("stop").attr("offset", "0%").attr("stop-color", mix(ramp.hue, palette.bg, 15));
|
|
46622
|
-
grad.append("stop").attr("offset", "100%").attr("stop-color", ramp.hue);
|
|
46623
|
-
block.append("rect").attr("width", 80).attr("height", 8).attr("fill", `url(#${gradId})`);
|
|
46624
|
-
block.append("text").attr("x", 0).attr("y", 22).attr("font-size", 9).attr("fill", palette.textMuted).text(String(ramp.min));
|
|
46625
|
-
block.append("text").attr("x", 80).attr("y", 22).attr("text-anchor", "end").attr("font-size", 9).attr("fill", palette.textMuted).text(String(ramp.max));
|
|
46626
|
-
if (ramp.metric) {
|
|
46627
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(ramp.metric);
|
|
46628
|
-
}
|
|
46629
|
-
xCursor += 110;
|
|
46630
|
-
});
|
|
46631
|
-
}
|
|
46632
|
-
if (legend.size) {
|
|
46633
|
-
const sz = legend.size;
|
|
46634
|
-
blocks.push(() => {
|
|
46635
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46636
|
-
[3, 6, 10].forEach((r, i) => {
|
|
46637
|
-
block.append("circle").attr("cx", i * 26 + r).attr("cy", 8).attr("r", r).attr("fill", "none").attr("stroke", palette.textMuted);
|
|
46638
|
-
});
|
|
46639
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(sz.metric ?? "size");
|
|
46640
|
-
xCursor += 110;
|
|
46641
|
-
});
|
|
46642
|
-
}
|
|
46643
|
-
if (legend.weight) {
|
|
46644
|
-
const wt = legend.weight;
|
|
46645
|
-
blocks.push(() => {
|
|
46646
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46647
|
-
[1, 3, 6].forEach((w, i) => {
|
|
46648
|
-
block.append("line").attr("x1", i * 26).attr("y1", 8).attr("x2", i * 26 + 20).attr("y2", 8).attr("stroke", palette.textMuted).attr("stroke-width", w);
|
|
46649
|
-
});
|
|
46650
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(wt.metric ?? "weight");
|
|
46651
|
-
xCursor += 110;
|
|
46652
|
-
});
|
|
46653
|
-
}
|
|
46654
|
-
for (const draw of blocks) draw();
|
|
47270
|
+
return t;
|
|
46655
47271
|
}
|
|
46656
47272
|
var LABEL_FONT;
|
|
46657
47273
|
var init_renderer16 = __esm({
|
|
@@ -53123,18 +53739,18 @@ function getRotateFn(mode) {
|
|
|
53123
53739
|
return () => 0;
|
|
53124
53740
|
}
|
|
53125
53741
|
function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
|
|
53126
|
-
return new Promise((
|
|
53742
|
+
return new Promise((resolve) => {
|
|
53127
53743
|
d3Selection23.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
53128
53744
|
const { words, cloudOptions } = parsed;
|
|
53129
53745
|
const title = parsed.noTitle ? null : parsed.title;
|
|
53130
53746
|
if (words.length === 0) {
|
|
53131
|
-
|
|
53747
|
+
resolve();
|
|
53132
53748
|
return;
|
|
53133
53749
|
}
|
|
53134
53750
|
const width = exportDims?.width ?? container.clientWidth;
|
|
53135
53751
|
const height = exportDims?.height ?? container.clientHeight;
|
|
53136
53752
|
if (width <= 0 || height <= 0) {
|
|
53137
|
-
|
|
53753
|
+
resolve();
|
|
53138
53754
|
return;
|
|
53139
53755
|
}
|
|
53140
53756
|
const titleHeight = title ? 40 : 0;
|
|
@@ -53163,7 +53779,7 @@ function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
|
|
|
53163
53779
|
"transform",
|
|
53164
53780
|
(d) => `translate(${d.x},${d.y}) rotate(${d.rotate})`
|
|
53165
53781
|
).text((d) => d.text);
|
|
53166
|
-
|
|
53782
|
+
resolve();
|
|
53167
53783
|
}).start();
|
|
53168
53784
|
});
|
|
53169
53785
|
}
|