@diagrammo/dgmo 0.19.0 → 0.20.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/dist/advanced.cjs +919 -298
- package/dist/advanced.d.cts +148 -54
- package/dist/advanced.d.ts +148 -54
- package/dist/advanced.js +922 -300
- package/dist/auto.cjs +904 -297
- package/dist/auto.js +117 -117
- package/dist/auto.mjs +909 -299
- package/dist/cli.cjs +159 -159
- package/dist/index.cjs +903 -296
- package/dist/index.js +908 -298
- package/dist/internal.cjs +919 -298
- package/dist/internal.d.cts +148 -54
- package/dist/internal.d.ts +148 -54
- package/dist/internal.js +922 -300
- 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 +6 -2
- 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 +29 -2
- 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/auto.cjs
CHANGED
|
@@ -53,6 +53,33 @@ function rectCircleOverlap(rect, circle) {
|
|
|
53
53
|
const dy = nearestY - circle.cy;
|
|
54
54
|
return dx * dx + dy * dy < circle.r * circle.r;
|
|
55
55
|
}
|
|
56
|
+
function segmentRectOverlap(x0, y0, x1, y1, rect) {
|
|
57
|
+
const dx = x1 - x0;
|
|
58
|
+
const dy = y1 - y0;
|
|
59
|
+
let t0 = 0;
|
|
60
|
+
let t1 = 1;
|
|
61
|
+
const edges = [
|
|
62
|
+
[-dx, x0 - rect.x],
|
|
63
|
+
[dx, rect.x + rect.w - x0],
|
|
64
|
+
[-dy, y0 - rect.y],
|
|
65
|
+
[dy, rect.y + rect.h - y0]
|
|
66
|
+
];
|
|
67
|
+
for (const [p, q] of edges) {
|
|
68
|
+
if (p === 0) {
|
|
69
|
+
if (q < 0) return false;
|
|
70
|
+
} else {
|
|
71
|
+
const t = q / p;
|
|
72
|
+
if (p < 0) {
|
|
73
|
+
if (t > t1) return false;
|
|
74
|
+
if (t > t0) t0 = t;
|
|
75
|
+
} else {
|
|
76
|
+
if (t < t0) return false;
|
|
77
|
+
if (t < t1) t1 = t;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
56
83
|
function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius, fontSize) {
|
|
57
84
|
const labelHeight = fontSize + 4;
|
|
58
85
|
const stepSize = labelHeight + 2;
|
|
@@ -3181,6 +3208,57 @@ var init_legend_constants = __esm({
|
|
|
3181
3208
|
});
|
|
3182
3209
|
|
|
3183
3210
|
// src/utils/legend-layout.ts
|
|
3211
|
+
function fmtRamp(n) {
|
|
3212
|
+
return Number.isInteger(n) ? String(n) : String(Math.round(n * 10) / 10);
|
|
3213
|
+
}
|
|
3214
|
+
function gradientCapsuleWidth(name, gradient) {
|
|
3215
|
+
const pw = pillWidth(name);
|
|
3216
|
+
const minW = measureLegendText(fmtRamp(gradient.min), LEGEND_ENTRY_FONT_SIZE);
|
|
3217
|
+
const maxW = measureLegendText(fmtRamp(gradient.max), LEGEND_ENTRY_FONT_SIZE);
|
|
3218
|
+
return LEGEND_CAPSULE_PAD + pw + 4 + minW + RAMP_LABEL_GAP + RAMP_LEGEND_W + RAMP_LABEL_GAP + maxW + LEGEND_CAPSULE_PAD;
|
|
3219
|
+
}
|
|
3220
|
+
function buildGradientCapsuleLayout(group, gradient) {
|
|
3221
|
+
const pw = pillWidth(group.name);
|
|
3222
|
+
const minText = fmtRamp(gradient.min);
|
|
3223
|
+
const maxText = fmtRamp(gradient.max);
|
|
3224
|
+
const minW = measureLegendText(minText, LEGEND_ENTRY_FONT_SIZE);
|
|
3225
|
+
const gx = LEGEND_CAPSULE_PAD + pw + 4;
|
|
3226
|
+
const minX = gx;
|
|
3227
|
+
const rampX = gx + minW + RAMP_LABEL_GAP;
|
|
3228
|
+
const maxX = rampX + RAMP_LEGEND_W + RAMP_LABEL_GAP;
|
|
3229
|
+
const width = gradientCapsuleWidth(group.name, gradient);
|
|
3230
|
+
return {
|
|
3231
|
+
groupName: group.name,
|
|
3232
|
+
x: 0,
|
|
3233
|
+
y: 0,
|
|
3234
|
+
width,
|
|
3235
|
+
height: LEGEND_HEIGHT,
|
|
3236
|
+
pill: {
|
|
3237
|
+
groupName: group.name,
|
|
3238
|
+
x: LEGEND_CAPSULE_PAD,
|
|
3239
|
+
y: LEGEND_CAPSULE_PAD,
|
|
3240
|
+
width: pw,
|
|
3241
|
+
height: LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2,
|
|
3242
|
+
isActive: true
|
|
3243
|
+
},
|
|
3244
|
+
entries: [],
|
|
3245
|
+
gradient: {
|
|
3246
|
+
rampX,
|
|
3247
|
+
rampY: (LEGEND_HEIGHT - RAMP_LEGEND_H) / 2,
|
|
3248
|
+
rampW: RAMP_LEGEND_W,
|
|
3249
|
+
rampH: RAMP_LEGEND_H,
|
|
3250
|
+
min: gradient.min,
|
|
3251
|
+
max: gradient.max,
|
|
3252
|
+
minText,
|
|
3253
|
+
minX,
|
|
3254
|
+
maxText,
|
|
3255
|
+
maxX,
|
|
3256
|
+
textY: LEGEND_HEIGHT / 2,
|
|
3257
|
+
hue: gradient.hue,
|
|
3258
|
+
base: gradient.base
|
|
3259
|
+
}
|
|
3260
|
+
};
|
|
3261
|
+
}
|
|
3184
3262
|
function pillWidth(name) {
|
|
3185
3263
|
return measureLegendText(name, LEGEND_PILL_FONT_SIZE) + LEGEND_PILL_PAD;
|
|
3186
3264
|
}
|
|
@@ -3323,7 +3401,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3323
3401
|
};
|
|
3324
3402
|
}
|
|
3325
3403
|
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3326
|
-
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0);
|
|
3404
|
+
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3327
3405
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3328
3406
|
return {
|
|
3329
3407
|
height: 0,
|
|
@@ -3402,7 +3480,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3402
3480
|
groupAvailW,
|
|
3403
3481
|
config.capsulePillAddonWidth ?? 0
|
|
3404
3482
|
);
|
|
3405
|
-
} else if (!activeGroupName) {
|
|
3483
|
+
} else if (!activeGroupName || config.showInactivePills) {
|
|
3406
3484
|
const pw = pillWidth(g.name);
|
|
3407
3485
|
pills.push({
|
|
3408
3486
|
groupName: g.name,
|
|
@@ -3440,6 +3518,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3440
3518
|
};
|
|
3441
3519
|
}
|
|
3442
3520
|
function buildCapsuleLayout(group, containerWidth, addonWidth = 0) {
|
|
3521
|
+
if (group.gradient) return buildGradientCapsuleLayout(group, group.gradient);
|
|
3443
3522
|
const pw = pillWidth(group.name);
|
|
3444
3523
|
const info = capsuleWidth(
|
|
3445
3524
|
group.name,
|
|
@@ -3610,7 +3689,7 @@ function getMaxLegendReservedHeight(config, containerWidth) {
|
|
|
3610
3689
|
}
|
|
3611
3690
|
return max;
|
|
3612
3691
|
}
|
|
3613
|
-
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
|
|
3692
|
+
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP, RAMP_LEGEND_W, RAMP_LEGEND_H, RAMP_LABEL_GAP;
|
|
3614
3693
|
var init_legend_layout = __esm({
|
|
3615
3694
|
"src/utils/legend-layout.ts"() {
|
|
3616
3695
|
"use strict";
|
|
@@ -3619,6 +3698,9 @@ var init_legend_layout = __esm({
|
|
|
3619
3698
|
CONTROL_FONT_SIZE = 11;
|
|
3620
3699
|
CONTROL_ICON_GAP = 4;
|
|
3621
3700
|
CONTROL_GAP = 8;
|
|
3701
|
+
RAMP_LEGEND_W = 80;
|
|
3702
|
+
RAMP_LEGEND_H = 8;
|
|
3703
|
+
RAMP_LABEL_GAP = 6;
|
|
3622
3704
|
}
|
|
3623
3705
|
});
|
|
3624
3706
|
|
|
@@ -3706,6 +3788,16 @@ function renderCapsule(parent, capsule, palette, groupBg, pillBorder, _isDark, c
|
|
|
3706
3788
|
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);
|
|
3707
3789
|
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);
|
|
3708
3790
|
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);
|
|
3791
|
+
if (capsule.gradient) {
|
|
3792
|
+
const gr = capsule.gradient;
|
|
3793
|
+
const gradId = `dgmo-legend-ramp-${capsule.groupName.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
3794
|
+
const def = g.append("defs").append("linearGradient").attr("id", gradId);
|
|
3795
|
+
def.append("stop").attr("offset", "0%").attr("stop-color", mix(gr.hue, gr.base, 15));
|
|
3796
|
+
def.append("stop").attr("offset", "100%").attr("stop-color", gr.hue);
|
|
3797
|
+
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);
|
|
3798
|
+
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})`);
|
|
3799
|
+
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);
|
|
3800
|
+
}
|
|
3709
3801
|
for (const entry of capsule.entries) {
|
|
3710
3802
|
const entryG = g.append("g").attr("data-legend-entry", entry.value.toLowerCase()).attr("data-series-name", entry.value).style("cursor", "pointer");
|
|
3711
3803
|
entryG.append("circle").attr("cx", entry.dotCx).attr("cy", entry.dotCy).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
|
|
@@ -11179,23 +11271,22 @@ function parseC4(content, palette) {
|
|
|
11179
11271
|
}
|
|
11180
11272
|
}
|
|
11181
11273
|
const parent = findParentElement(indent, stack);
|
|
11182
|
-
|
|
11183
|
-
|
|
11274
|
+
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
11275
|
+
if (parent && descResult.isKeyword) {
|
|
11184
11276
|
if (descResult.needsColon) {
|
|
11185
11277
|
pushError(
|
|
11186
11278
|
lineNumber,
|
|
11187
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11279
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`,
|
|
11188
11280
|
"warning"
|
|
11189
11281
|
);
|
|
11190
11282
|
}
|
|
11191
|
-
const descText = descResult.isKeyword ? descResult.text : trimmed;
|
|
11192
11283
|
let desc = elementDescription.get(parent.element);
|
|
11193
11284
|
if (!desc) {
|
|
11194
11285
|
desc = [];
|
|
11195
11286
|
elementDescription.set(parent.element, desc);
|
|
11196
11287
|
parent.element.description = desc;
|
|
11197
11288
|
}
|
|
11198
|
-
desc.push(
|
|
11289
|
+
desc.push(descResult.text);
|
|
11199
11290
|
} else {
|
|
11200
11291
|
pushError(lineNumber, `Unexpected content: "${trimmed}"`);
|
|
11201
11292
|
}
|
|
@@ -11662,7 +11753,7 @@ function parseSitemap(content, palette) {
|
|
|
11662
11753
|
if (descResult.needsColon) {
|
|
11663
11754
|
pushWarning(
|
|
11664
11755
|
lineNumber,
|
|
11665
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11756
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
11666
11757
|
);
|
|
11667
11758
|
}
|
|
11668
11759
|
const parent = findParentNode(indent, indentStack);
|
|
@@ -12490,23 +12581,22 @@ function parseInfra(content) {
|
|
|
12490
12581
|
}
|
|
12491
12582
|
}
|
|
12492
12583
|
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
12493
|
-
if (descResult.isKeyword
|
|
12494
|
-
|
|
12495
|
-
|
|
12496
|
-
|
|
12584
|
+
if (descResult.isKeyword) {
|
|
12585
|
+
if (currentNode.isEdge) {
|
|
12586
|
+
continue;
|
|
12587
|
+
}
|
|
12497
12588
|
if (descResult.needsColon) {
|
|
12498
12589
|
warn2(
|
|
12499
12590
|
lineNumber,
|
|
12500
|
-
`Use "description: ${descResult.text}" \u2014
|
|
12591
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
12501
12592
|
);
|
|
12502
12593
|
}
|
|
12503
|
-
|
|
12504
|
-
pushDescription(currentNode, descText);
|
|
12594
|
+
pushDescription(currentNode, descResult.text);
|
|
12505
12595
|
continue;
|
|
12506
12596
|
}
|
|
12507
12597
|
warn2(
|
|
12508
12598
|
lineNumber,
|
|
12509
|
-
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or description text.`
|
|
12599
|
+
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or a description (description: text).`
|
|
12510
12600
|
);
|
|
12511
12601
|
continue;
|
|
12512
12602
|
}
|
|
@@ -15643,9 +15733,6 @@ function parseMap(content) {
|
|
|
15643
15733
|
const pushWarning = (line12, message) => {
|
|
15644
15734
|
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15645
15735
|
};
|
|
15646
|
-
const pushInfo = (line12, message) => {
|
|
15647
|
-
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15648
|
-
};
|
|
15649
15736
|
const lines = content.split("\n");
|
|
15650
15737
|
let firstIdx = 0;
|
|
15651
15738
|
while (firstIdx < lines.length) {
|
|
@@ -15775,10 +15862,15 @@ function parseMap(content) {
|
|
|
15775
15862
|
break;
|
|
15776
15863
|
case "projection":
|
|
15777
15864
|
dup(d.projection);
|
|
15778
|
-
if (value && ![
|
|
15865
|
+
if (value && ![
|
|
15866
|
+
"equirectangular",
|
|
15867
|
+
"natural-earth",
|
|
15868
|
+
"albers-usa",
|
|
15869
|
+
"mercator"
|
|
15870
|
+
].includes(value))
|
|
15779
15871
|
pushWarning(
|
|
15780
15872
|
line12,
|
|
15781
|
-
`Unknown projection "${value}" (expected natural-earth | albers-usa | mercator).`
|
|
15873
|
+
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15782
15874
|
);
|
|
15783
15875
|
d.projection = value;
|
|
15784
15876
|
break;
|
|
@@ -15917,17 +16009,21 @@ function parseMap(content) {
|
|
|
15917
16009
|
scoreNum = void 0;
|
|
15918
16010
|
}
|
|
15919
16011
|
}
|
|
15920
|
-
|
|
15921
|
-
|
|
15922
|
-
|
|
15923
|
-
|
|
15924
|
-
|
|
16012
|
+
let regionName = split.name;
|
|
16013
|
+
let regionScope;
|
|
16014
|
+
const rToks = regionName.split(/\s+/);
|
|
16015
|
+
const rLast = rToks[rToks.length - 1];
|
|
16016
|
+
if (rToks.length > 1 && SCOPE_RE.test(rLast)) {
|
|
16017
|
+
regionName = rToks.slice(0, -1).join(" ");
|
|
16018
|
+
regionScope = rLast;
|
|
16019
|
+
}
|
|
15925
16020
|
const region = {
|
|
15926
|
-
name:
|
|
16021
|
+
name: regionName,
|
|
15927
16022
|
tags,
|
|
15928
16023
|
meta,
|
|
15929
16024
|
lineNumber: line12
|
|
15930
16025
|
};
|
|
16026
|
+
if (regionScope !== void 0) region.scope = regionScope;
|
|
15931
16027
|
if (scoreNum !== void 0) region.score = scoreNum;
|
|
15932
16028
|
regions.push(region);
|
|
15933
16029
|
}
|
|
@@ -17051,7 +17147,7 @@ function parseMindmap(content, palette) {
|
|
|
17051
17147
|
if (descResult.needsColon) {
|
|
17052
17148
|
pushWarning(
|
|
17053
17149
|
lineNumber,
|
|
17054
|
-
`Use "description: ${descResult.text}" \u2014
|
|
17150
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
17055
17151
|
);
|
|
17056
17152
|
}
|
|
17057
17153
|
const parent = findMetadataParent2(indent, indentStack);
|
|
@@ -18839,7 +18935,7 @@ function parseJourneyMap(content, palette) {
|
|
|
18839
18935
|
if (descResult.needsColon) {
|
|
18840
18936
|
warn2(
|
|
18841
18937
|
lineNumber,
|
|
18842
|
-
`Use "description: ${descResult.text}" \u2014
|
|
18938
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
18843
18939
|
);
|
|
18844
18940
|
}
|
|
18845
18941
|
currentStep.description = descResult.text;
|
|
@@ -45428,7 +45524,9 @@ function resolveMap(parsed, data) {
|
|
|
45428
45524
|
const usScoped = parsed.directives.region === "us-states" || parsed.directives.defaultCountry?.toUpperCase() === "US" || parsed.regions.some((r) => {
|
|
45429
45525
|
const f = fold(r.name);
|
|
45430
45526
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45431
|
-
}) || parsed.
|
|
45527
|
+
}) || parsed.regions.some(
|
|
45528
|
+
(r) => r.scope === "US" || r.scope?.startsWith("US-")
|
|
45529
|
+
) || parsed.pois.some(
|
|
45432
45530
|
(p) => p.pos.kind === "name" && p.pos.scope?.startsWith("US-")
|
|
45433
45531
|
);
|
|
45434
45532
|
const regions = [];
|
|
@@ -45440,7 +45538,30 @@ function resolveMap(parsed, data) {
|
|
|
45440
45538
|
const inCountry = countryIndex.get(f) ?? (REGION_ALIASES[f] ? countryIndex.get(REGION_ALIASES[f]) : void 0);
|
|
45441
45539
|
const inState = usStateIndex.get(f);
|
|
45442
45540
|
let chosen = null;
|
|
45443
|
-
|
|
45541
|
+
const scope = r.scope;
|
|
45542
|
+
if (scope) {
|
|
45543
|
+
const wantsState = scope === "US" || scope.startsWith("US-");
|
|
45544
|
+
if (wantsState && inState) {
|
|
45545
|
+
if (scope.startsWith("US-") && inState.id !== scope) {
|
|
45546
|
+
err(
|
|
45547
|
+
r.lineNumber,
|
|
45548
|
+
`No subdivision "${r.name}" in scope ${scope} (it is ${inState.id}).`,
|
|
45549
|
+
"E_MAP_SCOPE_MISS"
|
|
45550
|
+
);
|
|
45551
|
+
continue;
|
|
45552
|
+
}
|
|
45553
|
+
chosen = { ...inState, layer: "us-state" };
|
|
45554
|
+
} else if (!wantsState && inCountry) {
|
|
45555
|
+
chosen = { ...inCountry, layer: "country" };
|
|
45556
|
+
} else {
|
|
45557
|
+
err(
|
|
45558
|
+
r.lineNumber,
|
|
45559
|
+
`No region "${r.name}" found in scope ${scope}.`,
|
|
45560
|
+
"E_MAP_SCOPE_MISS"
|
|
45561
|
+
);
|
|
45562
|
+
continue;
|
|
45563
|
+
}
|
|
45564
|
+
} else if (inCountry && inState) {
|
|
45444
45565
|
if (usScoped) {
|
|
45445
45566
|
chosen = { ...inState, layer: "us-state" };
|
|
45446
45567
|
} else {
|
|
@@ -45448,7 +45569,7 @@ function resolveMap(parsed, data) {
|
|
|
45448
45569
|
}
|
|
45449
45570
|
warn2(
|
|
45450
45571
|
r.lineNumber,
|
|
45451
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}).`,
|
|
45572
|
+
`"${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}").`,
|
|
45452
45573
|
"W_MAP_REGION_AMBIGUOUS"
|
|
45453
45574
|
);
|
|
45454
45575
|
} else if (inState) {
|
|
@@ -45620,9 +45741,17 @@ function resolveMap(parsed, data) {
|
|
|
45620
45741
|
};
|
|
45621
45742
|
registerPoi(id, poi, p.lineNumber);
|
|
45622
45743
|
}
|
|
45744
|
+
const declaredByName = /* @__PURE__ */ new Map();
|
|
45745
|
+
for (const p of pois) {
|
|
45746
|
+
const fn = p.name ? fold(p.name) : void 0;
|
|
45747
|
+
if (fn && fn !== p.id && !declaredByName.has(fn))
|
|
45748
|
+
declaredByName.set(fn, p.id);
|
|
45749
|
+
}
|
|
45623
45750
|
const resolveEndpoint2 = (ref, line12) => {
|
|
45624
45751
|
const f = fold(ref);
|
|
45625
45752
|
if (registry.has(f)) return f;
|
|
45753
|
+
const aliased = declaredByName.get(f);
|
|
45754
|
+
if (aliased) return aliased;
|
|
45626
45755
|
const got = lookupName(ref, void 0, line12, inferredCountry, true);
|
|
45627
45756
|
if (got.kind !== "ok") return null;
|
|
45628
45757
|
noteCountry(got.iso);
|
|
@@ -45702,23 +45831,29 @@ function resolveMap(parsed, data) {
|
|
|
45702
45831
|
[-180, -85],
|
|
45703
45832
|
[180, 85]
|
|
45704
45833
|
];
|
|
45705
|
-
|
|
45834
|
+
let extent2 = unioned ? pad(unioned, PAD_FRACTION) : DEFAULT_EXTENT;
|
|
45706
45835
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
45707
45836
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
45708
45837
|
const span = Math.max(lonSpan, latSpan);
|
|
45709
45838
|
const usDominant = (inferredCountry === "US" || subdivisions.includes("us-states")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
45710
45839
|
let projection;
|
|
45711
45840
|
const override = parsed.directives.projection;
|
|
45712
|
-
if (override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
45841
|
+
if (override === "equirectangular" || override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
45713
45842
|
projection = override;
|
|
45714
45843
|
} else if (usDominant) {
|
|
45715
45844
|
projection = "albers-usa";
|
|
45716
45845
|
} else if (span > WORLD_SPAN) {
|
|
45717
|
-
projection = "
|
|
45846
|
+
projection = "equirectangular";
|
|
45718
45847
|
} else if (span < MERCATOR_MAX_SPAN) {
|
|
45719
45848
|
projection = "mercator";
|
|
45720
45849
|
} else {
|
|
45721
|
-
projection = "
|
|
45850
|
+
projection = "equirectangular";
|
|
45851
|
+
}
|
|
45852
|
+
if (lonSpan >= 180) {
|
|
45853
|
+
extent2 = [
|
|
45854
|
+
[-180, Math.min(extent2[0][1], WORLD_LAT_SOUTH)],
|
|
45855
|
+
[180, Math.max(extent2[1][1], WORLD_LAT_NORTH)]
|
|
45856
|
+
];
|
|
45722
45857
|
}
|
|
45723
45858
|
result.regions = regions;
|
|
45724
45859
|
result.pois = pois;
|
|
@@ -45766,7 +45901,7 @@ function firstError(diags) {
|
|
|
45766
45901
|
const e = diags.find((d) => d.severity === "error");
|
|
45767
45902
|
return e ? formatDgmoError(e) : null;
|
|
45768
45903
|
}
|
|
45769
|
-
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, REGION_ALIASES;
|
|
45904
|
+
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES;
|
|
45770
45905
|
var init_resolver2 = __esm({
|
|
45771
45906
|
"src/map/resolver.ts"() {
|
|
45772
45907
|
"use strict";
|
|
@@ -45775,6 +45910,8 @@ var init_resolver2 = __esm({
|
|
|
45775
45910
|
WORLD_SPAN = 90;
|
|
45776
45911
|
MERCATOR_MAX_SPAN = 25;
|
|
45777
45912
|
PAD_FRACTION = 0.05;
|
|
45913
|
+
WORLD_LAT_SOUTH = -58;
|
|
45914
|
+
WORLD_LAT_NORTH = 78;
|
|
45778
45915
|
REGION_ALIASES = {
|
|
45779
45916
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
45780
45917
|
"united states": "united states of america",
|
|
@@ -45839,13 +45976,36 @@ function moduleBaseDir() {
|
|
|
45839
45976
|
function loadMapData() {
|
|
45840
45977
|
cache ??= (async () => {
|
|
45841
45978
|
const dir = await firstExistingDir(moduleBaseDir());
|
|
45842
|
-
const [
|
|
45979
|
+
const [
|
|
45980
|
+
worldCoarse,
|
|
45981
|
+
worldDetail,
|
|
45982
|
+
usStates,
|
|
45983
|
+
lakes,
|
|
45984
|
+
rivers,
|
|
45985
|
+
naLand,
|
|
45986
|
+
naLakes,
|
|
45987
|
+
gazetteer
|
|
45988
|
+
] = await Promise.all([
|
|
45843
45989
|
readJson(dir, FILES.worldCoarse),
|
|
45844
45990
|
readJson(dir, FILES.worldDetail),
|
|
45845
45991
|
readJson(dir, FILES.usStates),
|
|
45992
|
+
// Lakes/rivers/NA assets are optional — older bundles may predate them.
|
|
45993
|
+
readJson(dir, FILES.lakes).catch(() => void 0),
|
|
45994
|
+
readJson(dir, FILES.rivers).catch(() => void 0),
|
|
45995
|
+
readJson(dir, FILES.naLand).catch(() => void 0),
|
|
45996
|
+
readJson(dir, FILES.naLakes).catch(() => void 0),
|
|
45846
45997
|
readJson(dir, FILES.gazetteer)
|
|
45847
45998
|
]);
|
|
45848
|
-
return validate({
|
|
45999
|
+
return validate({
|
|
46000
|
+
worldCoarse,
|
|
46001
|
+
worldDetail,
|
|
46002
|
+
usStates,
|
|
46003
|
+
gazetteer,
|
|
46004
|
+
...lakes && { lakes },
|
|
46005
|
+
...rivers && { rivers },
|
|
46006
|
+
...naLand && { naLand },
|
|
46007
|
+
...naLakes && { naLakes }
|
|
46008
|
+
});
|
|
45849
46009
|
})().catch((e) => {
|
|
45850
46010
|
cache = void 0;
|
|
45851
46011
|
throw e;
|
|
@@ -45864,6 +46024,10 @@ var init_load_data = __esm({
|
|
|
45864
46024
|
worldCoarse: "world-coarse.json",
|
|
45865
46025
|
worldDetail: "world-detail.json",
|
|
45866
46026
|
usStates: "us-states.json",
|
|
46027
|
+
lakes: "lakes.json",
|
|
46028
|
+
rivers: "rivers.json",
|
|
46029
|
+
naLand: "na-land.json",
|
|
46030
|
+
naLakes: "na-lakes.json",
|
|
45867
46031
|
gazetteer: "gazetteer.json"
|
|
45868
46032
|
};
|
|
45869
46033
|
CANDIDATE_DIRS = [
|
|
@@ -45891,36 +46055,67 @@ function decodeLayer(topo) {
|
|
|
45891
46055
|
function projectionFor(family) {
|
|
45892
46056
|
switch (family) {
|
|
45893
46057
|
case "albers-usa":
|
|
45894
|
-
return (
|
|
46058
|
+
return usConusProjection();
|
|
45895
46059
|
case "mercator":
|
|
45896
46060
|
return (0, import_d3_geo2.geoMercator)();
|
|
45897
46061
|
case "natural-earth":
|
|
45898
|
-
default:
|
|
45899
46062
|
return (0, import_d3_geo2.geoNaturalEarth1)();
|
|
46063
|
+
case "equirectangular":
|
|
46064
|
+
default:
|
|
46065
|
+
return (0, import_d3_geo2.geoEquirectangular)();
|
|
45900
46066
|
}
|
|
45901
46067
|
}
|
|
46068
|
+
function mapBackgroundColor(palette) {
|
|
46069
|
+
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
46070
|
+
}
|
|
45902
46071
|
function layoutMap(resolved, data, size, opts) {
|
|
45903
46072
|
const { palette, isDark } = opts;
|
|
45904
46073
|
const { width, height } = size;
|
|
45905
|
-
const
|
|
46074
|
+
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46075
|
+
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
46076
|
+
const worldTopo = usCrisp ? data.naLand : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
45906
46077
|
const worldLayer = decodeLayer(worldTopo);
|
|
45907
|
-
const usLayer =
|
|
45908
|
-
const
|
|
45909
|
-
const
|
|
46078
|
+
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
46079
|
+
const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
|
|
46080
|
+
const neutralFill = mix(palette.colors.green, palette.bg, landTint);
|
|
46081
|
+
const water = mapBackgroundColor(palette);
|
|
46082
|
+
const usContext = usLayer !== null;
|
|
46083
|
+
const foreignFill = mix(
|
|
46084
|
+
palette.colors.gray,
|
|
46085
|
+
palette.bg,
|
|
46086
|
+
isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46087
|
+
);
|
|
46088
|
+
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
45910
46089
|
const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
|
|
45911
46090
|
const scaleOverride = resolved.directives.scale;
|
|
45912
46091
|
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
|
|
45913
46092
|
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
|
|
45914
|
-
const rampHue = palette.
|
|
46093
|
+
const rampHue = palette.colors.red;
|
|
45915
46094
|
const hasRamp = scores.length > 0;
|
|
45916
|
-
const
|
|
45917
|
-
|
|
45918
|
-
|
|
45919
|
-
|
|
46095
|
+
const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
|
|
46096
|
+
const matchColorGroup = (v) => {
|
|
46097
|
+
const lv = v.trim().toLowerCase();
|
|
46098
|
+
if (lv === "none") return null;
|
|
46099
|
+
if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
|
|
46100
|
+
return SCORE_NAME;
|
|
46101
|
+
const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
46102
|
+
return tg ? tg.name : v;
|
|
46103
|
+
};
|
|
46104
|
+
const override = opts.activeGroup;
|
|
46105
|
+
let activeGroup;
|
|
46106
|
+
if (override !== void 0) {
|
|
46107
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
46108
|
+
} else if (resolved.directives.activeTag !== void 0) {
|
|
46109
|
+
activeGroup = matchColorGroup(resolved.directives.activeTag);
|
|
46110
|
+
} else {
|
|
46111
|
+
activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46112
|
+
}
|
|
46113
|
+
const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
|
|
46114
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
45920
46115
|
const fillForScore = (s) => {
|
|
45921
46116
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
45922
46117
|
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
45923
|
-
return mix(rampHue,
|
|
46118
|
+
return mix(rampHue, rampBase, pct);
|
|
45924
46119
|
};
|
|
45925
46120
|
const tagFill = (tags, groupName) => {
|
|
45926
46121
|
if (!groupName) return null;
|
|
@@ -45934,40 +46129,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
45934
46129
|
(e) => e.value.toLowerCase() === val.toLowerCase()
|
|
45935
46130
|
);
|
|
45936
46131
|
if (!entry?.color) return null;
|
|
45937
|
-
return
|
|
46132
|
+
return mix(
|
|
46133
|
+
entry.color,
|
|
46134
|
+
palette.bg,
|
|
46135
|
+
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46136
|
+
);
|
|
46137
|
+
};
|
|
46138
|
+
const regionFill = (r) => {
|
|
46139
|
+
if (activeIsScore) {
|
|
46140
|
+
return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
|
|
46141
|
+
}
|
|
46142
|
+
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
45938
46143
|
};
|
|
45939
46144
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
45940
|
-
const
|
|
45941
|
-
for (const r of resolved.regions) {
|
|
45942
|
-
const f = r.layer === "us-state" ? usLayer?.get(r.iso) : worldLayer.get(r.iso);
|
|
45943
|
-
if (f) regionFeatures.push(f);
|
|
45944
|
-
}
|
|
45945
|
-
const extentCorners = () => {
|
|
46145
|
+
const extentOutline = () => {
|
|
45946
46146
|
const [[w, s], [e, n]] = resolved.extent;
|
|
46147
|
+
const N = 16;
|
|
46148
|
+
const coords = [];
|
|
46149
|
+
for (let i = 0; i <= N; i++) {
|
|
46150
|
+
const t = i / N;
|
|
46151
|
+
const lon = w + (e - w) * t;
|
|
46152
|
+
const lat = s + (n - s) * t;
|
|
46153
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46154
|
+
}
|
|
45947
46155
|
return {
|
|
45948
46156
|
type: "Feature",
|
|
45949
46157
|
properties: {},
|
|
45950
|
-
geometry: {
|
|
45951
|
-
type: "MultiPoint",
|
|
45952
|
-
coordinates: [
|
|
45953
|
-
[w, s],
|
|
45954
|
-
[e, s],
|
|
45955
|
-
[e, n],
|
|
45956
|
-
[w, n]
|
|
45957
|
-
]
|
|
45958
|
-
}
|
|
46158
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
45959
46159
|
};
|
|
45960
46160
|
};
|
|
45961
46161
|
let fitFeatures;
|
|
45962
|
-
if (resolved.projection === "albers-usa") {
|
|
45963
|
-
|
|
45964
|
-
else if (usLayer) fitFeatures = [...usLayer.values()];
|
|
45965
|
-
else {
|
|
45966
|
-
const us = worldLayer.get("US");
|
|
45967
|
-
fitFeatures = us ? [us] : [...worldLayer.values()];
|
|
45968
|
-
}
|
|
46162
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46163
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
45969
46164
|
} else {
|
|
45970
|
-
fitFeatures = [
|
|
46165
|
+
fitFeatures = [extentOutline()];
|
|
45971
46166
|
}
|
|
45972
46167
|
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
45973
46168
|
const projection = projectionFor(resolved.projection);
|
|
@@ -45976,32 +46171,311 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
45976
46171
|
if (centerLon > 180) centerLon -= 360;
|
|
45977
46172
|
projection.rotate([-centerLon, 0]);
|
|
45978
46173
|
}
|
|
45979
|
-
|
|
46174
|
+
const TITLE_GAP = 16;
|
|
46175
|
+
let topPad = FIT_PAD;
|
|
46176
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
46177
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46178
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP);
|
|
46179
|
+
}
|
|
46180
|
+
const fitBox = [
|
|
46181
|
+
[FIT_PAD, topPad],
|
|
45980
46182
|
[
|
|
45981
|
-
|
|
45982
|
-
|
|
45983
|
-
|
|
45984
|
-
|
|
45985
|
-
|
|
45986
|
-
|
|
45987
|
-
|
|
45988
|
-
|
|
45989
|
-
|
|
45990
|
-
|
|
46183
|
+
Math.max(FIT_PAD + 1, width - FIT_PAD),
|
|
46184
|
+
Math.max(topPad + 1, height - FIT_PAD)
|
|
46185
|
+
]
|
|
46186
|
+
];
|
|
46187
|
+
projection.fitExtent(fitBox, fitTarget);
|
|
46188
|
+
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
46189
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46190
|
+
let path;
|
|
46191
|
+
let project;
|
|
46192
|
+
if (fitIsGlobal) {
|
|
46193
|
+
const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
|
|
46194
|
+
const bx0 = cb[0][0];
|
|
46195
|
+
const by0 = cb[0][1];
|
|
46196
|
+
const cw = cb[1][0] - bx0;
|
|
46197
|
+
const ch = cb[1][1] - by0;
|
|
46198
|
+
const ox = fitBox[0][0];
|
|
46199
|
+
const oy = fitBox[0][1];
|
|
46200
|
+
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46201
|
+
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
46202
|
+
const stretch = (x, y) => [
|
|
46203
|
+
ox + (x - bx0) * sx,
|
|
46204
|
+
oy + (y - by0) * sy
|
|
46205
|
+
];
|
|
46206
|
+
const baseProjection = projection;
|
|
46207
|
+
const tx = (0, import_d3_geo2.geoTransform)({
|
|
46208
|
+
point(x, y) {
|
|
46209
|
+
const [px, py] = stretch(x, y);
|
|
46210
|
+
this.stream.point(px, py);
|
|
46211
|
+
}
|
|
46212
|
+
});
|
|
46213
|
+
path = (0, import_d3_geo2.geoPath)({
|
|
46214
|
+
stream: (s) => baseProjection.stream(
|
|
46215
|
+
tx.stream(s)
|
|
46216
|
+
)
|
|
46217
|
+
});
|
|
46218
|
+
project = (lon, lat) => {
|
|
46219
|
+
const p = baseProjection([lon, lat]);
|
|
46220
|
+
return p ? stretch(p[0], p[1]) : null;
|
|
46221
|
+
};
|
|
46222
|
+
} else {
|
|
46223
|
+
path = (0, import_d3_geo2.geoPath)(projection);
|
|
46224
|
+
project = (lon, lat) => projection([lon, lat]) ?? null;
|
|
46225
|
+
}
|
|
46226
|
+
const insets = [];
|
|
46227
|
+
const insetRegions = [];
|
|
46228
|
+
const insetLabelSeeds = [];
|
|
46229
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46230
|
+
const PAD = 8;
|
|
46231
|
+
const GAP = 12;
|
|
46232
|
+
const yB = height - FIT_PAD;
|
|
46233
|
+
const BW = 8;
|
|
46234
|
+
const coast = /* @__PURE__ */ new Map();
|
|
46235
|
+
const addPt = (lon, lat) => {
|
|
46236
|
+
const p = projection([lon, lat]);
|
|
46237
|
+
if (!p) return;
|
|
46238
|
+
const bi = Math.floor(p[0] / BW);
|
|
46239
|
+
const cur = coast.get(bi);
|
|
46240
|
+
if (cur === void 0 || p[1] > cur) coast.set(bi, p[1]);
|
|
46241
|
+
};
|
|
46242
|
+
const walk = (co) => {
|
|
46243
|
+
if (Array.isArray(co) && typeof co[0] === "number")
|
|
46244
|
+
addPt(co[0], co[1]);
|
|
46245
|
+
else if (Array.isArray(co)) for (const c of co) walk(c);
|
|
46246
|
+
};
|
|
46247
|
+
for (const [iso, f] of usLayer) {
|
|
46248
|
+
if (US_NON_CONUS.has(iso)) continue;
|
|
46249
|
+
walk(f.geometry.coordinates);
|
|
46250
|
+
}
|
|
46251
|
+
const at = (x) => {
|
|
46252
|
+
const bi = Math.floor(x / BW);
|
|
46253
|
+
let y = -Infinity;
|
|
46254
|
+
for (let k = bi - 1; k <= bi + 1; k++) {
|
|
46255
|
+
const v = coast.get(k);
|
|
46256
|
+
if (v !== void 0 && v > y) y = v;
|
|
46257
|
+
}
|
|
46258
|
+
return y;
|
|
46259
|
+
};
|
|
46260
|
+
const coastTop = (x0, xr) => {
|
|
46261
|
+
const n = 24;
|
|
46262
|
+
const pts = [];
|
|
46263
|
+
let maxY = -Infinity;
|
|
46264
|
+
for (let i = 0; i <= n; i++) {
|
|
46265
|
+
const x = x0 + (xr - x0) * i / n;
|
|
46266
|
+
const y = at(x);
|
|
46267
|
+
if (y > -Infinity) {
|
|
46268
|
+
pts.push([x, y]);
|
|
46269
|
+
if (y > maxY) maxY = y;
|
|
46270
|
+
}
|
|
46271
|
+
}
|
|
46272
|
+
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46273
|
+
let m = 0;
|
|
46274
|
+
if (pts.length >= 2) {
|
|
46275
|
+
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46276
|
+
for (const [x, y] of pts) {
|
|
46277
|
+
sx += x;
|
|
46278
|
+
sy += y;
|
|
46279
|
+
sxx += x * x;
|
|
46280
|
+
sxy += x * y;
|
|
46281
|
+
}
|
|
46282
|
+
const den = pts.length * sxx - sx * sx;
|
|
46283
|
+
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46284
|
+
}
|
|
46285
|
+
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46286
|
+
let c = -Infinity;
|
|
46287
|
+
for (const [x, y] of pts) {
|
|
46288
|
+
const need = y - m * x + GAP;
|
|
46289
|
+
if (need > c) c = need;
|
|
46290
|
+
}
|
|
46291
|
+
return (x) => m * x + c;
|
|
46292
|
+
};
|
|
46293
|
+
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46294
|
+
const f = usLayer.get(iso);
|
|
46295
|
+
if (!f) return boxX;
|
|
46296
|
+
const x0 = boxX;
|
|
46297
|
+
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46298
|
+
if (iw < 24) return boxX;
|
|
46299
|
+
const xr = x0 + iw + 2 * PAD;
|
|
46300
|
+
const top = coastTop(x0, xr);
|
|
46301
|
+
const yL = top(x0);
|
|
46302
|
+
const yR = top(xr);
|
|
46303
|
+
proj.fitWidth(iw, f);
|
|
46304
|
+
const bb = (0, import_d3_geo2.geoPath)(proj).bounds(f);
|
|
46305
|
+
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46306
|
+
const needH = sh + 2 * PAD;
|
|
46307
|
+
let topFit = Math.max(yL, yR);
|
|
46308
|
+
const bottom = Math.min(topFit + needH, yB);
|
|
46309
|
+
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46310
|
+
const lift = topFit - Math.max(yL, yR);
|
|
46311
|
+
const topL = yL + lift;
|
|
46312
|
+
const topR = yR + lift;
|
|
46313
|
+
proj.fitExtent(
|
|
46314
|
+
[
|
|
46315
|
+
[x0 + PAD, topFit + PAD],
|
|
46316
|
+
[xr - PAD, bottom - PAD]
|
|
46317
|
+
],
|
|
46318
|
+
f
|
|
46319
|
+
);
|
|
46320
|
+
const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
|
|
46321
|
+
if (!d) return xr;
|
|
46322
|
+
const r = regionById.get(iso);
|
|
46323
|
+
let fill2 = neutralFill;
|
|
46324
|
+
let lineNumber = -1;
|
|
46325
|
+
if (r?.layer === "us-state") {
|
|
46326
|
+
fill2 = regionFill(r);
|
|
46327
|
+
lineNumber = r.lineNumber;
|
|
46328
|
+
}
|
|
46329
|
+
insets.push({
|
|
46330
|
+
x: x0,
|
|
46331
|
+
y: Math.min(topL, topR),
|
|
46332
|
+
w: xr - x0,
|
|
46333
|
+
h: bottom - Math.min(topL, topR),
|
|
46334
|
+
points: [
|
|
46335
|
+
[x0, topL],
|
|
46336
|
+
[xr, topR],
|
|
46337
|
+
[xr, bottom],
|
|
46338
|
+
[x0, bottom]
|
|
46339
|
+
]
|
|
46340
|
+
});
|
|
46341
|
+
insetRegions.push({
|
|
46342
|
+
id: iso,
|
|
46343
|
+
d,
|
|
46344
|
+
fill: fill2,
|
|
46345
|
+
stroke: regionStroke,
|
|
46346
|
+
lineNumber,
|
|
46347
|
+
layer: "us-state",
|
|
46348
|
+
...r?.score !== void 0 && { score: r.score },
|
|
46349
|
+
...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46350
|
+
});
|
|
46351
|
+
const ctr = (0, import_d3_geo2.geoPath)(proj).centroid(f);
|
|
46352
|
+
if (Number.isFinite(ctr[0])) {
|
|
46353
|
+
const name = f.properties?.name ?? iso;
|
|
46354
|
+
insetLabelSeeds.push({ x: ctr[0], y: ctr[1], iso, name, lineNumber });
|
|
46355
|
+
}
|
|
46356
|
+
return xr;
|
|
46357
|
+
};
|
|
46358
|
+
const akRight = placeInset(
|
|
46359
|
+
"US-AK",
|
|
46360
|
+
alaskaProjection(),
|
|
46361
|
+
FIT_PAD,
|
|
46362
|
+
width * 0.15
|
|
46363
|
+
);
|
|
46364
|
+
placeInset("US-HI", hawaiiProjection(), akRight + 24, width * 0.1);
|
|
46365
|
+
}
|
|
46366
|
+
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46367
|
+
const cullExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
|
|
46368
|
+
const [[exW, exS], [exE, exN]] = cullExtent;
|
|
46369
|
+
const lonSpan = exE - exW;
|
|
46370
|
+
const latSpan = exN - exS;
|
|
46371
|
+
const isGlobalView = lonSpan >= 270 || latSpan >= 130;
|
|
46372
|
+
const padLon = Math.max(8, lonSpan * 0.35);
|
|
46373
|
+
const padLat = Math.max(8, latSpan * 0.35);
|
|
46374
|
+
const vW = exW - padLon;
|
|
46375
|
+
const vE = exE + padLon;
|
|
46376
|
+
const vS = exS - padLat;
|
|
46377
|
+
const vN = exN + padLat;
|
|
46378
|
+
const vLonCenter = (exW + exE) / 2;
|
|
46379
|
+
const normLon = (lon) => {
|
|
46380
|
+
let L = lon;
|
|
46381
|
+
while (L < vLonCenter - 180) L += 360;
|
|
46382
|
+
while (L > vLonCenter + 180) L -= 360;
|
|
46383
|
+
return L;
|
|
46384
|
+
};
|
|
46385
|
+
const ringOverlapsView = (ring) => {
|
|
46386
|
+
let anyIn = false;
|
|
46387
|
+
let loMin = Infinity, loMax = -Infinity, laMin = Infinity, laMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
46388
|
+
for (const [rawLon, lat] of ring) {
|
|
46389
|
+
const lon = normLon(rawLon);
|
|
46390
|
+
if (lon >= vW && lon <= vE && lat >= vS && lat <= vN) anyIn = true;
|
|
46391
|
+
if (lon < loMin) loMin = lon;
|
|
46392
|
+
if (lon > loMax) loMax = lon;
|
|
46393
|
+
if (rawLon < rawMin) rawMin = rawLon;
|
|
46394
|
+
if (rawLon > rawMax) rawMax = rawLon;
|
|
46395
|
+
if (lat < laMin) laMin = lat;
|
|
46396
|
+
if (lat > laMax) laMax = lat;
|
|
46397
|
+
}
|
|
46398
|
+
if (loMax - loMin > 270) return false;
|
|
46399
|
+
if (rawMax - rawMin > 180 && loMax - loMin < 90) return false;
|
|
46400
|
+
if (anyIn) return true;
|
|
46401
|
+
if (loMax - loMin > 180) return false;
|
|
46402
|
+
return !(loMax < vW || loMin > vE || laMax < vS || laMin > vN);
|
|
46403
|
+
};
|
|
46404
|
+
const cullFeatureToView = (f) => {
|
|
46405
|
+
if (isGlobalView) return f;
|
|
46406
|
+
const g = f.geometry;
|
|
46407
|
+
if (!g) return f;
|
|
46408
|
+
if (g.type === "Polygon") {
|
|
46409
|
+
const ring = g.coordinates[0];
|
|
46410
|
+
return ringOverlapsView(ring) ? f : null;
|
|
46411
|
+
}
|
|
46412
|
+
if (g.type === "MultiPolygon") {
|
|
46413
|
+
const polys = g.coordinates;
|
|
46414
|
+
const keep = polys.filter(
|
|
46415
|
+
(p) => ringOverlapsView(p[0])
|
|
46416
|
+
);
|
|
46417
|
+
if (!keep.length) return null;
|
|
46418
|
+
if (keep.length === polys.length) return f;
|
|
46419
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46420
|
+
}
|
|
46421
|
+
return f;
|
|
46422
|
+
};
|
|
46423
|
+
const SEAM_SLIVER_MAX_SPAN = 100;
|
|
46424
|
+
const ringIsFrameFiller = (ring) => {
|
|
46425
|
+
const lons = ring.map(([lon]) => lon).sort((a, b) => a - b);
|
|
46426
|
+
if (lons.length < 2) return false;
|
|
46427
|
+
let maxGap = -1;
|
|
46428
|
+
let gapIdx = 0;
|
|
46429
|
+
for (let i = 1; i < lons.length; i++) {
|
|
46430
|
+
const g = lons[i] - lons[i - 1];
|
|
46431
|
+
if (g > maxGap) {
|
|
46432
|
+
maxGap = g;
|
|
46433
|
+
gapIdx = i;
|
|
46434
|
+
}
|
|
46435
|
+
}
|
|
46436
|
+
const wrapGap = lons[0] + 360 - lons[lons.length - 1];
|
|
46437
|
+
if (wrapGap >= maxGap) return false;
|
|
46438
|
+
const span = 360 - maxGap;
|
|
46439
|
+
const east = lons[gapIdx - 1] + 360;
|
|
46440
|
+
return east > 180 && span < SEAM_SLIVER_MAX_SPAN;
|
|
46441
|
+
};
|
|
46442
|
+
const dropFrameFillers = (f) => {
|
|
46443
|
+
const g = f.geometry;
|
|
46444
|
+
if (!g) return f;
|
|
46445
|
+
if (g.type === "Polygon") {
|
|
46446
|
+
const ring = g.coordinates[0];
|
|
46447
|
+
return ringIsFrameFiller(ring) ? null : f;
|
|
46448
|
+
}
|
|
46449
|
+
if (g.type === "MultiPolygon") {
|
|
46450
|
+
const polys = g.coordinates;
|
|
46451
|
+
const keep = polys.filter(
|
|
46452
|
+
(p) => !ringIsFrameFiller(p[0])
|
|
46453
|
+
);
|
|
46454
|
+
if (!keep.length) return null;
|
|
46455
|
+
if (keep.length === polys.length) return f;
|
|
46456
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46457
|
+
}
|
|
46458
|
+
return f;
|
|
46459
|
+
};
|
|
45991
46460
|
const regions = [];
|
|
45992
|
-
const pushRegionLayer = (layerFeatures, layerKind) => {
|
|
46461
|
+
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
45993
46462
|
for (const [iso, f] of layerFeatures) {
|
|
45994
|
-
|
|
45995
|
-
|
|
46463
|
+
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
46464
|
+
continue;
|
|
46465
|
+
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
45996
46466
|
const r = regionById.get(iso);
|
|
46467
|
+
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
46468
|
+
if (!viewF) continue;
|
|
46469
|
+
const d = path(viewF) ?? "";
|
|
46470
|
+
if (!d) continue;
|
|
45997
46471
|
const isThisLayer = r?.layer === layerKind;
|
|
45998
|
-
|
|
46472
|
+
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46473
|
+
let fill2 = isForeign ? foreignFill : neutralFill;
|
|
45999
46474
|
let label;
|
|
46000
46475
|
let lineNumber = -1;
|
|
46001
46476
|
let layer = "base";
|
|
46002
46477
|
if (isThisLayer) {
|
|
46003
|
-
|
|
46004
|
-
else fill2 = tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46478
|
+
fill2 = regionFill(r);
|
|
46005
46479
|
lineNumber = r.lineNumber;
|
|
46006
46480
|
layer = layerKind;
|
|
46007
46481
|
label = r.name;
|
|
@@ -46013,12 +46487,42 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46013
46487
|
stroke: regionStroke,
|
|
46014
46488
|
lineNumber,
|
|
46015
46489
|
layer,
|
|
46016
|
-
...label !== void 0 && { label }
|
|
46490
|
+
...label !== void 0 && { label },
|
|
46491
|
+
...isThisLayer && r.score !== void 0 && { score: r.score },
|
|
46492
|
+
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46017
46493
|
});
|
|
46018
46494
|
}
|
|
46019
46495
|
};
|
|
46020
|
-
pushRegionLayer(worldLayer, "country");
|
|
46021
|
-
if (usLayer) pushRegionLayer(usLayer, "us-state");
|
|
46496
|
+
pushRegionLayer(worldLayer, "country", !isGlobalView);
|
|
46497
|
+
if (usLayer) pushRegionLayer(usLayer, "us-state", !conusFit && !isGlobalView);
|
|
46498
|
+
const lakesTopo = usCrisp && data.naLakes ? data.naLakes : data.lakes;
|
|
46499
|
+
if (lakesTopo) {
|
|
46500
|
+
for (const [, f] of decodeLayer(lakesTopo)) {
|
|
46501
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46502
|
+
if (!viewF) continue;
|
|
46503
|
+
const d = path(viewF) ?? "";
|
|
46504
|
+
if (!d) continue;
|
|
46505
|
+
regions.push({
|
|
46506
|
+
id: "lake",
|
|
46507
|
+
d,
|
|
46508
|
+
fill: water,
|
|
46509
|
+
stroke: "none",
|
|
46510
|
+
lineNumber: -1,
|
|
46511
|
+
layer: "base"
|
|
46512
|
+
});
|
|
46513
|
+
}
|
|
46514
|
+
}
|
|
46515
|
+
const riverColor = water;
|
|
46516
|
+
const rivers = [];
|
|
46517
|
+
if (data.rivers) {
|
|
46518
|
+
for (const [, f] of decodeLayer(data.rivers)) {
|
|
46519
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46520
|
+
if (!viewF) continue;
|
|
46521
|
+
const d = path(viewF) ?? "";
|
|
46522
|
+
if (!d) continue;
|
|
46523
|
+
rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
|
|
46524
|
+
}
|
|
46525
|
+
}
|
|
46022
46526
|
const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
46023
46527
|
const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
|
|
46024
46528
|
const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
|
|
@@ -46039,8 +46543,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46039
46543
|
if (hex) return { fill: hex, stroke: mix(hex, palette.text, 18) };
|
|
46040
46544
|
}
|
|
46041
46545
|
return {
|
|
46042
|
-
fill: palette.
|
|
46043
|
-
stroke: mix(palette.
|
|
46546
|
+
fill: palette.colors.orange,
|
|
46547
|
+
stroke: mix(palette.colors.orange, palette.text, 18)
|
|
46044
46548
|
};
|
|
46045
46549
|
};
|
|
46046
46550
|
const routeNumberById = /* @__PURE__ */ new Map();
|
|
@@ -46078,7 +46582,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46078
46582
|
cy += Math.sin(ang) * COLO_R;
|
|
46079
46583
|
}
|
|
46080
46584
|
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
46081
|
-
poiScreen.set(e.p.id, { cx, cy });
|
|
46585
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
46082
46586
|
const num = routeNumberById.get(e.p.id);
|
|
46083
46587
|
pois.push({
|
|
46084
46588
|
id: e.p.id,
|
|
@@ -46095,17 +46599,36 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46095
46599
|
});
|
|
46096
46600
|
}
|
|
46097
46601
|
const legs = [];
|
|
46602
|
+
const RIM_GAP = 1.5;
|
|
46098
46603
|
const legPath = (a, b, curved, offset) => {
|
|
46099
|
-
if (!curved && offset === 0) return `M${a.cx},${a.cy}L${b.cx},${b.cy}`;
|
|
46100
46604
|
const mx = (a.cx + b.cx) / 2;
|
|
46101
46605
|
const my = (a.cy + b.cy) / 2;
|
|
46102
46606
|
const dx = b.cx - a.cx;
|
|
46103
46607
|
const dy = b.cy - a.cy;
|
|
46104
46608
|
const len = Math.hypot(dx, dy) || 1;
|
|
46609
|
+
const trimA = Math.min(a.r + RIM_GAP, len * 0.45);
|
|
46610
|
+
const trimB = Math.min(b.r + RIM_GAP, len * 0.45);
|
|
46611
|
+
if (!curved && offset === 0) {
|
|
46612
|
+
const ux = dx / len;
|
|
46613
|
+
const uy = dy / len;
|
|
46614
|
+
const ax2 = a.cx + ux * trimA;
|
|
46615
|
+
const ay2 = a.cy + uy * trimA;
|
|
46616
|
+
const bx2 = b.cx - ux * trimB;
|
|
46617
|
+
const by2 = b.cy - uy * trimB;
|
|
46618
|
+
return `M${ax2},${ay2}L${bx2},${by2}`;
|
|
46619
|
+
}
|
|
46105
46620
|
const nx = -dy / len;
|
|
46106
46621
|
const ny = dx / len;
|
|
46107
46622
|
const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
|
|
46108
|
-
|
|
46623
|
+
const px = mx + nx * bow;
|
|
46624
|
+
const py = my + ny * bow;
|
|
46625
|
+
const ta = Math.hypot(px - a.cx, py - a.cy) || 1;
|
|
46626
|
+
const tb = Math.hypot(b.cx - px, b.cy - py) || 1;
|
|
46627
|
+
const ax = a.cx + (px - a.cx) / ta * trimA;
|
|
46628
|
+
const ay = a.cy + (py - a.cy) / ta * trimA;
|
|
46629
|
+
const bx = b.cx - (b.cx - px) / tb * trimB;
|
|
46630
|
+
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
46631
|
+
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
46109
46632
|
};
|
|
46110
46633
|
for (const rt of resolved.routes) {
|
|
46111
46634
|
const curved = rt.meta["style"] === "arc";
|
|
@@ -46116,7 +46639,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46116
46639
|
legs.push({
|
|
46117
46640
|
d: legPath(a, b, curved, 0),
|
|
46118
46641
|
width: W_MIN,
|
|
46119
|
-
color: mix(palette.text, palette.bg,
|
|
46642
|
+
color: mix(palette.text, palette.bg, 72),
|
|
46120
46643
|
arrow: true,
|
|
46121
46644
|
lineNumber: rt.lineNumber
|
|
46122
46645
|
});
|
|
@@ -46152,7 +46675,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46152
46675
|
legs.push({
|
|
46153
46676
|
d: legPath(a, b, curved, offset),
|
|
46154
46677
|
width: widthFor(e),
|
|
46155
|
-
color: mix(palette.text, palette.bg,
|
|
46678
|
+
color: mix(palette.text, palette.bg, 66),
|
|
46156
46679
|
arrow: e.directed,
|
|
46157
46680
|
lineNumber: e.lineNumber,
|
|
46158
46681
|
...e.label !== void 0 && {
|
|
@@ -46164,38 +46687,92 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46164
46687
|
});
|
|
46165
46688
|
}
|
|
46166
46689
|
const labels = [];
|
|
46167
|
-
const pinList = [];
|
|
46168
46690
|
const obstacles = [];
|
|
46169
46691
|
const markers = pois.map((p) => ({
|
|
46170
46692
|
cx: p.cx,
|
|
46171
46693
|
cy: p.cy,
|
|
46172
46694
|
r: p.r
|
|
46173
46695
|
}));
|
|
46174
|
-
const
|
|
46696
|
+
const legSegments = [];
|
|
46697
|
+
for (const leg of legs) {
|
|
46698
|
+
const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
46699
|
+
leg.d
|
|
46700
|
+
);
|
|
46701
|
+
if (!m) continue;
|
|
46702
|
+
const x0 = +m[1];
|
|
46703
|
+
const y0 = +m[2];
|
|
46704
|
+
if (m[3] !== void 0) {
|
|
46705
|
+
legSegments.push([x0, y0, +m[3], +m[4]]);
|
|
46706
|
+
} else {
|
|
46707
|
+
const cx = +m[5];
|
|
46708
|
+
const cy = +m[6];
|
|
46709
|
+
const ex = +m[7];
|
|
46710
|
+
const ey = +m[8];
|
|
46711
|
+
const N = 8;
|
|
46712
|
+
let px = x0;
|
|
46713
|
+
let py = y0;
|
|
46714
|
+
for (let i = 1; i <= N; i++) {
|
|
46715
|
+
const t = i / N;
|
|
46716
|
+
const u = 1 - t;
|
|
46717
|
+
const qx = u * u * x0 + 2 * u * t * cx + t * t * ex;
|
|
46718
|
+
const qy = u * u * y0 + 2 * u * t * cy + t * t * ey;
|
|
46719
|
+
legSegments.push([px, py, qx, qy]);
|
|
46720
|
+
px = qx;
|
|
46721
|
+
py = qy;
|
|
46722
|
+
}
|
|
46723
|
+
}
|
|
46724
|
+
}
|
|
46725
|
+
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));
|
|
46175
46726
|
const regionLabelMode = resolved.directives.regionLabels ?? "off";
|
|
46727
|
+
const LABEL_PADX = 6;
|
|
46728
|
+
const LABEL_PADY = 3;
|
|
46729
|
+
const labelW = (text) => measureLegendText(text, FONT) + 2 * LABEL_PADX;
|
|
46730
|
+
const labelH = FONT + 2 * LABEL_PADY;
|
|
46731
|
+
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
46732
|
+
const color = contrastText(
|
|
46733
|
+
fill2,
|
|
46734
|
+
palette.textOnFillLight,
|
|
46735
|
+
palette.textOnFillDark
|
|
46736
|
+
);
|
|
46737
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
46738
|
+
labels.push({
|
|
46739
|
+
x,
|
|
46740
|
+
y,
|
|
46741
|
+
text,
|
|
46742
|
+
anchor: "middle",
|
|
46743
|
+
color,
|
|
46744
|
+
halo: true,
|
|
46745
|
+
haloColor,
|
|
46746
|
+
lineNumber
|
|
46747
|
+
});
|
|
46748
|
+
};
|
|
46749
|
+
const WORLD_LABEL_ANCHORS = {
|
|
46750
|
+
US: [-98.5, 39.5]
|
|
46751
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
46752
|
+
};
|
|
46176
46753
|
if (regionLabelMode === "full" || regionLabelMode === "abbrev") {
|
|
46177
46754
|
for (const r of regions) {
|
|
46178
46755
|
if (r.layer === "base" || r.label === void 0) continue;
|
|
46179
46756
|
const f = r.layer === "us-state" ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
46180
46757
|
if (!f) continue;
|
|
46181
46758
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
46182
|
-
if ((x1 - x0) * (y1 - y0) < TINY_REGION_AREA) continue;
|
|
46183
|
-
const c = path.centroid(f);
|
|
46184
|
-
if (!Number.isFinite(c[0])) continue;
|
|
46185
46759
|
const text = regionLabelMode === "abbrev" ? r.id.replace(/^US-/, "") : r.label;
|
|
46186
|
-
|
|
46187
|
-
|
|
46188
|
-
|
|
46760
|
+
if (labelW(text) > x1 - x0 || labelH > y1 - y0) continue;
|
|
46761
|
+
const anchor = r.layer !== "us-state" ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
46762
|
+
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
46763
|
+
if (!c || !Number.isFinite(c[0])) continue;
|
|
46764
|
+
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
46765
|
+
}
|
|
46766
|
+
for (const seed of insetLabelSeeds) {
|
|
46767
|
+
const text = regionLabelMode === "abbrev" ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
46768
|
+
const src = regionById.get(seed.iso);
|
|
46769
|
+
pushRegionLabel(
|
|
46770
|
+
seed.x,
|
|
46771
|
+
seed.y,
|
|
46189
46772
|
text,
|
|
46190
|
-
|
|
46191
|
-
|
|
46192
|
-
|
|
46193
|
-
palette.textOnFillLight,
|
|
46194
|
-
palette.textOnFillDark
|
|
46195
|
-
),
|
|
46196
|
-
halo: true,
|
|
46197
|
-
lineNumber: r.lineNumber
|
|
46198
|
-
});
|
|
46773
|
+
src ? regionFill(src) : neutralFill,
|
|
46774
|
+
seed.lineNumber
|
|
46775
|
+
);
|
|
46199
46776
|
}
|
|
46200
46777
|
}
|
|
46201
46778
|
const poiLabelMode = resolved.directives.poiLabels ?? "auto";
|
|
@@ -46208,68 +46785,106 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46208
46785
|
const src = poiById.get(p.id);
|
|
46209
46786
|
return src?.label ?? src?.name ?? p.id;
|
|
46210
46787
|
};
|
|
46211
|
-
|
|
46212
|
-
|
|
46788
|
+
const poiLabH = FONT * 1.25;
|
|
46789
|
+
const labelInfo = (p) => {
|
|
46213
46790
|
const text = labelText(p);
|
|
46214
|
-
|
|
46215
|
-
|
|
46216
|
-
|
|
46217
|
-
|
|
46218
|
-
|
|
46791
|
+
return { text, w: measureLegendText(text, FONT) };
|
|
46792
|
+
};
|
|
46793
|
+
const pushInline = (p, text, w, side) => {
|
|
46794
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46795
|
+
obstacles.push({
|
|
46796
|
+
x: side === "right" ? tx : tx - w,
|
|
46797
|
+
y: p.cy - poiLabH / 2,
|
|
46798
|
+
w,
|
|
46799
|
+
h: poiLabH
|
|
46800
|
+
});
|
|
46801
|
+
labels.push({
|
|
46802
|
+
x: tx,
|
|
46803
|
+
y: p.cy + FONT / 3,
|
|
46804
|
+
text,
|
|
46805
|
+
anchor: side === "right" ? "start" : "end",
|
|
46806
|
+
color: palette.text,
|
|
46807
|
+
halo: true,
|
|
46808
|
+
haloColor: palette.bg,
|
|
46809
|
+
poiId: p.id,
|
|
46810
|
+
lineNumber: p.lineNumber
|
|
46811
|
+
});
|
|
46812
|
+
};
|
|
46813
|
+
const inlineFits = (p, w, side) => {
|
|
46814
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46815
|
+
const rect = {
|
|
46816
|
+
x: side === "right" ? tx : tx - w,
|
|
46817
|
+
y: p.cy - poiLabH / 2,
|
|
46818
|
+
w,
|
|
46819
|
+
h: poiLabH
|
|
46820
|
+
};
|
|
46821
|
+
return rect.x >= 0 && rect.x + rect.w <= width && !collides(rect);
|
|
46822
|
+
};
|
|
46823
|
+
const GROUP_R = 30;
|
|
46824
|
+
const groups = [];
|
|
46825
|
+
for (const p of ordered) {
|
|
46826
|
+
const near = groups.find(
|
|
46827
|
+
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
46828
|
+
);
|
|
46829
|
+
if (near) near.push(p);
|
|
46830
|
+
else groups.push([p]);
|
|
46831
|
+
}
|
|
46832
|
+
const ROW_GAP2 = 3;
|
|
46833
|
+
const step = poiLabH + ROW_GAP2;
|
|
46834
|
+
const COL_GAP = 16;
|
|
46835
|
+
const placeColumn = (group) => {
|
|
46836
|
+
const items = group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
46837
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
46838
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
46839
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
46840
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
46841
|
+
const side = right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
46842
|
+
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
46843
|
+
const totalH = items.length * step;
|
|
46844
|
+
let startY = cyMid - totalH / 2;
|
|
46845
|
+
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
46846
|
+
items.forEach((o, i) => {
|
|
46847
|
+
const rowCy = startY + i * step + step / 2;
|
|
46848
|
+
obstacles.push({
|
|
46849
|
+
x: side === "right" ? colX : colX - o.w,
|
|
46850
|
+
y: rowCy - poiLabH / 2,
|
|
46851
|
+
w: o.w,
|
|
46852
|
+
h: poiLabH
|
|
46853
|
+
});
|
|
46219
46854
|
labels.push({
|
|
46220
|
-
x:
|
|
46221
|
-
y:
|
|
46222
|
-
text,
|
|
46223
|
-
anchor: "start",
|
|
46855
|
+
x: colX,
|
|
46856
|
+
y: rowCy + FONT / 3,
|
|
46857
|
+
text: o.text,
|
|
46858
|
+
anchor: side === "right" ? "start" : "end",
|
|
46224
46859
|
color: palette.text,
|
|
46225
46860
|
halo: true,
|
|
46226
|
-
|
|
46861
|
+
haloColor: palette.bg,
|
|
46862
|
+
leader: {
|
|
46863
|
+
x1: o.p.cx,
|
|
46864
|
+
y1: o.p.cy,
|
|
46865
|
+
x2: side === "right" ? colX - 2 : colX + 2,
|
|
46866
|
+
y2: rowCy
|
|
46867
|
+
},
|
|
46868
|
+
leaderColor: o.p.fill,
|
|
46869
|
+
poiId: o.p.id,
|
|
46870
|
+
lineNumber: o.p.lineNumber
|
|
46227
46871
|
});
|
|
46228
|
-
|
|
46229
|
-
|
|
46230
|
-
|
|
46231
|
-
|
|
46232
|
-
|
|
46233
|
-
|
|
46234
|
-
|
|
46235
|
-
|
|
46236
|
-
|
|
46237
|
-
|
|
46238
|
-
|
|
46239
|
-
|
|
46240
|
-
|
|
46241
|
-
if (rect.x < 0 || rect.x + rect.w > width || rect.y < 0 || rect.y + rect.h > height) {
|
|
46242
|
-
continue;
|
|
46243
|
-
}
|
|
46244
|
-
if (collides(rect)) continue;
|
|
46245
|
-
obstacles.push(rect);
|
|
46246
|
-
labels.push({
|
|
46247
|
-
x: cx,
|
|
46248
|
-
y: cy + FONT / 3,
|
|
46249
|
-
text,
|
|
46250
|
-
anchor: dx >= 0 ? "start" : "end",
|
|
46251
|
-
color: palette.text,
|
|
46252
|
-
halo: true,
|
|
46253
|
-
leader: { x1: p.cx, y1: p.cy, x2: cx, y2: cy },
|
|
46254
|
-
lineNumber: p.lineNumber
|
|
46255
|
-
});
|
|
46256
|
-
placed = true;
|
|
46257
|
-
break;
|
|
46872
|
+
});
|
|
46873
|
+
};
|
|
46874
|
+
for (const g of groups) {
|
|
46875
|
+
if (g.length === 1) {
|
|
46876
|
+
const p = g[0];
|
|
46877
|
+
const { text, w } = labelInfo(p);
|
|
46878
|
+
if (inlineFits(p, w, "right")) {
|
|
46879
|
+
pushInline(p, text, w, "right");
|
|
46880
|
+
continue;
|
|
46881
|
+
}
|
|
46882
|
+
if (inlineFits(p, w, "left")) {
|
|
46883
|
+
pushInline(p, text, w, "left");
|
|
46884
|
+
continue;
|
|
46258
46885
|
}
|
|
46259
46886
|
}
|
|
46260
|
-
|
|
46261
|
-
pinCounter += 1;
|
|
46262
|
-
pinList.push({ pin: pinCounter, label: text });
|
|
46263
|
-
labels.push({
|
|
46264
|
-
x: p.cx + p.r + 2,
|
|
46265
|
-
y: p.cy - p.r,
|
|
46266
|
-
text: String(pinCounter),
|
|
46267
|
-
anchor: "start",
|
|
46268
|
-
color: palette.text,
|
|
46269
|
-
halo: true,
|
|
46270
|
-
pin: pinCounter,
|
|
46271
|
-
lineNumber: p.lineNumber
|
|
46272
|
-
});
|
|
46887
|
+
placeColumn(g);
|
|
46273
46888
|
}
|
|
46274
46889
|
}
|
|
46275
46890
|
let legend = null;
|
|
@@ -46278,8 +46893,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46278
46893
|
name: g.name,
|
|
46279
46894
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
46280
46895
|
}));
|
|
46281
|
-
|
|
46282
|
-
if (hasAnything) {
|
|
46896
|
+
if (tagGroups.length > 0 || hasRamp) {
|
|
46283
46897
|
legend = {
|
|
46284
46898
|
tagGroups,
|
|
46285
46899
|
activeGroup,
|
|
@@ -46290,20 +46904,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46290
46904
|
},
|
|
46291
46905
|
min: rampMin,
|
|
46292
46906
|
max: rampMax,
|
|
46293
|
-
hue: rampHue
|
|
46907
|
+
hue: rampHue,
|
|
46908
|
+
base: rampBase
|
|
46294
46909
|
}
|
|
46295
|
-
},
|
|
46296
|
-
...sizeVals.length > 0 && {
|
|
46297
|
-
size: {
|
|
46298
|
-
...resolved.directives.sizeMetric !== void 0 && {
|
|
46299
|
-
metric: resolved.directives.sizeMetric
|
|
46300
|
-
},
|
|
46301
|
-
min: sizeMin,
|
|
46302
|
-
max: sizeMax
|
|
46303
|
-
}
|
|
46304
|
-
},
|
|
46305
|
-
...weightVals.length > 0 && {
|
|
46306
|
-
weight: { min: wMin, max: wMax }
|
|
46307
46910
|
}
|
|
46308
46911
|
};
|
|
46309
46912
|
}
|
|
@@ -46311,28 +46914,30 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46311
46914
|
return {
|
|
46312
46915
|
width,
|
|
46313
46916
|
height,
|
|
46314
|
-
background:
|
|
46917
|
+
background: water,
|
|
46315
46918
|
title: resolved.title,
|
|
46316
46919
|
...resolved.subtitle !== void 0 && { subtitle: resolved.subtitle },
|
|
46317
46920
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
46318
46921
|
regions,
|
|
46922
|
+
rivers,
|
|
46319
46923
|
legs,
|
|
46320
46924
|
pois,
|
|
46321
46925
|
labels,
|
|
46322
|
-
|
|
46323
|
-
|
|
46926
|
+
legend,
|
|
46927
|
+
insets,
|
|
46928
|
+
insetRegions
|
|
46324
46929
|
};
|
|
46325
46930
|
}
|
|
46326
|
-
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT,
|
|
46931
|
+
var import_d3_geo2, import_topojson_client2, 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;
|
|
46327
46932
|
var init_layout15 = __esm({
|
|
46328
46933
|
"src/map/layout.ts"() {
|
|
46329
46934
|
"use strict";
|
|
46330
46935
|
import_d3_geo2 = require("d3-geo");
|
|
46331
46936
|
import_topojson_client2 = require("topojson-client");
|
|
46332
46937
|
init_color_utils();
|
|
46333
|
-
init_tag_groups();
|
|
46334
46938
|
init_label_layout();
|
|
46335
46939
|
init_legend_constants();
|
|
46940
|
+
init_title_constants();
|
|
46336
46941
|
FIT_PAD = 24;
|
|
46337
46942
|
RAMP_FLOOR = 15;
|
|
46338
46943
|
R_DEFAULT = 6;
|
|
@@ -46341,23 +46946,32 @@ var init_layout15 = __esm({
|
|
|
46341
46946
|
W_MIN = 1.25;
|
|
46342
46947
|
W_MAX = 8;
|
|
46343
46948
|
FONT = 11;
|
|
46344
|
-
LEADER_STEP = 14;
|
|
46345
46949
|
COLO_EPS = 1.5;
|
|
46950
|
+
LAND_TINT_LIGHT = 58;
|
|
46951
|
+
LAND_TINT_DARK = 75;
|
|
46952
|
+
TAG_TINT_LIGHT = 60;
|
|
46953
|
+
TAG_TINT_DARK = 68;
|
|
46954
|
+
WATER_TINT = 55;
|
|
46955
|
+
RIVER_WIDTH = 1.3;
|
|
46956
|
+
FOREIGN_TINT_LIGHT = 30;
|
|
46957
|
+
FOREIGN_TINT_DARK = 62;
|
|
46346
46958
|
COLO_R = 9;
|
|
46347
46959
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
46348
46960
|
FAN_STEP = 16;
|
|
46349
|
-
TINY_REGION_AREA = 600;
|
|
46350
46961
|
ARC_CURVE_FRAC = 0.18;
|
|
46351
|
-
|
|
46352
|
-
|
|
46353
|
-
|
|
46354
|
-
|
|
46355
|
-
|
|
46356
|
-
|
|
46357
|
-
|
|
46358
|
-
|
|
46359
|
-
|
|
46360
|
-
|
|
46962
|
+
usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
46963
|
+
alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
46964
|
+
hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
|
|
46965
|
+
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
46966
|
+
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
46967
|
+
"US-AK",
|
|
46968
|
+
"US-HI",
|
|
46969
|
+
"US-AS",
|
|
46970
|
+
"US-GU",
|
|
46971
|
+
"US-MP",
|
|
46972
|
+
"US-PR",
|
|
46973
|
+
"US-VI"
|
|
46974
|
+
]);
|
|
46361
46975
|
}
|
|
46362
46976
|
});
|
|
46363
46977
|
|
|
@@ -46367,7 +46981,7 @@ __export(renderer_exports16, {
|
|
|
46367
46981
|
renderMap: () => renderMap,
|
|
46368
46982
|
renderMapForExport: () => renderMapForExport
|
|
46369
46983
|
});
|
|
46370
|
-
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims) {
|
|
46984
|
+
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
46371
46985
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
46372
46986
|
const width = exportDims?.width ?? container.clientWidth;
|
|
46373
46987
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -46378,27 +46992,29 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46378
46992
|
{ width, height },
|
|
46379
46993
|
{
|
|
46380
46994
|
palette,
|
|
46381
|
-
isDark
|
|
46995
|
+
isDark,
|
|
46996
|
+
...activeGroupOverride !== void 0 && {
|
|
46997
|
+
activeGroup: activeGroupOverride
|
|
46998
|
+
}
|
|
46382
46999
|
}
|
|
46383
47000
|
);
|
|
46384
|
-
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);
|
|
47001
|
+
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);
|
|
46385
47002
|
svg.append("rect").attr("width", width).attr("height", height).attr("fill", layout.background);
|
|
46386
|
-
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
46387
47003
|
const defs = svg.append("defs");
|
|
46388
|
-
|
|
46389
|
-
const haloColor =
|
|
46390
|
-
if (layout.title) {
|
|
46391
|
-
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);
|
|
46392
|
-
}
|
|
46393
|
-
if (layout.subtitle) {
|
|
46394
|
-
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);
|
|
46395
|
-
}
|
|
46396
|
-
if (layout.caption) {
|
|
46397
|
-
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);
|
|
46398
|
-
}
|
|
47004
|
+
const arrowSize = (w) => Math.min(15, 7 + w * 0.95);
|
|
47005
|
+
const haloColor = palette.bg;
|
|
46399
47006
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
46400
|
-
|
|
46401
|
-
const p =
|
|
47007
|
+
const drawRegion = (g, r, strokeWidth) => {
|
|
47008
|
+
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
47009
|
+
if (r.layer !== "base") {
|
|
47010
|
+
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47011
|
+
if (r.score !== void 0) p.attr("data-score", r.score);
|
|
47012
|
+
if (r.tags) {
|
|
47013
|
+
for (const [group, value] of Object.entries(r.tags)) {
|
|
47014
|
+
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
47015
|
+
}
|
|
47016
|
+
}
|
|
47017
|
+
}
|
|
46402
47018
|
if (r.lineNumber >= 0) {
|
|
46403
47019
|
p.attr("data-line-number", r.lineNumber);
|
|
46404
47020
|
if (onClickItem) {
|
|
@@ -46408,11 +47024,31 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46408
47024
|
);
|
|
46409
47025
|
}
|
|
46410
47026
|
}
|
|
47027
|
+
};
|
|
47028
|
+
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
47029
|
+
if (layout.rivers.length) {
|
|
47030
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47031
|
+
for (const r of layout.rivers) {
|
|
47032
|
+
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
47033
|
+
}
|
|
47034
|
+
}
|
|
47035
|
+
if (layout.insets.length) {
|
|
47036
|
+
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47037
|
+
for (const box of layout.insets) {
|
|
47038
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47039
|
+
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");
|
|
47040
|
+
}
|
|
47041
|
+
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
46411
47042
|
}
|
|
46412
47043
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
46413
|
-
|
|
47044
|
+
layout.legs.forEach((leg, i) => {
|
|
46414
47045
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
46415
|
-
if (leg.arrow)
|
|
47046
|
+
if (leg.arrow) {
|
|
47047
|
+
const id = `dgmo-map-arrow-${i}`;
|
|
47048
|
+
const s = arrowSize(leg.width);
|
|
47049
|
+
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);
|
|
47050
|
+
p.attr("marker-end", `url(#${id})`);
|
|
47051
|
+
}
|
|
46416
47052
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
46417
47053
|
emitText(
|
|
46418
47054
|
gLegs,
|
|
@@ -46426,13 +47062,13 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46426
47062
|
LABEL_FONT - 1
|
|
46427
47063
|
);
|
|
46428
47064
|
}
|
|
46429
|
-
}
|
|
47065
|
+
});
|
|
46430
47066
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
46431
47067
|
for (const poi of layout.pois) {
|
|
46432
47068
|
if (poi.isOrigin) {
|
|
46433
47069
|
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);
|
|
46434
47070
|
}
|
|
46435
|
-
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);
|
|
47071
|
+
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);
|
|
46436
47072
|
if (onClickItem) {
|
|
46437
47073
|
c.style("cursor", "pointer").on(
|
|
46438
47074
|
"click",
|
|
@@ -46456,48 +47092,66 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46456
47092
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
46457
47093
|
for (const lab of layout.labels) {
|
|
46458
47094
|
if (lab.leader) {
|
|
46459
|
-
gLabels.append("line").attr("x1", lab.leader.x1).attr("y1", lab.leader.y1).attr("x2", lab.leader.x2).attr("y2", lab.leader.y2).attr(
|
|
46460
|
-
|
|
46461
|
-
|
|
46462
|
-
|
|
47095
|
+
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(
|
|
47096
|
+
"stroke",
|
|
47097
|
+
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47098
|
+
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47099
|
+
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
46463
47100
|
}
|
|
46464
|
-
emitText(
|
|
47101
|
+
const t = emitText(
|
|
46465
47102
|
gLabels,
|
|
46466
47103
|
lab.x,
|
|
46467
47104
|
lab.y,
|
|
46468
47105
|
lab.text,
|
|
46469
47106
|
lab.anchor,
|
|
46470
47107
|
lab.color,
|
|
46471
|
-
haloColor,
|
|
47108
|
+
lab.haloColor,
|
|
46472
47109
|
lab.halo,
|
|
46473
47110
|
LABEL_FONT
|
|
46474
47111
|
);
|
|
46475
|
-
|
|
46476
|
-
|
|
46477
|
-
|
|
46478
|
-
"transform",
|
|
46479
|
-
`translate(12, ${height - layout.pinList.length * 14 - 8})`
|
|
46480
|
-
);
|
|
46481
|
-
layout.pinList.forEach((entry, i) => {
|
|
46482
|
-
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}`);
|
|
46483
|
-
});
|
|
47112
|
+
if (lab.poiId !== void 0) {
|
|
47113
|
+
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47114
|
+
}
|
|
46484
47115
|
}
|
|
46485
47116
|
if (layout.legend) {
|
|
46486
47117
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
46487
47118
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
46488
|
-
const
|
|
47119
|
+
const ramp = layout.legend.ramp;
|
|
47120
|
+
const scoreGroup = ramp ? {
|
|
47121
|
+
name: ramp.metric?.trim() || "Score",
|
|
47122
|
+
entries: [],
|
|
47123
|
+
gradient: {
|
|
47124
|
+
min: ramp.min,
|
|
47125
|
+
max: ramp.max,
|
|
47126
|
+
hue: ramp.hue,
|
|
47127
|
+
base: ramp.base
|
|
47128
|
+
}
|
|
47129
|
+
} : null;
|
|
47130
|
+
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47131
|
+
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
46489
47132
|
if (groups.length > 0) {
|
|
46490
47133
|
const config = {
|
|
46491
|
-
groups
|
|
47134
|
+
groups,
|
|
46492
47135
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
46493
47136
|
mode: exportDims ? "export" : "preview",
|
|
46494
|
-
showEmptyGroups: false
|
|
47137
|
+
showEmptyGroups: false,
|
|
47138
|
+
// Keep inactive siblings visible as pills so the user can click to flip
|
|
47139
|
+
// the active colouring dimension (preview only — export shows just the
|
|
47140
|
+
// active group).
|
|
47141
|
+
showInactivePills: true
|
|
46495
47142
|
};
|
|
46496
47143
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
46497
47144
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
46498
47145
|
}
|
|
46499
|
-
|
|
46500
|
-
|
|
47146
|
+
}
|
|
47147
|
+
if (layout.title) {
|
|
47148
|
+
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);
|
|
47149
|
+
}
|
|
47150
|
+
if (layout.subtitle) {
|
|
47151
|
+
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);
|
|
47152
|
+
}
|
|
47153
|
+
if (layout.caption) {
|
|
47154
|
+
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);
|
|
46501
47155
|
}
|
|
46502
47156
|
}
|
|
46503
47157
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
@@ -46508,54 +47162,7 @@ function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
|
46508
47162
|
if (withHalo) {
|
|
46509
47163
|
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7);
|
|
46510
47164
|
}
|
|
46511
|
-
|
|
46512
|
-
function emitExtraLegend(svg, layout, palette, height, bottomGap) {
|
|
46513
|
-
const { legend } = layout;
|
|
46514
|
-
if (!legend) return;
|
|
46515
|
-
if (!legend.ramp && !legend.size && !legend.weight) return;
|
|
46516
|
-
const blocks = [];
|
|
46517
|
-
const g = svg.append("g").attr("class", "dgmo-map-legend-keys").attr("transform", `translate(12, ${height - 56 - bottomGap})`);
|
|
46518
|
-
let xCursor = 0;
|
|
46519
|
-
if (legend.ramp) {
|
|
46520
|
-
const ramp = legend.ramp;
|
|
46521
|
-
blocks.push(() => {
|
|
46522
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46523
|
-
const gradId = "dgmo-map-ramp";
|
|
46524
|
-
const grad = block.append("defs").append("linearGradient").attr("id", gradId).attr("x1", "0%").attr("x2", "100%");
|
|
46525
|
-
grad.append("stop").attr("offset", "0%").attr("stop-color", mix(ramp.hue, palette.bg, 15));
|
|
46526
|
-
grad.append("stop").attr("offset", "100%").attr("stop-color", ramp.hue);
|
|
46527
|
-
block.append("rect").attr("width", 80).attr("height", 8).attr("fill", `url(#${gradId})`);
|
|
46528
|
-
block.append("text").attr("x", 0).attr("y", 22).attr("font-size", 9).attr("fill", palette.textMuted).text(String(ramp.min));
|
|
46529
|
-
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));
|
|
46530
|
-
if (ramp.metric) {
|
|
46531
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(ramp.metric);
|
|
46532
|
-
}
|
|
46533
|
-
xCursor += 110;
|
|
46534
|
-
});
|
|
46535
|
-
}
|
|
46536
|
-
if (legend.size) {
|
|
46537
|
-
const sz = legend.size;
|
|
46538
|
-
blocks.push(() => {
|
|
46539
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46540
|
-
[3, 6, 10].forEach((r, i) => {
|
|
46541
|
-
block.append("circle").attr("cx", i * 26 + r).attr("cy", 8).attr("r", r).attr("fill", "none").attr("stroke", palette.textMuted);
|
|
46542
|
-
});
|
|
46543
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(sz.metric ?? "size");
|
|
46544
|
-
xCursor += 110;
|
|
46545
|
-
});
|
|
46546
|
-
}
|
|
46547
|
-
if (legend.weight) {
|
|
46548
|
-
const wt = legend.weight;
|
|
46549
|
-
blocks.push(() => {
|
|
46550
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46551
|
-
[1, 3, 6].forEach((w, i) => {
|
|
46552
|
-
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);
|
|
46553
|
-
});
|
|
46554
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(wt.metric ?? "weight");
|
|
46555
|
-
xCursor += 110;
|
|
46556
|
-
});
|
|
46557
|
-
}
|
|
46558
|
-
for (const draw of blocks) draw();
|
|
47165
|
+
return t;
|
|
46559
47166
|
}
|
|
46560
47167
|
var d3Selection18, LABEL_FONT;
|
|
46561
47168
|
var init_renderer16 = __esm({
|
|
@@ -56429,7 +57036,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
|
|
|
56429
57036
|
|
|
56430
57037
|
// src/auto/index.ts
|
|
56431
57038
|
init_safe_href();
|
|
56432
|
-
var VERSION = "0.
|
|
57039
|
+
var VERSION = "0.20.0";
|
|
56433
57040
|
var DEFAULTS = {
|
|
56434
57041
|
theme: "auto",
|
|
56435
57042
|
palette: "nord",
|