@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.mjs
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;
|
|
@@ -3179,6 +3206,57 @@ var init_legend_constants = __esm({
|
|
|
3179
3206
|
});
|
|
3180
3207
|
|
|
3181
3208
|
// src/utils/legend-layout.ts
|
|
3209
|
+
function fmtRamp(n) {
|
|
3210
|
+
return Number.isInteger(n) ? String(n) : String(Math.round(n * 10) / 10);
|
|
3211
|
+
}
|
|
3212
|
+
function gradientCapsuleWidth(name, gradient) {
|
|
3213
|
+
const pw = pillWidth(name);
|
|
3214
|
+
const minW = measureLegendText(fmtRamp(gradient.min), LEGEND_ENTRY_FONT_SIZE);
|
|
3215
|
+
const maxW = measureLegendText(fmtRamp(gradient.max), LEGEND_ENTRY_FONT_SIZE);
|
|
3216
|
+
return LEGEND_CAPSULE_PAD + pw + 4 + minW + RAMP_LABEL_GAP + RAMP_LEGEND_W + RAMP_LABEL_GAP + maxW + LEGEND_CAPSULE_PAD;
|
|
3217
|
+
}
|
|
3218
|
+
function buildGradientCapsuleLayout(group, gradient) {
|
|
3219
|
+
const pw = pillWidth(group.name);
|
|
3220
|
+
const minText = fmtRamp(gradient.min);
|
|
3221
|
+
const maxText = fmtRamp(gradient.max);
|
|
3222
|
+
const minW = measureLegendText(minText, LEGEND_ENTRY_FONT_SIZE);
|
|
3223
|
+
const gx = LEGEND_CAPSULE_PAD + pw + 4;
|
|
3224
|
+
const minX = gx;
|
|
3225
|
+
const rampX = gx + minW + RAMP_LABEL_GAP;
|
|
3226
|
+
const maxX = rampX + RAMP_LEGEND_W + RAMP_LABEL_GAP;
|
|
3227
|
+
const width = gradientCapsuleWidth(group.name, gradient);
|
|
3228
|
+
return {
|
|
3229
|
+
groupName: group.name,
|
|
3230
|
+
x: 0,
|
|
3231
|
+
y: 0,
|
|
3232
|
+
width,
|
|
3233
|
+
height: LEGEND_HEIGHT,
|
|
3234
|
+
pill: {
|
|
3235
|
+
groupName: group.name,
|
|
3236
|
+
x: LEGEND_CAPSULE_PAD,
|
|
3237
|
+
y: LEGEND_CAPSULE_PAD,
|
|
3238
|
+
width: pw,
|
|
3239
|
+
height: LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2,
|
|
3240
|
+
isActive: true
|
|
3241
|
+
},
|
|
3242
|
+
entries: [],
|
|
3243
|
+
gradient: {
|
|
3244
|
+
rampX,
|
|
3245
|
+
rampY: (LEGEND_HEIGHT - RAMP_LEGEND_H) / 2,
|
|
3246
|
+
rampW: RAMP_LEGEND_W,
|
|
3247
|
+
rampH: RAMP_LEGEND_H,
|
|
3248
|
+
min: gradient.min,
|
|
3249
|
+
max: gradient.max,
|
|
3250
|
+
minText,
|
|
3251
|
+
minX,
|
|
3252
|
+
maxText,
|
|
3253
|
+
maxX,
|
|
3254
|
+
textY: LEGEND_HEIGHT / 2,
|
|
3255
|
+
hue: gradient.hue,
|
|
3256
|
+
base: gradient.base
|
|
3257
|
+
}
|
|
3258
|
+
};
|
|
3259
|
+
}
|
|
3182
3260
|
function pillWidth(name) {
|
|
3183
3261
|
return measureLegendText(name, LEGEND_PILL_FONT_SIZE) + LEGEND_PILL_PAD;
|
|
3184
3262
|
}
|
|
@@ -3321,7 +3399,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3321
3399
|
};
|
|
3322
3400
|
}
|
|
3323
3401
|
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3324
|
-
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0);
|
|
3402
|
+
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3325
3403
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3326
3404
|
return {
|
|
3327
3405
|
height: 0,
|
|
@@ -3400,7 +3478,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3400
3478
|
groupAvailW,
|
|
3401
3479
|
config.capsulePillAddonWidth ?? 0
|
|
3402
3480
|
);
|
|
3403
|
-
} else if (!activeGroupName) {
|
|
3481
|
+
} else if (!activeGroupName || config.showInactivePills) {
|
|
3404
3482
|
const pw = pillWidth(g.name);
|
|
3405
3483
|
pills.push({
|
|
3406
3484
|
groupName: g.name,
|
|
@@ -3438,6 +3516,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3438
3516
|
};
|
|
3439
3517
|
}
|
|
3440
3518
|
function buildCapsuleLayout(group, containerWidth, addonWidth = 0) {
|
|
3519
|
+
if (group.gradient) return buildGradientCapsuleLayout(group, group.gradient);
|
|
3441
3520
|
const pw = pillWidth(group.name);
|
|
3442
3521
|
const info = capsuleWidth(
|
|
3443
3522
|
group.name,
|
|
@@ -3608,7 +3687,7 @@ function getMaxLegendReservedHeight(config, containerWidth) {
|
|
|
3608
3687
|
}
|
|
3609
3688
|
return max;
|
|
3610
3689
|
}
|
|
3611
|
-
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
|
|
3690
|
+
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP, RAMP_LEGEND_W, RAMP_LEGEND_H, RAMP_LABEL_GAP;
|
|
3612
3691
|
var init_legend_layout = __esm({
|
|
3613
3692
|
"src/utils/legend-layout.ts"() {
|
|
3614
3693
|
"use strict";
|
|
@@ -3617,6 +3696,9 @@ var init_legend_layout = __esm({
|
|
|
3617
3696
|
CONTROL_FONT_SIZE = 11;
|
|
3618
3697
|
CONTROL_ICON_GAP = 4;
|
|
3619
3698
|
CONTROL_GAP = 8;
|
|
3699
|
+
RAMP_LEGEND_W = 80;
|
|
3700
|
+
RAMP_LEGEND_H = 8;
|
|
3701
|
+
RAMP_LABEL_GAP = 6;
|
|
3620
3702
|
}
|
|
3621
3703
|
});
|
|
3622
3704
|
|
|
@@ -3704,6 +3786,16 @@ function renderCapsule(parent, capsule, palette, groupBg, pillBorder, _isDark, c
|
|
|
3704
3786
|
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);
|
|
3705
3787
|
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);
|
|
3706
3788
|
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);
|
|
3789
|
+
if (capsule.gradient) {
|
|
3790
|
+
const gr = capsule.gradient;
|
|
3791
|
+
const gradId = `dgmo-legend-ramp-${capsule.groupName.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
3792
|
+
const def = g.append("defs").append("linearGradient").attr("id", gradId);
|
|
3793
|
+
def.append("stop").attr("offset", "0%").attr("stop-color", mix(gr.hue, gr.base, 15));
|
|
3794
|
+
def.append("stop").attr("offset", "100%").attr("stop-color", gr.hue);
|
|
3795
|
+
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);
|
|
3796
|
+
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})`);
|
|
3797
|
+
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);
|
|
3798
|
+
}
|
|
3707
3799
|
for (const entry of capsule.entries) {
|
|
3708
3800
|
const entryG = g.append("g").attr("data-legend-entry", entry.value.toLowerCase()).attr("data-series-name", entry.value).style("cursor", "pointer");
|
|
3709
3801
|
entryG.append("circle").attr("cx", entry.dotCx).attr("cy", entry.dotCy).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
|
|
@@ -11195,23 +11287,22 @@ function parseC4(content, palette) {
|
|
|
11195
11287
|
}
|
|
11196
11288
|
}
|
|
11197
11289
|
const parent = findParentElement(indent, stack);
|
|
11198
|
-
|
|
11199
|
-
|
|
11290
|
+
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
11291
|
+
if (parent && descResult.isKeyword) {
|
|
11200
11292
|
if (descResult.needsColon) {
|
|
11201
11293
|
pushError(
|
|
11202
11294
|
lineNumber,
|
|
11203
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11295
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`,
|
|
11204
11296
|
"warning"
|
|
11205
11297
|
);
|
|
11206
11298
|
}
|
|
11207
|
-
const descText = descResult.isKeyword ? descResult.text : trimmed;
|
|
11208
11299
|
let desc = elementDescription.get(parent.element);
|
|
11209
11300
|
if (!desc) {
|
|
11210
11301
|
desc = [];
|
|
11211
11302
|
elementDescription.set(parent.element, desc);
|
|
11212
11303
|
parent.element.description = desc;
|
|
11213
11304
|
}
|
|
11214
|
-
desc.push(
|
|
11305
|
+
desc.push(descResult.text);
|
|
11215
11306
|
} else {
|
|
11216
11307
|
pushError(lineNumber, `Unexpected content: "${trimmed}"`);
|
|
11217
11308
|
}
|
|
@@ -11678,7 +11769,7 @@ function parseSitemap(content, palette) {
|
|
|
11678
11769
|
if (descResult.needsColon) {
|
|
11679
11770
|
pushWarning(
|
|
11680
11771
|
lineNumber,
|
|
11681
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11772
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
11682
11773
|
);
|
|
11683
11774
|
}
|
|
11684
11775
|
const parent = findParentNode(indent, indentStack);
|
|
@@ -12506,23 +12597,22 @@ function parseInfra(content) {
|
|
|
12506
12597
|
}
|
|
12507
12598
|
}
|
|
12508
12599
|
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
12509
|
-
if (descResult.isKeyword
|
|
12510
|
-
|
|
12511
|
-
|
|
12512
|
-
|
|
12600
|
+
if (descResult.isKeyword) {
|
|
12601
|
+
if (currentNode.isEdge) {
|
|
12602
|
+
continue;
|
|
12603
|
+
}
|
|
12513
12604
|
if (descResult.needsColon) {
|
|
12514
12605
|
warn2(
|
|
12515
12606
|
lineNumber,
|
|
12516
|
-
`Use "description: ${descResult.text}" \u2014
|
|
12607
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
12517
12608
|
);
|
|
12518
12609
|
}
|
|
12519
|
-
|
|
12520
|
-
pushDescription(currentNode, descText);
|
|
12610
|
+
pushDescription(currentNode, descResult.text);
|
|
12521
12611
|
continue;
|
|
12522
12612
|
}
|
|
12523
12613
|
warn2(
|
|
12524
12614
|
lineNumber,
|
|
12525
|
-
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or description text.`
|
|
12615
|
+
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or a description (description: text).`
|
|
12526
12616
|
);
|
|
12527
12617
|
continue;
|
|
12528
12618
|
}
|
|
@@ -15659,9 +15749,6 @@ function parseMap(content) {
|
|
|
15659
15749
|
const pushWarning = (line12, message) => {
|
|
15660
15750
|
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15661
15751
|
};
|
|
15662
|
-
const pushInfo = (line12, message) => {
|
|
15663
|
-
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15664
|
-
};
|
|
15665
15752
|
const lines = content.split("\n");
|
|
15666
15753
|
let firstIdx = 0;
|
|
15667
15754
|
while (firstIdx < lines.length) {
|
|
@@ -15791,10 +15878,15 @@ function parseMap(content) {
|
|
|
15791
15878
|
break;
|
|
15792
15879
|
case "projection":
|
|
15793
15880
|
dup(d.projection);
|
|
15794
|
-
if (value && ![
|
|
15881
|
+
if (value && ![
|
|
15882
|
+
"equirectangular",
|
|
15883
|
+
"natural-earth",
|
|
15884
|
+
"albers-usa",
|
|
15885
|
+
"mercator"
|
|
15886
|
+
].includes(value))
|
|
15795
15887
|
pushWarning(
|
|
15796
15888
|
line12,
|
|
15797
|
-
`Unknown projection "${value}" (expected natural-earth | albers-usa | mercator).`
|
|
15889
|
+
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15798
15890
|
);
|
|
15799
15891
|
d.projection = value;
|
|
15800
15892
|
break;
|
|
@@ -15933,17 +16025,21 @@ function parseMap(content) {
|
|
|
15933
16025
|
scoreNum = void 0;
|
|
15934
16026
|
}
|
|
15935
16027
|
}
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
16028
|
+
let regionName = split.name;
|
|
16029
|
+
let regionScope;
|
|
16030
|
+
const rToks = regionName.split(/\s+/);
|
|
16031
|
+
const rLast = rToks[rToks.length - 1];
|
|
16032
|
+
if (rToks.length > 1 && SCOPE_RE.test(rLast)) {
|
|
16033
|
+
regionName = rToks.slice(0, -1).join(" ");
|
|
16034
|
+
regionScope = rLast;
|
|
16035
|
+
}
|
|
15941
16036
|
const region = {
|
|
15942
|
-
name:
|
|
16037
|
+
name: regionName,
|
|
15943
16038
|
tags,
|
|
15944
16039
|
meta,
|
|
15945
16040
|
lineNumber: line12
|
|
15946
16041
|
};
|
|
16042
|
+
if (regionScope !== void 0) region.scope = regionScope;
|
|
15947
16043
|
if (scoreNum !== void 0) region.score = scoreNum;
|
|
15948
16044
|
regions.push(region);
|
|
15949
16045
|
}
|
|
@@ -17067,7 +17163,7 @@ function parseMindmap(content, palette) {
|
|
|
17067
17163
|
if (descResult.needsColon) {
|
|
17068
17164
|
pushWarning(
|
|
17069
17165
|
lineNumber,
|
|
17070
|
-
`Use "description: ${descResult.text}" \u2014
|
|
17166
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
17071
17167
|
);
|
|
17072
17168
|
}
|
|
17073
17169
|
const parent = findMetadataParent2(indent, indentStack);
|
|
@@ -18855,7 +18951,7 @@ function parseJourneyMap(content, palette) {
|
|
|
18855
18951
|
if (descResult.needsColon) {
|
|
18856
18952
|
warn2(
|
|
18857
18953
|
lineNumber,
|
|
18858
|
-
`Use "description: ${descResult.text}" \u2014
|
|
18954
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
18859
18955
|
);
|
|
18860
18956
|
}
|
|
18861
18957
|
currentStep.description = descResult.text;
|
|
@@ -45444,7 +45540,9 @@ function resolveMap(parsed, data) {
|
|
|
45444
45540
|
const usScoped = parsed.directives.region === "us-states" || parsed.directives.defaultCountry?.toUpperCase() === "US" || parsed.regions.some((r) => {
|
|
45445
45541
|
const f = fold(r.name);
|
|
45446
45542
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45447
|
-
}) || parsed.
|
|
45543
|
+
}) || parsed.regions.some(
|
|
45544
|
+
(r) => r.scope === "US" || r.scope?.startsWith("US-")
|
|
45545
|
+
) || parsed.pois.some(
|
|
45448
45546
|
(p) => p.pos.kind === "name" && p.pos.scope?.startsWith("US-")
|
|
45449
45547
|
);
|
|
45450
45548
|
const regions = [];
|
|
@@ -45456,7 +45554,30 @@ function resolveMap(parsed, data) {
|
|
|
45456
45554
|
const inCountry = countryIndex.get(f) ?? (REGION_ALIASES[f] ? countryIndex.get(REGION_ALIASES[f]) : void 0);
|
|
45457
45555
|
const inState = usStateIndex.get(f);
|
|
45458
45556
|
let chosen = null;
|
|
45459
|
-
|
|
45557
|
+
const scope = r.scope;
|
|
45558
|
+
if (scope) {
|
|
45559
|
+
const wantsState = scope === "US" || scope.startsWith("US-");
|
|
45560
|
+
if (wantsState && inState) {
|
|
45561
|
+
if (scope.startsWith("US-") && inState.id !== scope) {
|
|
45562
|
+
err(
|
|
45563
|
+
r.lineNumber,
|
|
45564
|
+
`No subdivision "${r.name}" in scope ${scope} (it is ${inState.id}).`,
|
|
45565
|
+
"E_MAP_SCOPE_MISS"
|
|
45566
|
+
);
|
|
45567
|
+
continue;
|
|
45568
|
+
}
|
|
45569
|
+
chosen = { ...inState, layer: "us-state" };
|
|
45570
|
+
} else if (!wantsState && inCountry) {
|
|
45571
|
+
chosen = { ...inCountry, layer: "country" };
|
|
45572
|
+
} else {
|
|
45573
|
+
err(
|
|
45574
|
+
r.lineNumber,
|
|
45575
|
+
`No region "${r.name}" found in scope ${scope}.`,
|
|
45576
|
+
"E_MAP_SCOPE_MISS"
|
|
45577
|
+
);
|
|
45578
|
+
continue;
|
|
45579
|
+
}
|
|
45580
|
+
} else if (inCountry && inState) {
|
|
45460
45581
|
if (usScoped) {
|
|
45461
45582
|
chosen = { ...inState, layer: "us-state" };
|
|
45462
45583
|
} else {
|
|
@@ -45464,7 +45585,7 @@ function resolveMap(parsed, data) {
|
|
|
45464
45585
|
}
|
|
45465
45586
|
warn2(
|
|
45466
45587
|
r.lineNumber,
|
|
45467
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}).`,
|
|
45588
|
+
`"${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}").`,
|
|
45468
45589
|
"W_MAP_REGION_AMBIGUOUS"
|
|
45469
45590
|
);
|
|
45470
45591
|
} else if (inState) {
|
|
@@ -45636,9 +45757,17 @@ function resolveMap(parsed, data) {
|
|
|
45636
45757
|
};
|
|
45637
45758
|
registerPoi(id, poi, p.lineNumber);
|
|
45638
45759
|
}
|
|
45760
|
+
const declaredByName = /* @__PURE__ */ new Map();
|
|
45761
|
+
for (const p of pois) {
|
|
45762
|
+
const fn = p.name ? fold(p.name) : void 0;
|
|
45763
|
+
if (fn && fn !== p.id && !declaredByName.has(fn))
|
|
45764
|
+
declaredByName.set(fn, p.id);
|
|
45765
|
+
}
|
|
45639
45766
|
const resolveEndpoint2 = (ref, line12) => {
|
|
45640
45767
|
const f = fold(ref);
|
|
45641
45768
|
if (registry.has(f)) return f;
|
|
45769
|
+
const aliased = declaredByName.get(f);
|
|
45770
|
+
if (aliased) return aliased;
|
|
45642
45771
|
const got = lookupName(ref, void 0, line12, inferredCountry, true);
|
|
45643
45772
|
if (got.kind !== "ok") return null;
|
|
45644
45773
|
noteCountry(got.iso);
|
|
@@ -45718,23 +45847,29 @@ function resolveMap(parsed, data) {
|
|
|
45718
45847
|
[-180, -85],
|
|
45719
45848
|
[180, 85]
|
|
45720
45849
|
];
|
|
45721
|
-
|
|
45850
|
+
let extent2 = unioned ? pad(unioned, PAD_FRACTION) : DEFAULT_EXTENT;
|
|
45722
45851
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
45723
45852
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
45724
45853
|
const span = Math.max(lonSpan, latSpan);
|
|
45725
45854
|
const usDominant = (inferredCountry === "US" || subdivisions.includes("us-states")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
45726
45855
|
let projection;
|
|
45727
45856
|
const override = parsed.directives.projection;
|
|
45728
|
-
if (override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
45857
|
+
if (override === "equirectangular" || override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
45729
45858
|
projection = override;
|
|
45730
45859
|
} else if (usDominant) {
|
|
45731
45860
|
projection = "albers-usa";
|
|
45732
45861
|
} else if (span > WORLD_SPAN) {
|
|
45733
|
-
projection = "
|
|
45862
|
+
projection = "equirectangular";
|
|
45734
45863
|
} else if (span < MERCATOR_MAX_SPAN) {
|
|
45735
45864
|
projection = "mercator";
|
|
45736
45865
|
} else {
|
|
45737
|
-
projection = "
|
|
45866
|
+
projection = "equirectangular";
|
|
45867
|
+
}
|
|
45868
|
+
if (lonSpan >= 180) {
|
|
45869
|
+
extent2 = [
|
|
45870
|
+
[-180, Math.min(extent2[0][1], WORLD_LAT_SOUTH)],
|
|
45871
|
+
[180, Math.max(extent2[1][1], WORLD_LAT_NORTH)]
|
|
45872
|
+
];
|
|
45738
45873
|
}
|
|
45739
45874
|
result.regions = regions;
|
|
45740
45875
|
result.pois = pois;
|
|
@@ -45782,7 +45917,7 @@ function firstError(diags) {
|
|
|
45782
45917
|
const e = diags.find((d) => d.severity === "error");
|
|
45783
45918
|
return e ? formatDgmoError(e) : null;
|
|
45784
45919
|
}
|
|
45785
|
-
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, REGION_ALIASES;
|
|
45920
|
+
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES;
|
|
45786
45921
|
var init_resolver2 = __esm({
|
|
45787
45922
|
"src/map/resolver.ts"() {
|
|
45788
45923
|
"use strict";
|
|
@@ -45791,6 +45926,8 @@ var init_resolver2 = __esm({
|
|
|
45791
45926
|
WORLD_SPAN = 90;
|
|
45792
45927
|
MERCATOR_MAX_SPAN = 25;
|
|
45793
45928
|
PAD_FRACTION = 0.05;
|
|
45929
|
+
WORLD_LAT_SOUTH = -58;
|
|
45930
|
+
WORLD_LAT_NORTH = 78;
|
|
45794
45931
|
REGION_ALIASES = {
|
|
45795
45932
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
45796
45933
|
"united states": "united states of america",
|
|
@@ -45858,13 +45995,36 @@ function moduleBaseDir() {
|
|
|
45858
45995
|
function loadMapData() {
|
|
45859
45996
|
cache ??= (async () => {
|
|
45860
45997
|
const dir = await firstExistingDir(moduleBaseDir());
|
|
45861
|
-
const [
|
|
45998
|
+
const [
|
|
45999
|
+
worldCoarse,
|
|
46000
|
+
worldDetail,
|
|
46001
|
+
usStates,
|
|
46002
|
+
lakes,
|
|
46003
|
+
rivers,
|
|
46004
|
+
naLand,
|
|
46005
|
+
naLakes,
|
|
46006
|
+
gazetteer
|
|
46007
|
+
] = await Promise.all([
|
|
45862
46008
|
readJson(dir, FILES.worldCoarse),
|
|
45863
46009
|
readJson(dir, FILES.worldDetail),
|
|
45864
46010
|
readJson(dir, FILES.usStates),
|
|
46011
|
+
// Lakes/rivers/NA assets are optional — older bundles may predate them.
|
|
46012
|
+
readJson(dir, FILES.lakes).catch(() => void 0),
|
|
46013
|
+
readJson(dir, FILES.rivers).catch(() => void 0),
|
|
46014
|
+
readJson(dir, FILES.naLand).catch(() => void 0),
|
|
46015
|
+
readJson(dir, FILES.naLakes).catch(() => void 0),
|
|
45865
46016
|
readJson(dir, FILES.gazetteer)
|
|
45866
46017
|
]);
|
|
45867
|
-
return validate({
|
|
46018
|
+
return validate({
|
|
46019
|
+
worldCoarse,
|
|
46020
|
+
worldDetail,
|
|
46021
|
+
usStates,
|
|
46022
|
+
gazetteer,
|
|
46023
|
+
...lakes && { lakes },
|
|
46024
|
+
...rivers && { rivers },
|
|
46025
|
+
...naLand && { naLand },
|
|
46026
|
+
...naLakes && { naLakes }
|
|
46027
|
+
});
|
|
45868
46028
|
})().catch((e) => {
|
|
45869
46029
|
cache = void 0;
|
|
45870
46030
|
throw e;
|
|
@@ -45879,6 +46039,10 @@ var init_load_data = __esm({
|
|
|
45879
46039
|
worldCoarse: "world-coarse.json",
|
|
45880
46040
|
worldDetail: "world-detail.json",
|
|
45881
46041
|
usStates: "us-states.json",
|
|
46042
|
+
lakes: "lakes.json",
|
|
46043
|
+
rivers: "rivers.json",
|
|
46044
|
+
naLand: "na-land.json",
|
|
46045
|
+
naLakes: "na-lakes.json",
|
|
45882
46046
|
gazetteer: "gazetteer.json"
|
|
45883
46047
|
};
|
|
45884
46048
|
CANDIDATE_DIRS = [
|
|
@@ -45894,8 +46058,11 @@ var init_load_data = __esm({
|
|
|
45894
46058
|
import {
|
|
45895
46059
|
geoPath,
|
|
45896
46060
|
geoNaturalEarth1,
|
|
45897
|
-
|
|
45898
|
-
|
|
46061
|
+
geoEquirectangular,
|
|
46062
|
+
geoConicEqualArea,
|
|
46063
|
+
geoMercator,
|
|
46064
|
+
geoBounds as geoBounds2,
|
|
46065
|
+
geoTransform
|
|
45899
46066
|
} from "d3-geo";
|
|
45900
46067
|
import { feature as feature2 } from "topojson-client";
|
|
45901
46068
|
function geomObject2(topo) {
|
|
@@ -45913,36 +46080,67 @@ function decodeLayer(topo) {
|
|
|
45913
46080
|
function projectionFor(family) {
|
|
45914
46081
|
switch (family) {
|
|
45915
46082
|
case "albers-usa":
|
|
45916
|
-
return
|
|
46083
|
+
return usConusProjection();
|
|
45917
46084
|
case "mercator":
|
|
45918
46085
|
return geoMercator();
|
|
45919
46086
|
case "natural-earth":
|
|
45920
|
-
default:
|
|
45921
46087
|
return geoNaturalEarth1();
|
|
46088
|
+
case "equirectangular":
|
|
46089
|
+
default:
|
|
46090
|
+
return geoEquirectangular();
|
|
45922
46091
|
}
|
|
45923
46092
|
}
|
|
46093
|
+
function mapBackgroundColor(palette) {
|
|
46094
|
+
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
46095
|
+
}
|
|
45924
46096
|
function layoutMap(resolved, data, size, opts) {
|
|
45925
46097
|
const { palette, isDark } = opts;
|
|
45926
46098
|
const { width, height } = size;
|
|
45927
|
-
const
|
|
46099
|
+
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46100
|
+
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
46101
|
+
const worldTopo = usCrisp ? data.naLand : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
45928
46102
|
const worldLayer = decodeLayer(worldTopo);
|
|
45929
|
-
const usLayer =
|
|
45930
|
-
const
|
|
45931
|
-
const
|
|
46103
|
+
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
46104
|
+
const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
|
|
46105
|
+
const neutralFill = mix(palette.colors.green, palette.bg, landTint);
|
|
46106
|
+
const water = mapBackgroundColor(palette);
|
|
46107
|
+
const usContext = usLayer !== null;
|
|
46108
|
+
const foreignFill = mix(
|
|
46109
|
+
palette.colors.gray,
|
|
46110
|
+
palette.bg,
|
|
46111
|
+
isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46112
|
+
);
|
|
46113
|
+
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
45932
46114
|
const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
|
|
45933
46115
|
const scaleOverride = resolved.directives.scale;
|
|
45934
46116
|
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
|
|
45935
46117
|
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
|
|
45936
|
-
const rampHue = palette.
|
|
46118
|
+
const rampHue = palette.colors.red;
|
|
45937
46119
|
const hasRamp = scores.length > 0;
|
|
45938
|
-
const
|
|
45939
|
-
|
|
45940
|
-
|
|
45941
|
-
|
|
46120
|
+
const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
|
|
46121
|
+
const matchColorGroup = (v) => {
|
|
46122
|
+
const lv = v.trim().toLowerCase();
|
|
46123
|
+
if (lv === "none") return null;
|
|
46124
|
+
if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
|
|
46125
|
+
return SCORE_NAME;
|
|
46126
|
+
const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
46127
|
+
return tg ? tg.name : v;
|
|
46128
|
+
};
|
|
46129
|
+
const override = opts.activeGroup;
|
|
46130
|
+
let activeGroup;
|
|
46131
|
+
if (override !== void 0) {
|
|
46132
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
46133
|
+
} else if (resolved.directives.activeTag !== void 0) {
|
|
46134
|
+
activeGroup = matchColorGroup(resolved.directives.activeTag);
|
|
46135
|
+
} else {
|
|
46136
|
+
activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46137
|
+
}
|
|
46138
|
+
const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
|
|
46139
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
45942
46140
|
const fillForScore = (s) => {
|
|
45943
46141
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
45944
46142
|
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
45945
|
-
return mix(rampHue,
|
|
46143
|
+
return mix(rampHue, rampBase, pct);
|
|
45946
46144
|
};
|
|
45947
46145
|
const tagFill = (tags, groupName) => {
|
|
45948
46146
|
if (!groupName) return null;
|
|
@@ -45956,40 +46154,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
45956
46154
|
(e) => e.value.toLowerCase() === val.toLowerCase()
|
|
45957
46155
|
);
|
|
45958
46156
|
if (!entry?.color) return null;
|
|
45959
|
-
return
|
|
46157
|
+
return mix(
|
|
46158
|
+
entry.color,
|
|
46159
|
+
palette.bg,
|
|
46160
|
+
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46161
|
+
);
|
|
46162
|
+
};
|
|
46163
|
+
const regionFill = (r) => {
|
|
46164
|
+
if (activeIsScore) {
|
|
46165
|
+
return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
|
|
46166
|
+
}
|
|
46167
|
+
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
45960
46168
|
};
|
|
45961
46169
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
45962
|
-
const
|
|
45963
|
-
for (const r of resolved.regions) {
|
|
45964
|
-
const f = r.layer === "us-state" ? usLayer?.get(r.iso) : worldLayer.get(r.iso);
|
|
45965
|
-
if (f) regionFeatures.push(f);
|
|
45966
|
-
}
|
|
45967
|
-
const extentCorners = () => {
|
|
46170
|
+
const extentOutline = () => {
|
|
45968
46171
|
const [[w, s], [e, n]] = resolved.extent;
|
|
46172
|
+
const N = 16;
|
|
46173
|
+
const coords = [];
|
|
46174
|
+
for (let i = 0; i <= N; i++) {
|
|
46175
|
+
const t = i / N;
|
|
46176
|
+
const lon = w + (e - w) * t;
|
|
46177
|
+
const lat = s + (n - s) * t;
|
|
46178
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46179
|
+
}
|
|
45969
46180
|
return {
|
|
45970
46181
|
type: "Feature",
|
|
45971
46182
|
properties: {},
|
|
45972
|
-
geometry: {
|
|
45973
|
-
type: "MultiPoint",
|
|
45974
|
-
coordinates: [
|
|
45975
|
-
[w, s],
|
|
45976
|
-
[e, s],
|
|
45977
|
-
[e, n],
|
|
45978
|
-
[w, n]
|
|
45979
|
-
]
|
|
45980
|
-
}
|
|
46183
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
45981
46184
|
};
|
|
45982
46185
|
};
|
|
45983
46186
|
let fitFeatures;
|
|
45984
|
-
if (resolved.projection === "albers-usa") {
|
|
45985
|
-
|
|
45986
|
-
else if (usLayer) fitFeatures = [...usLayer.values()];
|
|
45987
|
-
else {
|
|
45988
|
-
const us = worldLayer.get("US");
|
|
45989
|
-
fitFeatures = us ? [us] : [...worldLayer.values()];
|
|
45990
|
-
}
|
|
46187
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46188
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
45991
46189
|
} else {
|
|
45992
|
-
fitFeatures = [
|
|
46190
|
+
fitFeatures = [extentOutline()];
|
|
45993
46191
|
}
|
|
45994
46192
|
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
45995
46193
|
const projection = projectionFor(resolved.projection);
|
|
@@ -45998,32 +46196,311 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
45998
46196
|
if (centerLon > 180) centerLon -= 360;
|
|
45999
46197
|
projection.rotate([-centerLon, 0]);
|
|
46000
46198
|
}
|
|
46001
|
-
|
|
46199
|
+
const TITLE_GAP = 16;
|
|
46200
|
+
let topPad = FIT_PAD;
|
|
46201
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
46202
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46203
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP);
|
|
46204
|
+
}
|
|
46205
|
+
const fitBox = [
|
|
46206
|
+
[FIT_PAD, topPad],
|
|
46002
46207
|
[
|
|
46003
|
-
|
|
46004
|
-
|
|
46005
|
-
|
|
46006
|
-
|
|
46007
|
-
|
|
46008
|
-
|
|
46009
|
-
|
|
46010
|
-
|
|
46011
|
-
|
|
46012
|
-
|
|
46208
|
+
Math.max(FIT_PAD + 1, width - FIT_PAD),
|
|
46209
|
+
Math.max(topPad + 1, height - FIT_PAD)
|
|
46210
|
+
]
|
|
46211
|
+
];
|
|
46212
|
+
projection.fitExtent(fitBox, fitTarget);
|
|
46213
|
+
const fitGB = geoBounds2(fitTarget);
|
|
46214
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46215
|
+
let path;
|
|
46216
|
+
let project;
|
|
46217
|
+
if (fitIsGlobal) {
|
|
46218
|
+
const cb = geoPath(projection).bounds(fitTarget);
|
|
46219
|
+
const bx0 = cb[0][0];
|
|
46220
|
+
const by0 = cb[0][1];
|
|
46221
|
+
const cw = cb[1][0] - bx0;
|
|
46222
|
+
const ch = cb[1][1] - by0;
|
|
46223
|
+
const ox = fitBox[0][0];
|
|
46224
|
+
const oy = fitBox[0][1];
|
|
46225
|
+
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46226
|
+
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
46227
|
+
const stretch = (x, y) => [
|
|
46228
|
+
ox + (x - bx0) * sx,
|
|
46229
|
+
oy + (y - by0) * sy
|
|
46230
|
+
];
|
|
46231
|
+
const baseProjection = projection;
|
|
46232
|
+
const tx = geoTransform({
|
|
46233
|
+
point(x, y) {
|
|
46234
|
+
const [px, py] = stretch(x, y);
|
|
46235
|
+
this.stream.point(px, py);
|
|
46236
|
+
}
|
|
46237
|
+
});
|
|
46238
|
+
path = geoPath({
|
|
46239
|
+
stream: (s) => baseProjection.stream(
|
|
46240
|
+
tx.stream(s)
|
|
46241
|
+
)
|
|
46242
|
+
});
|
|
46243
|
+
project = (lon, lat) => {
|
|
46244
|
+
const p = baseProjection([lon, lat]);
|
|
46245
|
+
return p ? stretch(p[0], p[1]) : null;
|
|
46246
|
+
};
|
|
46247
|
+
} else {
|
|
46248
|
+
path = geoPath(projection);
|
|
46249
|
+
project = (lon, lat) => projection([lon, lat]) ?? null;
|
|
46250
|
+
}
|
|
46251
|
+
const insets = [];
|
|
46252
|
+
const insetRegions = [];
|
|
46253
|
+
const insetLabelSeeds = [];
|
|
46254
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46255
|
+
const PAD = 8;
|
|
46256
|
+
const GAP = 12;
|
|
46257
|
+
const yB = height - FIT_PAD;
|
|
46258
|
+
const BW = 8;
|
|
46259
|
+
const coast = /* @__PURE__ */ new Map();
|
|
46260
|
+
const addPt = (lon, lat) => {
|
|
46261
|
+
const p = projection([lon, lat]);
|
|
46262
|
+
if (!p) return;
|
|
46263
|
+
const bi = Math.floor(p[0] / BW);
|
|
46264
|
+
const cur = coast.get(bi);
|
|
46265
|
+
if (cur === void 0 || p[1] > cur) coast.set(bi, p[1]);
|
|
46266
|
+
};
|
|
46267
|
+
const walk = (co) => {
|
|
46268
|
+
if (Array.isArray(co) && typeof co[0] === "number")
|
|
46269
|
+
addPt(co[0], co[1]);
|
|
46270
|
+
else if (Array.isArray(co)) for (const c of co) walk(c);
|
|
46271
|
+
};
|
|
46272
|
+
for (const [iso, f] of usLayer) {
|
|
46273
|
+
if (US_NON_CONUS.has(iso)) continue;
|
|
46274
|
+
walk(f.geometry.coordinates);
|
|
46275
|
+
}
|
|
46276
|
+
const at = (x) => {
|
|
46277
|
+
const bi = Math.floor(x / BW);
|
|
46278
|
+
let y = -Infinity;
|
|
46279
|
+
for (let k = bi - 1; k <= bi + 1; k++) {
|
|
46280
|
+
const v = coast.get(k);
|
|
46281
|
+
if (v !== void 0 && v > y) y = v;
|
|
46282
|
+
}
|
|
46283
|
+
return y;
|
|
46284
|
+
};
|
|
46285
|
+
const coastTop = (x0, xr) => {
|
|
46286
|
+
const n = 24;
|
|
46287
|
+
const pts = [];
|
|
46288
|
+
let maxY = -Infinity;
|
|
46289
|
+
for (let i = 0; i <= n; i++) {
|
|
46290
|
+
const x = x0 + (xr - x0) * i / n;
|
|
46291
|
+
const y = at(x);
|
|
46292
|
+
if (y > -Infinity) {
|
|
46293
|
+
pts.push([x, y]);
|
|
46294
|
+
if (y > maxY) maxY = y;
|
|
46295
|
+
}
|
|
46296
|
+
}
|
|
46297
|
+
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46298
|
+
let m = 0;
|
|
46299
|
+
if (pts.length >= 2) {
|
|
46300
|
+
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46301
|
+
for (const [x, y] of pts) {
|
|
46302
|
+
sx += x;
|
|
46303
|
+
sy += y;
|
|
46304
|
+
sxx += x * x;
|
|
46305
|
+
sxy += x * y;
|
|
46306
|
+
}
|
|
46307
|
+
const den = pts.length * sxx - sx * sx;
|
|
46308
|
+
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46309
|
+
}
|
|
46310
|
+
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46311
|
+
let c = -Infinity;
|
|
46312
|
+
for (const [x, y] of pts) {
|
|
46313
|
+
const need = y - m * x + GAP;
|
|
46314
|
+
if (need > c) c = need;
|
|
46315
|
+
}
|
|
46316
|
+
return (x) => m * x + c;
|
|
46317
|
+
};
|
|
46318
|
+
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46319
|
+
const f = usLayer.get(iso);
|
|
46320
|
+
if (!f) return boxX;
|
|
46321
|
+
const x0 = boxX;
|
|
46322
|
+
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46323
|
+
if (iw < 24) return boxX;
|
|
46324
|
+
const xr = x0 + iw + 2 * PAD;
|
|
46325
|
+
const top = coastTop(x0, xr);
|
|
46326
|
+
const yL = top(x0);
|
|
46327
|
+
const yR = top(xr);
|
|
46328
|
+
proj.fitWidth(iw, f);
|
|
46329
|
+
const bb = geoPath(proj).bounds(f);
|
|
46330
|
+
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46331
|
+
const needH = sh + 2 * PAD;
|
|
46332
|
+
let topFit = Math.max(yL, yR);
|
|
46333
|
+
const bottom = Math.min(topFit + needH, yB);
|
|
46334
|
+
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46335
|
+
const lift = topFit - Math.max(yL, yR);
|
|
46336
|
+
const topL = yL + lift;
|
|
46337
|
+
const topR = yR + lift;
|
|
46338
|
+
proj.fitExtent(
|
|
46339
|
+
[
|
|
46340
|
+
[x0 + PAD, topFit + PAD],
|
|
46341
|
+
[xr - PAD, bottom - PAD]
|
|
46342
|
+
],
|
|
46343
|
+
f
|
|
46344
|
+
);
|
|
46345
|
+
const d = geoPath(proj)(f) ?? "";
|
|
46346
|
+
if (!d) return xr;
|
|
46347
|
+
const r = regionById.get(iso);
|
|
46348
|
+
let fill2 = neutralFill;
|
|
46349
|
+
let lineNumber = -1;
|
|
46350
|
+
if (r?.layer === "us-state") {
|
|
46351
|
+
fill2 = regionFill(r);
|
|
46352
|
+
lineNumber = r.lineNumber;
|
|
46353
|
+
}
|
|
46354
|
+
insets.push({
|
|
46355
|
+
x: x0,
|
|
46356
|
+
y: Math.min(topL, topR),
|
|
46357
|
+
w: xr - x0,
|
|
46358
|
+
h: bottom - Math.min(topL, topR),
|
|
46359
|
+
points: [
|
|
46360
|
+
[x0, topL],
|
|
46361
|
+
[xr, topR],
|
|
46362
|
+
[xr, bottom],
|
|
46363
|
+
[x0, bottom]
|
|
46364
|
+
]
|
|
46365
|
+
});
|
|
46366
|
+
insetRegions.push({
|
|
46367
|
+
id: iso,
|
|
46368
|
+
d,
|
|
46369
|
+
fill: fill2,
|
|
46370
|
+
stroke: regionStroke,
|
|
46371
|
+
lineNumber,
|
|
46372
|
+
layer: "us-state",
|
|
46373
|
+
...r?.score !== void 0 && { score: r.score },
|
|
46374
|
+
...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46375
|
+
});
|
|
46376
|
+
const ctr = geoPath(proj).centroid(f);
|
|
46377
|
+
if (Number.isFinite(ctr[0])) {
|
|
46378
|
+
const name = f.properties?.name ?? iso;
|
|
46379
|
+
insetLabelSeeds.push({ x: ctr[0], y: ctr[1], iso, name, lineNumber });
|
|
46380
|
+
}
|
|
46381
|
+
return xr;
|
|
46382
|
+
};
|
|
46383
|
+
const akRight = placeInset(
|
|
46384
|
+
"US-AK",
|
|
46385
|
+
alaskaProjection(),
|
|
46386
|
+
FIT_PAD,
|
|
46387
|
+
width * 0.15
|
|
46388
|
+
);
|
|
46389
|
+
placeInset("US-HI", hawaiiProjection(), akRight + 24, width * 0.1);
|
|
46390
|
+
}
|
|
46391
|
+
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46392
|
+
const cullExtent = conusFit ? geoBounds2(fitTarget) : resolved.extent;
|
|
46393
|
+
const [[exW, exS], [exE, exN]] = cullExtent;
|
|
46394
|
+
const lonSpan = exE - exW;
|
|
46395
|
+
const latSpan = exN - exS;
|
|
46396
|
+
const isGlobalView = lonSpan >= 270 || latSpan >= 130;
|
|
46397
|
+
const padLon = Math.max(8, lonSpan * 0.35);
|
|
46398
|
+
const padLat = Math.max(8, latSpan * 0.35);
|
|
46399
|
+
const vW = exW - padLon;
|
|
46400
|
+
const vE = exE + padLon;
|
|
46401
|
+
const vS = exS - padLat;
|
|
46402
|
+
const vN = exN + padLat;
|
|
46403
|
+
const vLonCenter = (exW + exE) / 2;
|
|
46404
|
+
const normLon = (lon) => {
|
|
46405
|
+
let L = lon;
|
|
46406
|
+
while (L < vLonCenter - 180) L += 360;
|
|
46407
|
+
while (L > vLonCenter + 180) L -= 360;
|
|
46408
|
+
return L;
|
|
46409
|
+
};
|
|
46410
|
+
const ringOverlapsView = (ring) => {
|
|
46411
|
+
let anyIn = false;
|
|
46412
|
+
let loMin = Infinity, loMax = -Infinity, laMin = Infinity, laMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
46413
|
+
for (const [rawLon, lat] of ring) {
|
|
46414
|
+
const lon = normLon(rawLon);
|
|
46415
|
+
if (lon >= vW && lon <= vE && lat >= vS && lat <= vN) anyIn = true;
|
|
46416
|
+
if (lon < loMin) loMin = lon;
|
|
46417
|
+
if (lon > loMax) loMax = lon;
|
|
46418
|
+
if (rawLon < rawMin) rawMin = rawLon;
|
|
46419
|
+
if (rawLon > rawMax) rawMax = rawLon;
|
|
46420
|
+
if (lat < laMin) laMin = lat;
|
|
46421
|
+
if (lat > laMax) laMax = lat;
|
|
46422
|
+
}
|
|
46423
|
+
if (loMax - loMin > 270) return false;
|
|
46424
|
+
if (rawMax - rawMin > 180 && loMax - loMin < 90) return false;
|
|
46425
|
+
if (anyIn) return true;
|
|
46426
|
+
if (loMax - loMin > 180) return false;
|
|
46427
|
+
return !(loMax < vW || loMin > vE || laMax < vS || laMin > vN);
|
|
46428
|
+
};
|
|
46429
|
+
const cullFeatureToView = (f) => {
|
|
46430
|
+
if (isGlobalView) return f;
|
|
46431
|
+
const g = f.geometry;
|
|
46432
|
+
if (!g) return f;
|
|
46433
|
+
if (g.type === "Polygon") {
|
|
46434
|
+
const ring = g.coordinates[0];
|
|
46435
|
+
return ringOverlapsView(ring) ? f : null;
|
|
46436
|
+
}
|
|
46437
|
+
if (g.type === "MultiPolygon") {
|
|
46438
|
+
const polys = g.coordinates;
|
|
46439
|
+
const keep = polys.filter(
|
|
46440
|
+
(p) => ringOverlapsView(p[0])
|
|
46441
|
+
);
|
|
46442
|
+
if (!keep.length) return null;
|
|
46443
|
+
if (keep.length === polys.length) return f;
|
|
46444
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46445
|
+
}
|
|
46446
|
+
return f;
|
|
46447
|
+
};
|
|
46448
|
+
const SEAM_SLIVER_MAX_SPAN = 100;
|
|
46449
|
+
const ringIsFrameFiller = (ring) => {
|
|
46450
|
+
const lons = ring.map(([lon]) => lon).sort((a, b) => a - b);
|
|
46451
|
+
if (lons.length < 2) return false;
|
|
46452
|
+
let maxGap = -1;
|
|
46453
|
+
let gapIdx = 0;
|
|
46454
|
+
for (let i = 1; i < lons.length; i++) {
|
|
46455
|
+
const g = lons[i] - lons[i - 1];
|
|
46456
|
+
if (g > maxGap) {
|
|
46457
|
+
maxGap = g;
|
|
46458
|
+
gapIdx = i;
|
|
46459
|
+
}
|
|
46460
|
+
}
|
|
46461
|
+
const wrapGap = lons[0] + 360 - lons[lons.length - 1];
|
|
46462
|
+
if (wrapGap >= maxGap) return false;
|
|
46463
|
+
const span = 360 - maxGap;
|
|
46464
|
+
const east = lons[gapIdx - 1] + 360;
|
|
46465
|
+
return east > 180 && span < SEAM_SLIVER_MAX_SPAN;
|
|
46466
|
+
};
|
|
46467
|
+
const dropFrameFillers = (f) => {
|
|
46468
|
+
const g = f.geometry;
|
|
46469
|
+
if (!g) return f;
|
|
46470
|
+
if (g.type === "Polygon") {
|
|
46471
|
+
const ring = g.coordinates[0];
|
|
46472
|
+
return ringIsFrameFiller(ring) ? null : f;
|
|
46473
|
+
}
|
|
46474
|
+
if (g.type === "MultiPolygon") {
|
|
46475
|
+
const polys = g.coordinates;
|
|
46476
|
+
const keep = polys.filter(
|
|
46477
|
+
(p) => !ringIsFrameFiller(p[0])
|
|
46478
|
+
);
|
|
46479
|
+
if (!keep.length) return null;
|
|
46480
|
+
if (keep.length === polys.length) return f;
|
|
46481
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46482
|
+
}
|
|
46483
|
+
return f;
|
|
46484
|
+
};
|
|
46013
46485
|
const regions = [];
|
|
46014
|
-
const pushRegionLayer = (layerFeatures, layerKind) => {
|
|
46486
|
+
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46015
46487
|
for (const [iso, f] of layerFeatures) {
|
|
46016
|
-
|
|
46017
|
-
|
|
46488
|
+
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
46489
|
+
continue;
|
|
46490
|
+
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46018
46491
|
const r = regionById.get(iso);
|
|
46492
|
+
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
46493
|
+
if (!viewF) continue;
|
|
46494
|
+
const d = path(viewF) ?? "";
|
|
46495
|
+
if (!d) continue;
|
|
46019
46496
|
const isThisLayer = r?.layer === layerKind;
|
|
46020
|
-
|
|
46497
|
+
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46498
|
+
let fill2 = isForeign ? foreignFill : neutralFill;
|
|
46021
46499
|
let label;
|
|
46022
46500
|
let lineNumber = -1;
|
|
46023
46501
|
let layer = "base";
|
|
46024
46502
|
if (isThisLayer) {
|
|
46025
|
-
|
|
46026
|
-
else fill2 = tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46503
|
+
fill2 = regionFill(r);
|
|
46027
46504
|
lineNumber = r.lineNumber;
|
|
46028
46505
|
layer = layerKind;
|
|
46029
46506
|
label = r.name;
|
|
@@ -46035,12 +46512,42 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46035
46512
|
stroke: regionStroke,
|
|
46036
46513
|
lineNumber,
|
|
46037
46514
|
layer,
|
|
46038
|
-
...label !== void 0 && { label }
|
|
46515
|
+
...label !== void 0 && { label },
|
|
46516
|
+
...isThisLayer && r.score !== void 0 && { score: r.score },
|
|
46517
|
+
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46039
46518
|
});
|
|
46040
46519
|
}
|
|
46041
46520
|
};
|
|
46042
|
-
pushRegionLayer(worldLayer, "country");
|
|
46043
|
-
if (usLayer) pushRegionLayer(usLayer, "us-state");
|
|
46521
|
+
pushRegionLayer(worldLayer, "country", !isGlobalView);
|
|
46522
|
+
if (usLayer) pushRegionLayer(usLayer, "us-state", !conusFit && !isGlobalView);
|
|
46523
|
+
const lakesTopo = usCrisp && data.naLakes ? data.naLakes : data.lakes;
|
|
46524
|
+
if (lakesTopo) {
|
|
46525
|
+
for (const [, f] of decodeLayer(lakesTopo)) {
|
|
46526
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46527
|
+
if (!viewF) continue;
|
|
46528
|
+
const d = path(viewF) ?? "";
|
|
46529
|
+
if (!d) continue;
|
|
46530
|
+
regions.push({
|
|
46531
|
+
id: "lake",
|
|
46532
|
+
d,
|
|
46533
|
+
fill: water,
|
|
46534
|
+
stroke: "none",
|
|
46535
|
+
lineNumber: -1,
|
|
46536
|
+
layer: "base"
|
|
46537
|
+
});
|
|
46538
|
+
}
|
|
46539
|
+
}
|
|
46540
|
+
const riverColor = water;
|
|
46541
|
+
const rivers = [];
|
|
46542
|
+
if (data.rivers) {
|
|
46543
|
+
for (const [, f] of decodeLayer(data.rivers)) {
|
|
46544
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46545
|
+
if (!viewF) continue;
|
|
46546
|
+
const d = path(viewF) ?? "";
|
|
46547
|
+
if (!d) continue;
|
|
46548
|
+
rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
|
|
46549
|
+
}
|
|
46550
|
+
}
|
|
46044
46551
|
const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
46045
46552
|
const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
|
|
46046
46553
|
const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
|
|
@@ -46061,8 +46568,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46061
46568
|
if (hex) return { fill: hex, stroke: mix(hex, palette.text, 18) };
|
|
46062
46569
|
}
|
|
46063
46570
|
return {
|
|
46064
|
-
fill: palette.
|
|
46065
|
-
stroke: mix(palette.
|
|
46571
|
+
fill: palette.colors.orange,
|
|
46572
|
+
stroke: mix(palette.colors.orange, palette.text, 18)
|
|
46066
46573
|
};
|
|
46067
46574
|
};
|
|
46068
46575
|
const routeNumberById = /* @__PURE__ */ new Map();
|
|
@@ -46100,7 +46607,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46100
46607
|
cy += Math.sin(ang) * COLO_R;
|
|
46101
46608
|
}
|
|
46102
46609
|
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
46103
|
-
poiScreen.set(e.p.id, { cx, cy });
|
|
46610
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
46104
46611
|
const num = routeNumberById.get(e.p.id);
|
|
46105
46612
|
pois.push({
|
|
46106
46613
|
id: e.p.id,
|
|
@@ -46117,17 +46624,36 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46117
46624
|
});
|
|
46118
46625
|
}
|
|
46119
46626
|
const legs = [];
|
|
46627
|
+
const RIM_GAP = 1.5;
|
|
46120
46628
|
const legPath = (a, b, curved, offset) => {
|
|
46121
|
-
if (!curved && offset === 0) return `M${a.cx},${a.cy}L${b.cx},${b.cy}`;
|
|
46122
46629
|
const mx = (a.cx + b.cx) / 2;
|
|
46123
46630
|
const my = (a.cy + b.cy) / 2;
|
|
46124
46631
|
const dx = b.cx - a.cx;
|
|
46125
46632
|
const dy = b.cy - a.cy;
|
|
46126
46633
|
const len = Math.hypot(dx, dy) || 1;
|
|
46634
|
+
const trimA = Math.min(a.r + RIM_GAP, len * 0.45);
|
|
46635
|
+
const trimB = Math.min(b.r + RIM_GAP, len * 0.45);
|
|
46636
|
+
if (!curved && offset === 0) {
|
|
46637
|
+
const ux = dx / len;
|
|
46638
|
+
const uy = dy / len;
|
|
46639
|
+
const ax2 = a.cx + ux * trimA;
|
|
46640
|
+
const ay2 = a.cy + uy * trimA;
|
|
46641
|
+
const bx2 = b.cx - ux * trimB;
|
|
46642
|
+
const by2 = b.cy - uy * trimB;
|
|
46643
|
+
return `M${ax2},${ay2}L${bx2},${by2}`;
|
|
46644
|
+
}
|
|
46127
46645
|
const nx = -dy / len;
|
|
46128
46646
|
const ny = dx / len;
|
|
46129
46647
|
const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
|
|
46130
|
-
|
|
46648
|
+
const px = mx + nx * bow;
|
|
46649
|
+
const py = my + ny * bow;
|
|
46650
|
+
const ta = Math.hypot(px - a.cx, py - a.cy) || 1;
|
|
46651
|
+
const tb = Math.hypot(b.cx - px, b.cy - py) || 1;
|
|
46652
|
+
const ax = a.cx + (px - a.cx) / ta * trimA;
|
|
46653
|
+
const ay = a.cy + (py - a.cy) / ta * trimA;
|
|
46654
|
+
const bx = b.cx - (b.cx - px) / tb * trimB;
|
|
46655
|
+
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
46656
|
+
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
46131
46657
|
};
|
|
46132
46658
|
for (const rt of resolved.routes) {
|
|
46133
46659
|
const curved = rt.meta["style"] === "arc";
|
|
@@ -46138,7 +46664,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46138
46664
|
legs.push({
|
|
46139
46665
|
d: legPath(a, b, curved, 0),
|
|
46140
46666
|
width: W_MIN,
|
|
46141
|
-
color: mix(palette.text, palette.bg,
|
|
46667
|
+
color: mix(palette.text, palette.bg, 72),
|
|
46142
46668
|
arrow: true,
|
|
46143
46669
|
lineNumber: rt.lineNumber
|
|
46144
46670
|
});
|
|
@@ -46174,7 +46700,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46174
46700
|
legs.push({
|
|
46175
46701
|
d: legPath(a, b, curved, offset),
|
|
46176
46702
|
width: widthFor(e),
|
|
46177
|
-
color: mix(palette.text, palette.bg,
|
|
46703
|
+
color: mix(palette.text, palette.bg, 66),
|
|
46178
46704
|
arrow: e.directed,
|
|
46179
46705
|
lineNumber: e.lineNumber,
|
|
46180
46706
|
...e.label !== void 0 && {
|
|
@@ -46186,38 +46712,92 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46186
46712
|
});
|
|
46187
46713
|
}
|
|
46188
46714
|
const labels = [];
|
|
46189
|
-
const pinList = [];
|
|
46190
46715
|
const obstacles = [];
|
|
46191
46716
|
const markers = pois.map((p) => ({
|
|
46192
46717
|
cx: p.cx,
|
|
46193
46718
|
cy: p.cy,
|
|
46194
46719
|
r: p.r
|
|
46195
46720
|
}));
|
|
46196
|
-
const
|
|
46721
|
+
const legSegments = [];
|
|
46722
|
+
for (const leg of legs) {
|
|
46723
|
+
const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
46724
|
+
leg.d
|
|
46725
|
+
);
|
|
46726
|
+
if (!m) continue;
|
|
46727
|
+
const x0 = +m[1];
|
|
46728
|
+
const y0 = +m[2];
|
|
46729
|
+
if (m[3] !== void 0) {
|
|
46730
|
+
legSegments.push([x0, y0, +m[3], +m[4]]);
|
|
46731
|
+
} else {
|
|
46732
|
+
const cx = +m[5];
|
|
46733
|
+
const cy = +m[6];
|
|
46734
|
+
const ex = +m[7];
|
|
46735
|
+
const ey = +m[8];
|
|
46736
|
+
const N = 8;
|
|
46737
|
+
let px = x0;
|
|
46738
|
+
let py = y0;
|
|
46739
|
+
for (let i = 1; i <= N; i++) {
|
|
46740
|
+
const t = i / N;
|
|
46741
|
+
const u = 1 - t;
|
|
46742
|
+
const qx = u * u * x0 + 2 * u * t * cx + t * t * ex;
|
|
46743
|
+
const qy = u * u * y0 + 2 * u * t * cy + t * t * ey;
|
|
46744
|
+
legSegments.push([px, py, qx, qy]);
|
|
46745
|
+
px = qx;
|
|
46746
|
+
py = qy;
|
|
46747
|
+
}
|
|
46748
|
+
}
|
|
46749
|
+
}
|
|
46750
|
+
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));
|
|
46197
46751
|
const regionLabelMode = resolved.directives.regionLabels ?? "off";
|
|
46752
|
+
const LABEL_PADX = 6;
|
|
46753
|
+
const LABEL_PADY = 3;
|
|
46754
|
+
const labelW = (text) => measureLegendText(text, FONT) + 2 * LABEL_PADX;
|
|
46755
|
+
const labelH = FONT + 2 * LABEL_PADY;
|
|
46756
|
+
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
46757
|
+
const color = contrastText(
|
|
46758
|
+
fill2,
|
|
46759
|
+
palette.textOnFillLight,
|
|
46760
|
+
palette.textOnFillDark
|
|
46761
|
+
);
|
|
46762
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
46763
|
+
labels.push({
|
|
46764
|
+
x,
|
|
46765
|
+
y,
|
|
46766
|
+
text,
|
|
46767
|
+
anchor: "middle",
|
|
46768
|
+
color,
|
|
46769
|
+
halo: true,
|
|
46770
|
+
haloColor,
|
|
46771
|
+
lineNumber
|
|
46772
|
+
});
|
|
46773
|
+
};
|
|
46774
|
+
const WORLD_LABEL_ANCHORS = {
|
|
46775
|
+
US: [-98.5, 39.5]
|
|
46776
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
46777
|
+
};
|
|
46198
46778
|
if (regionLabelMode === "full" || regionLabelMode === "abbrev") {
|
|
46199
46779
|
for (const r of regions) {
|
|
46200
46780
|
if (r.layer === "base" || r.label === void 0) continue;
|
|
46201
46781
|
const f = r.layer === "us-state" ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
46202
46782
|
if (!f) continue;
|
|
46203
46783
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
46204
|
-
if ((x1 - x0) * (y1 - y0) < TINY_REGION_AREA) continue;
|
|
46205
|
-
const c = path.centroid(f);
|
|
46206
|
-
if (!Number.isFinite(c[0])) continue;
|
|
46207
46784
|
const text = regionLabelMode === "abbrev" ? r.id.replace(/^US-/, "") : r.label;
|
|
46208
|
-
|
|
46209
|
-
|
|
46210
|
-
|
|
46785
|
+
if (labelW(text) > x1 - x0 || labelH > y1 - y0) continue;
|
|
46786
|
+
const anchor = r.layer !== "us-state" ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
46787
|
+
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
46788
|
+
if (!c || !Number.isFinite(c[0])) continue;
|
|
46789
|
+
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
46790
|
+
}
|
|
46791
|
+
for (const seed of insetLabelSeeds) {
|
|
46792
|
+
const text = regionLabelMode === "abbrev" ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
46793
|
+
const src = regionById.get(seed.iso);
|
|
46794
|
+
pushRegionLabel(
|
|
46795
|
+
seed.x,
|
|
46796
|
+
seed.y,
|
|
46211
46797
|
text,
|
|
46212
|
-
|
|
46213
|
-
|
|
46214
|
-
|
|
46215
|
-
palette.textOnFillLight,
|
|
46216
|
-
palette.textOnFillDark
|
|
46217
|
-
),
|
|
46218
|
-
halo: true,
|
|
46219
|
-
lineNumber: r.lineNumber
|
|
46220
|
-
});
|
|
46798
|
+
src ? regionFill(src) : neutralFill,
|
|
46799
|
+
seed.lineNumber
|
|
46800
|
+
);
|
|
46221
46801
|
}
|
|
46222
46802
|
}
|
|
46223
46803
|
const poiLabelMode = resolved.directives.poiLabels ?? "auto";
|
|
@@ -46230,68 +46810,106 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46230
46810
|
const src = poiById.get(p.id);
|
|
46231
46811
|
return src?.label ?? src?.name ?? p.id;
|
|
46232
46812
|
};
|
|
46233
|
-
|
|
46234
|
-
|
|
46813
|
+
const poiLabH = FONT * 1.25;
|
|
46814
|
+
const labelInfo = (p) => {
|
|
46235
46815
|
const text = labelText(p);
|
|
46236
|
-
|
|
46237
|
-
|
|
46238
|
-
|
|
46239
|
-
|
|
46240
|
-
|
|
46816
|
+
return { text, w: measureLegendText(text, FONT) };
|
|
46817
|
+
};
|
|
46818
|
+
const pushInline = (p, text, w, side) => {
|
|
46819
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46820
|
+
obstacles.push({
|
|
46821
|
+
x: side === "right" ? tx : tx - w,
|
|
46822
|
+
y: p.cy - poiLabH / 2,
|
|
46823
|
+
w,
|
|
46824
|
+
h: poiLabH
|
|
46825
|
+
});
|
|
46826
|
+
labels.push({
|
|
46827
|
+
x: tx,
|
|
46828
|
+
y: p.cy + FONT / 3,
|
|
46829
|
+
text,
|
|
46830
|
+
anchor: side === "right" ? "start" : "end",
|
|
46831
|
+
color: palette.text,
|
|
46832
|
+
halo: true,
|
|
46833
|
+
haloColor: palette.bg,
|
|
46834
|
+
poiId: p.id,
|
|
46835
|
+
lineNumber: p.lineNumber
|
|
46836
|
+
});
|
|
46837
|
+
};
|
|
46838
|
+
const inlineFits = (p, w, side) => {
|
|
46839
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46840
|
+
const rect = {
|
|
46841
|
+
x: side === "right" ? tx : tx - w,
|
|
46842
|
+
y: p.cy - poiLabH / 2,
|
|
46843
|
+
w,
|
|
46844
|
+
h: poiLabH
|
|
46845
|
+
};
|
|
46846
|
+
return rect.x >= 0 && rect.x + rect.w <= width && !collides(rect);
|
|
46847
|
+
};
|
|
46848
|
+
const GROUP_R = 30;
|
|
46849
|
+
const groups = [];
|
|
46850
|
+
for (const p of ordered) {
|
|
46851
|
+
const near = groups.find(
|
|
46852
|
+
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
46853
|
+
);
|
|
46854
|
+
if (near) near.push(p);
|
|
46855
|
+
else groups.push([p]);
|
|
46856
|
+
}
|
|
46857
|
+
const ROW_GAP2 = 3;
|
|
46858
|
+
const step = poiLabH + ROW_GAP2;
|
|
46859
|
+
const COL_GAP = 16;
|
|
46860
|
+
const placeColumn = (group) => {
|
|
46861
|
+
const items = group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
46862
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
46863
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
46864
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
46865
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
46866
|
+
const side = right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
46867
|
+
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
46868
|
+
const totalH = items.length * step;
|
|
46869
|
+
let startY = cyMid - totalH / 2;
|
|
46870
|
+
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
46871
|
+
items.forEach((o, i) => {
|
|
46872
|
+
const rowCy = startY + i * step + step / 2;
|
|
46873
|
+
obstacles.push({
|
|
46874
|
+
x: side === "right" ? colX : colX - o.w,
|
|
46875
|
+
y: rowCy - poiLabH / 2,
|
|
46876
|
+
w: o.w,
|
|
46877
|
+
h: poiLabH
|
|
46878
|
+
});
|
|
46241
46879
|
labels.push({
|
|
46242
|
-
x:
|
|
46243
|
-
y:
|
|
46244
|
-
text,
|
|
46245
|
-
anchor: "start",
|
|
46880
|
+
x: colX,
|
|
46881
|
+
y: rowCy + FONT / 3,
|
|
46882
|
+
text: o.text,
|
|
46883
|
+
anchor: side === "right" ? "start" : "end",
|
|
46246
46884
|
color: palette.text,
|
|
46247
46885
|
halo: true,
|
|
46248
|
-
|
|
46886
|
+
haloColor: palette.bg,
|
|
46887
|
+
leader: {
|
|
46888
|
+
x1: o.p.cx,
|
|
46889
|
+
y1: o.p.cy,
|
|
46890
|
+
x2: side === "right" ? colX - 2 : colX + 2,
|
|
46891
|
+
y2: rowCy
|
|
46892
|
+
},
|
|
46893
|
+
leaderColor: o.p.fill,
|
|
46894
|
+
poiId: o.p.id,
|
|
46895
|
+
lineNumber: o.p.lineNumber
|
|
46249
46896
|
});
|
|
46250
|
-
|
|
46251
|
-
|
|
46252
|
-
|
|
46253
|
-
|
|
46254
|
-
|
|
46255
|
-
|
|
46256
|
-
|
|
46257
|
-
|
|
46258
|
-
|
|
46259
|
-
|
|
46260
|
-
|
|
46261
|
-
|
|
46262
|
-
|
|
46263
|
-
if (rect.x < 0 || rect.x + rect.w > width || rect.y < 0 || rect.y + rect.h > height) {
|
|
46264
|
-
continue;
|
|
46265
|
-
}
|
|
46266
|
-
if (collides(rect)) continue;
|
|
46267
|
-
obstacles.push(rect);
|
|
46268
|
-
labels.push({
|
|
46269
|
-
x: cx,
|
|
46270
|
-
y: cy + FONT / 3,
|
|
46271
|
-
text,
|
|
46272
|
-
anchor: dx >= 0 ? "start" : "end",
|
|
46273
|
-
color: palette.text,
|
|
46274
|
-
halo: true,
|
|
46275
|
-
leader: { x1: p.cx, y1: p.cy, x2: cx, y2: cy },
|
|
46276
|
-
lineNumber: p.lineNumber
|
|
46277
|
-
});
|
|
46278
|
-
placed = true;
|
|
46279
|
-
break;
|
|
46897
|
+
});
|
|
46898
|
+
};
|
|
46899
|
+
for (const g of groups) {
|
|
46900
|
+
if (g.length === 1) {
|
|
46901
|
+
const p = g[0];
|
|
46902
|
+
const { text, w } = labelInfo(p);
|
|
46903
|
+
if (inlineFits(p, w, "right")) {
|
|
46904
|
+
pushInline(p, text, w, "right");
|
|
46905
|
+
continue;
|
|
46906
|
+
}
|
|
46907
|
+
if (inlineFits(p, w, "left")) {
|
|
46908
|
+
pushInline(p, text, w, "left");
|
|
46909
|
+
continue;
|
|
46280
46910
|
}
|
|
46281
46911
|
}
|
|
46282
|
-
|
|
46283
|
-
pinCounter += 1;
|
|
46284
|
-
pinList.push({ pin: pinCounter, label: text });
|
|
46285
|
-
labels.push({
|
|
46286
|
-
x: p.cx + p.r + 2,
|
|
46287
|
-
y: p.cy - p.r,
|
|
46288
|
-
text: String(pinCounter),
|
|
46289
|
-
anchor: "start",
|
|
46290
|
-
color: palette.text,
|
|
46291
|
-
halo: true,
|
|
46292
|
-
pin: pinCounter,
|
|
46293
|
-
lineNumber: p.lineNumber
|
|
46294
|
-
});
|
|
46912
|
+
placeColumn(g);
|
|
46295
46913
|
}
|
|
46296
46914
|
}
|
|
46297
46915
|
let legend = null;
|
|
@@ -46300,8 +46918,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46300
46918
|
name: g.name,
|
|
46301
46919
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
46302
46920
|
}));
|
|
46303
|
-
|
|
46304
|
-
if (hasAnything) {
|
|
46921
|
+
if (tagGroups.length > 0 || hasRamp) {
|
|
46305
46922
|
legend = {
|
|
46306
46923
|
tagGroups,
|
|
46307
46924
|
activeGroup,
|
|
@@ -46312,20 +46929,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46312
46929
|
},
|
|
46313
46930
|
min: rampMin,
|
|
46314
46931
|
max: rampMax,
|
|
46315
|
-
hue: rampHue
|
|
46932
|
+
hue: rampHue,
|
|
46933
|
+
base: rampBase
|
|
46316
46934
|
}
|
|
46317
|
-
},
|
|
46318
|
-
...sizeVals.length > 0 && {
|
|
46319
|
-
size: {
|
|
46320
|
-
...resolved.directives.sizeMetric !== void 0 && {
|
|
46321
|
-
metric: resolved.directives.sizeMetric
|
|
46322
|
-
},
|
|
46323
|
-
min: sizeMin,
|
|
46324
|
-
max: sizeMax
|
|
46325
|
-
}
|
|
46326
|
-
},
|
|
46327
|
-
...weightVals.length > 0 && {
|
|
46328
|
-
weight: { min: wMin, max: wMax }
|
|
46329
46935
|
}
|
|
46330
46936
|
};
|
|
46331
46937
|
}
|
|
@@ -46333,26 +46939,28 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46333
46939
|
return {
|
|
46334
46940
|
width,
|
|
46335
46941
|
height,
|
|
46336
|
-
background:
|
|
46942
|
+
background: water,
|
|
46337
46943
|
title: resolved.title,
|
|
46338
46944
|
...resolved.subtitle !== void 0 && { subtitle: resolved.subtitle },
|
|
46339
46945
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
46340
46946
|
regions,
|
|
46947
|
+
rivers,
|
|
46341
46948
|
legs,
|
|
46342
46949
|
pois,
|
|
46343
46950
|
labels,
|
|
46344
|
-
|
|
46345
|
-
|
|
46951
|
+
legend,
|
|
46952
|
+
insets,
|
|
46953
|
+
insetRegions
|
|
46346
46954
|
};
|
|
46347
46955
|
}
|
|
46348
|
-
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT,
|
|
46956
|
+
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;
|
|
46349
46957
|
var init_layout15 = __esm({
|
|
46350
46958
|
"src/map/layout.ts"() {
|
|
46351
46959
|
"use strict";
|
|
46352
46960
|
init_color_utils();
|
|
46353
|
-
init_tag_groups();
|
|
46354
46961
|
init_label_layout();
|
|
46355
46962
|
init_legend_constants();
|
|
46963
|
+
init_title_constants();
|
|
46356
46964
|
FIT_PAD = 24;
|
|
46357
46965
|
RAMP_FLOOR = 15;
|
|
46358
46966
|
R_DEFAULT = 6;
|
|
@@ -46361,23 +46969,32 @@ var init_layout15 = __esm({
|
|
|
46361
46969
|
W_MIN = 1.25;
|
|
46362
46970
|
W_MAX = 8;
|
|
46363
46971
|
FONT = 11;
|
|
46364
|
-
LEADER_STEP = 14;
|
|
46365
46972
|
COLO_EPS = 1.5;
|
|
46973
|
+
LAND_TINT_LIGHT = 58;
|
|
46974
|
+
LAND_TINT_DARK = 75;
|
|
46975
|
+
TAG_TINT_LIGHT = 60;
|
|
46976
|
+
TAG_TINT_DARK = 68;
|
|
46977
|
+
WATER_TINT = 55;
|
|
46978
|
+
RIVER_WIDTH = 1.3;
|
|
46979
|
+
FOREIGN_TINT_LIGHT = 30;
|
|
46980
|
+
FOREIGN_TINT_DARK = 62;
|
|
46366
46981
|
COLO_R = 9;
|
|
46367
46982
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
46368
46983
|
FAN_STEP = 16;
|
|
46369
|
-
TINY_REGION_AREA = 600;
|
|
46370
46984
|
ARC_CURVE_FRAC = 0.18;
|
|
46371
|
-
|
|
46372
|
-
|
|
46373
|
-
|
|
46374
|
-
|
|
46375
|
-
|
|
46376
|
-
|
|
46377
|
-
|
|
46378
|
-
|
|
46379
|
-
|
|
46380
|
-
|
|
46985
|
+
usConusProjection = () => geoConicEqualArea().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
46986
|
+
alaskaProjection = () => geoConicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
46987
|
+
hawaiiProjection = () => geoMercator();
|
|
46988
|
+
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
46989
|
+
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
46990
|
+
"US-AK",
|
|
46991
|
+
"US-HI",
|
|
46992
|
+
"US-AS",
|
|
46993
|
+
"US-GU",
|
|
46994
|
+
"US-MP",
|
|
46995
|
+
"US-PR",
|
|
46996
|
+
"US-VI"
|
|
46997
|
+
]);
|
|
46381
46998
|
}
|
|
46382
46999
|
});
|
|
46383
47000
|
|
|
@@ -46388,7 +47005,7 @@ __export(renderer_exports16, {
|
|
|
46388
47005
|
renderMapForExport: () => renderMapForExport
|
|
46389
47006
|
});
|
|
46390
47007
|
import * as d3Selection18 from "d3-selection";
|
|
46391
|
-
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims) {
|
|
47008
|
+
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
46392
47009
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
46393
47010
|
const width = exportDims?.width ?? container.clientWidth;
|
|
46394
47011
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -46399,27 +47016,29 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46399
47016
|
{ width, height },
|
|
46400
47017
|
{
|
|
46401
47018
|
palette,
|
|
46402
|
-
isDark
|
|
47019
|
+
isDark,
|
|
47020
|
+
...activeGroupOverride !== void 0 && {
|
|
47021
|
+
activeGroup: activeGroupOverride
|
|
47022
|
+
}
|
|
46403
47023
|
}
|
|
46404
47024
|
);
|
|
46405
|
-
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);
|
|
47025
|
+
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);
|
|
46406
47026
|
svg.append("rect").attr("width", width).attr("height", height).attr("fill", layout.background);
|
|
46407
|
-
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
46408
47027
|
const defs = svg.append("defs");
|
|
46409
|
-
|
|
46410
|
-
const haloColor =
|
|
46411
|
-
if (layout.title) {
|
|
46412
|
-
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);
|
|
46413
|
-
}
|
|
46414
|
-
if (layout.subtitle) {
|
|
46415
|
-
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);
|
|
46416
|
-
}
|
|
46417
|
-
if (layout.caption) {
|
|
46418
|
-
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);
|
|
46419
|
-
}
|
|
47028
|
+
const arrowSize = (w) => Math.min(15, 7 + w * 0.95);
|
|
47029
|
+
const haloColor = palette.bg;
|
|
46420
47030
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
46421
|
-
|
|
46422
|
-
const p =
|
|
47031
|
+
const drawRegion = (g, r, strokeWidth) => {
|
|
47032
|
+
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
47033
|
+
if (r.layer !== "base") {
|
|
47034
|
+
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47035
|
+
if (r.score !== void 0) p.attr("data-score", r.score);
|
|
47036
|
+
if (r.tags) {
|
|
47037
|
+
for (const [group, value] of Object.entries(r.tags)) {
|
|
47038
|
+
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
47039
|
+
}
|
|
47040
|
+
}
|
|
47041
|
+
}
|
|
46423
47042
|
if (r.lineNumber >= 0) {
|
|
46424
47043
|
p.attr("data-line-number", r.lineNumber);
|
|
46425
47044
|
if (onClickItem) {
|
|
@@ -46429,11 +47048,31 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46429
47048
|
);
|
|
46430
47049
|
}
|
|
46431
47050
|
}
|
|
47051
|
+
};
|
|
47052
|
+
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
47053
|
+
if (layout.rivers.length) {
|
|
47054
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47055
|
+
for (const r of layout.rivers) {
|
|
47056
|
+
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
47057
|
+
}
|
|
47058
|
+
}
|
|
47059
|
+
if (layout.insets.length) {
|
|
47060
|
+
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47061
|
+
for (const box of layout.insets) {
|
|
47062
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47063
|
+
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");
|
|
47064
|
+
}
|
|
47065
|
+
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
46432
47066
|
}
|
|
46433
47067
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
46434
|
-
|
|
47068
|
+
layout.legs.forEach((leg, i) => {
|
|
46435
47069
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
46436
|
-
if (leg.arrow)
|
|
47070
|
+
if (leg.arrow) {
|
|
47071
|
+
const id = `dgmo-map-arrow-${i}`;
|
|
47072
|
+
const s = arrowSize(leg.width);
|
|
47073
|
+
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);
|
|
47074
|
+
p.attr("marker-end", `url(#${id})`);
|
|
47075
|
+
}
|
|
46437
47076
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
46438
47077
|
emitText(
|
|
46439
47078
|
gLegs,
|
|
@@ -46447,13 +47086,13 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46447
47086
|
LABEL_FONT - 1
|
|
46448
47087
|
);
|
|
46449
47088
|
}
|
|
46450
|
-
}
|
|
47089
|
+
});
|
|
46451
47090
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
46452
47091
|
for (const poi of layout.pois) {
|
|
46453
47092
|
if (poi.isOrigin) {
|
|
46454
47093
|
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);
|
|
46455
47094
|
}
|
|
46456
|
-
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);
|
|
47095
|
+
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);
|
|
46457
47096
|
if (onClickItem) {
|
|
46458
47097
|
c.style("cursor", "pointer").on(
|
|
46459
47098
|
"click",
|
|
@@ -46477,48 +47116,66 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46477
47116
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
46478
47117
|
for (const lab of layout.labels) {
|
|
46479
47118
|
if (lab.leader) {
|
|
46480
|
-
gLabels.append("line").attr("x1", lab.leader.x1).attr("y1", lab.leader.y1).attr("x2", lab.leader.x2).attr("y2", lab.leader.y2).attr(
|
|
46481
|
-
|
|
46482
|
-
|
|
46483
|
-
|
|
47119
|
+
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(
|
|
47120
|
+
"stroke",
|
|
47121
|
+
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47122
|
+
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47123
|
+
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
46484
47124
|
}
|
|
46485
|
-
emitText(
|
|
47125
|
+
const t = emitText(
|
|
46486
47126
|
gLabels,
|
|
46487
47127
|
lab.x,
|
|
46488
47128
|
lab.y,
|
|
46489
47129
|
lab.text,
|
|
46490
47130
|
lab.anchor,
|
|
46491
47131
|
lab.color,
|
|
46492
|
-
haloColor,
|
|
47132
|
+
lab.haloColor,
|
|
46493
47133
|
lab.halo,
|
|
46494
47134
|
LABEL_FONT
|
|
46495
47135
|
);
|
|
46496
|
-
|
|
46497
|
-
|
|
46498
|
-
|
|
46499
|
-
"transform",
|
|
46500
|
-
`translate(12, ${height - layout.pinList.length * 14 - 8})`
|
|
46501
|
-
);
|
|
46502
|
-
layout.pinList.forEach((entry, i) => {
|
|
46503
|
-
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}`);
|
|
46504
|
-
});
|
|
47136
|
+
if (lab.poiId !== void 0) {
|
|
47137
|
+
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47138
|
+
}
|
|
46505
47139
|
}
|
|
46506
47140
|
if (layout.legend) {
|
|
46507
47141
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
46508
47142
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
46509
|
-
const
|
|
47143
|
+
const ramp = layout.legend.ramp;
|
|
47144
|
+
const scoreGroup = ramp ? {
|
|
47145
|
+
name: ramp.metric?.trim() || "Score",
|
|
47146
|
+
entries: [],
|
|
47147
|
+
gradient: {
|
|
47148
|
+
min: ramp.min,
|
|
47149
|
+
max: ramp.max,
|
|
47150
|
+
hue: ramp.hue,
|
|
47151
|
+
base: ramp.base
|
|
47152
|
+
}
|
|
47153
|
+
} : null;
|
|
47154
|
+
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47155
|
+
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
46510
47156
|
if (groups.length > 0) {
|
|
46511
47157
|
const config = {
|
|
46512
|
-
groups
|
|
47158
|
+
groups,
|
|
46513
47159
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
46514
47160
|
mode: exportDims ? "export" : "preview",
|
|
46515
|
-
showEmptyGroups: false
|
|
47161
|
+
showEmptyGroups: false,
|
|
47162
|
+
// Keep inactive siblings visible as pills so the user can click to flip
|
|
47163
|
+
// the active colouring dimension (preview only — export shows just the
|
|
47164
|
+
// active group).
|
|
47165
|
+
showInactivePills: true
|
|
46516
47166
|
};
|
|
46517
47167
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
46518
47168
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
46519
47169
|
}
|
|
46520
|
-
|
|
46521
|
-
|
|
47170
|
+
}
|
|
47171
|
+
if (layout.title) {
|
|
47172
|
+
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);
|
|
47173
|
+
}
|
|
47174
|
+
if (layout.subtitle) {
|
|
47175
|
+
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);
|
|
47176
|
+
}
|
|
47177
|
+
if (layout.caption) {
|
|
47178
|
+
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);
|
|
46522
47179
|
}
|
|
46523
47180
|
}
|
|
46524
47181
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
@@ -46529,54 +47186,7 @@ function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
|
46529
47186
|
if (withHalo) {
|
|
46530
47187
|
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7);
|
|
46531
47188
|
}
|
|
46532
|
-
|
|
46533
|
-
function emitExtraLegend(svg, layout, palette, height, bottomGap) {
|
|
46534
|
-
const { legend } = layout;
|
|
46535
|
-
if (!legend) return;
|
|
46536
|
-
if (!legend.ramp && !legend.size && !legend.weight) return;
|
|
46537
|
-
const blocks = [];
|
|
46538
|
-
const g = svg.append("g").attr("class", "dgmo-map-legend-keys").attr("transform", `translate(12, ${height - 56 - bottomGap})`);
|
|
46539
|
-
let xCursor = 0;
|
|
46540
|
-
if (legend.ramp) {
|
|
46541
|
-
const ramp = legend.ramp;
|
|
46542
|
-
blocks.push(() => {
|
|
46543
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46544
|
-
const gradId = "dgmo-map-ramp";
|
|
46545
|
-
const grad = block.append("defs").append("linearGradient").attr("id", gradId).attr("x1", "0%").attr("x2", "100%");
|
|
46546
|
-
grad.append("stop").attr("offset", "0%").attr("stop-color", mix(ramp.hue, palette.bg, 15));
|
|
46547
|
-
grad.append("stop").attr("offset", "100%").attr("stop-color", ramp.hue);
|
|
46548
|
-
block.append("rect").attr("width", 80).attr("height", 8).attr("fill", `url(#${gradId})`);
|
|
46549
|
-
block.append("text").attr("x", 0).attr("y", 22).attr("font-size", 9).attr("fill", palette.textMuted).text(String(ramp.min));
|
|
46550
|
-
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));
|
|
46551
|
-
if (ramp.metric) {
|
|
46552
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(ramp.metric);
|
|
46553
|
-
}
|
|
46554
|
-
xCursor += 110;
|
|
46555
|
-
});
|
|
46556
|
-
}
|
|
46557
|
-
if (legend.size) {
|
|
46558
|
-
const sz = legend.size;
|
|
46559
|
-
blocks.push(() => {
|
|
46560
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46561
|
-
[3, 6, 10].forEach((r, i) => {
|
|
46562
|
-
block.append("circle").attr("cx", i * 26 + r).attr("cy", 8).attr("r", r).attr("fill", "none").attr("stroke", palette.textMuted);
|
|
46563
|
-
});
|
|
46564
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(sz.metric ?? "size");
|
|
46565
|
-
xCursor += 110;
|
|
46566
|
-
});
|
|
46567
|
-
}
|
|
46568
|
-
if (legend.weight) {
|
|
46569
|
-
const wt = legend.weight;
|
|
46570
|
-
blocks.push(() => {
|
|
46571
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46572
|
-
[1, 3, 6].forEach((w, i) => {
|
|
46573
|
-
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);
|
|
46574
|
-
});
|
|
46575
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(wt.metric ?? "weight");
|
|
46576
|
-
xCursor += 110;
|
|
46577
|
-
});
|
|
46578
|
-
}
|
|
46579
|
-
for (const draw of blocks) draw();
|
|
47189
|
+
return t;
|
|
46580
47190
|
}
|
|
46581
47191
|
var LABEL_FONT;
|
|
46582
47192
|
var init_renderer16 = __esm({
|
|
@@ -56435,7 +57045,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
|
|
|
56435
57045
|
|
|
56436
57046
|
// src/auto/index.ts
|
|
56437
57047
|
init_safe_href();
|
|
56438
|
-
var VERSION = "0.
|
|
57048
|
+
var VERSION = "0.20.0";
|
|
56439
57049
|
var DEFAULTS = {
|
|
56440
57050
|
theme: "auto",
|
|
56441
57051
|
palette: "nord",
|