@diagrammo/dgmo 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.cjs +948 -321
- package/dist/advanced.d.cts +148 -54
- package/dist/advanced.d.ts +148 -54
- package/dist/advanced.js +949 -321
- package/dist/auto.cjs +930 -317
- package/dist/auto.js +117 -117
- package/dist/auto.mjs +934 -318
- package/dist/cli.cjs +160 -160
- package/dist/index.cjs +929 -316
- package/dist/index.js +933 -317
- package/dist/internal.cjs +948 -321
- package/dist/internal.d.cts +148 -54
- package/dist/internal.d.ts +148 -54
- package/dist/internal.js +949 -321
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/lakes.json +1 -0
- package/dist/map-data/na-lakes.json +1 -0
- package/dist/map-data/na-land.json +1 -0
- package/dist/map-data/rivers.json +1 -0
- package/docs/language-reference.md +12 -7
- package/gallery/fixtures/map-region-scope.dgmo +15 -0
- package/package.json +4 -4
- package/src/advanced.ts +7 -6
- package/src/c4/parser.ts +6 -6
- package/src/completion.ts +6 -2
- package/src/echarts.ts +1 -1
- package/src/infra/parser.ts +10 -10
- package/src/journey-map/parser.ts +1 -1
- package/src/label-layout.ts +36 -0
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/README.md +2 -0
- package/src/map/data/lakes.json +1 -0
- package/src/map/data/na-lakes.json +1 -0
- package/src/map/data/na-land.json +1 -0
- package/src/map/data/rivers.json +1 -0
- package/src/map/layout.ts +1022 -205
- package/src/map/load-data.ts +73 -17
- package/src/map/parser.ts +22 -13
- package/src/map/renderer.ts +200 -219
- package/src/map/resolved-types.ts +18 -1
- package/src/map/resolver.ts +79 -7
- package/src/map/types.ts +4 -0
- package/src/mindmap/parser.ts +1 -1
- package/src/sitemap/parser.ts +1 -1
- package/src/utils/legend-d3.ts +42 -0
- package/src/utils/legend-layout.ts +83 -3
- package/src/utils/legend-svg.ts +1 -8
- package/src/utils/legend-types.ts +44 -1
package/dist/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",
|
|
@@ -45820,17 +45957,22 @@ var load_data_exports = {};
|
|
|
45820
45957
|
__export(load_data_exports, {
|
|
45821
45958
|
loadMapData: () => loadMapData
|
|
45822
45959
|
});
|
|
45823
|
-
|
|
45824
|
-
|
|
45825
|
-
import
|
|
45826
|
-
|
|
45827
|
-
|
|
45960
|
+
async function loadNodeBuiltins() {
|
|
45961
|
+
const [{ readFile }, { fileURLToPath }, { dirname, resolve }] = await Promise.all([
|
|
45962
|
+
import("fs/promises"),
|
|
45963
|
+
import("url"),
|
|
45964
|
+
import("path")
|
|
45965
|
+
]);
|
|
45966
|
+
return { readFile, fileURLToPath, dirname, resolve };
|
|
45967
|
+
}
|
|
45968
|
+
async function readJson(nb, dir, name) {
|
|
45969
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
45828
45970
|
}
|
|
45829
|
-
async function firstExistingDir(baseDir) {
|
|
45971
|
+
async function firstExistingDir(nb, baseDir) {
|
|
45830
45972
|
for (const rel of CANDIDATE_DIRS) {
|
|
45831
|
-
const dir = resolve(baseDir, rel);
|
|
45973
|
+
const dir = nb.resolve(baseDir, rel);
|
|
45832
45974
|
try {
|
|
45833
|
-
await readFile(resolve(dir, FILES.gazetteer), "utf8");
|
|
45975
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
45834
45976
|
return dir;
|
|
45835
45977
|
} catch {
|
|
45836
45978
|
}
|
|
@@ -45846,10 +45988,10 @@ function validate(data) {
|
|
|
45846
45988
|
}
|
|
45847
45989
|
return data;
|
|
45848
45990
|
}
|
|
45849
|
-
function moduleBaseDir() {
|
|
45991
|
+
function moduleBaseDir(nb) {
|
|
45850
45992
|
try {
|
|
45851
45993
|
const url = import.meta.url;
|
|
45852
|
-
if (url) return dirname(fileURLToPath(url));
|
|
45994
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
45853
45995
|
} catch {
|
|
45854
45996
|
}
|
|
45855
45997
|
if (typeof __dirname !== "undefined") return __dirname;
|
|
@@ -45857,14 +45999,38 @@ function moduleBaseDir() {
|
|
|
45857
45999
|
}
|
|
45858
46000
|
function loadMapData() {
|
|
45859
46001
|
cache ??= (async () => {
|
|
45860
|
-
const
|
|
45861
|
-
const
|
|
45862
|
-
|
|
45863
|
-
|
|
45864
|
-
|
|
45865
|
-
|
|
46002
|
+
const nb = await loadNodeBuiltins();
|
|
46003
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
46004
|
+
const [
|
|
46005
|
+
worldCoarse,
|
|
46006
|
+
worldDetail,
|
|
46007
|
+
usStates,
|
|
46008
|
+
lakes,
|
|
46009
|
+
rivers,
|
|
46010
|
+
naLand,
|
|
46011
|
+
naLakes,
|
|
46012
|
+
gazetteer
|
|
46013
|
+
] = await Promise.all([
|
|
46014
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
46015
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
46016
|
+
readJson(nb, dir, FILES.usStates),
|
|
46017
|
+
// Lakes/rivers/NA assets are optional — older bundles may predate them.
|
|
46018
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
46019
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
46020
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
46021
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
46022
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
45866
46023
|
]);
|
|
45867
|
-
return validate({
|
|
46024
|
+
return validate({
|
|
46025
|
+
worldCoarse,
|
|
46026
|
+
worldDetail,
|
|
46027
|
+
usStates,
|
|
46028
|
+
gazetteer,
|
|
46029
|
+
...lakes && { lakes },
|
|
46030
|
+
...rivers && { rivers },
|
|
46031
|
+
...naLand && { naLand },
|
|
46032
|
+
...naLakes && { naLakes }
|
|
46033
|
+
});
|
|
45868
46034
|
})().catch((e) => {
|
|
45869
46035
|
cache = void 0;
|
|
45870
46036
|
throw e;
|
|
@@ -45879,6 +46045,10 @@ var init_load_data = __esm({
|
|
|
45879
46045
|
worldCoarse: "world-coarse.json",
|
|
45880
46046
|
worldDetail: "world-detail.json",
|
|
45881
46047
|
usStates: "us-states.json",
|
|
46048
|
+
lakes: "lakes.json",
|
|
46049
|
+
rivers: "rivers.json",
|
|
46050
|
+
naLand: "na-land.json",
|
|
46051
|
+
naLakes: "na-lakes.json",
|
|
45882
46052
|
gazetteer: "gazetteer.json"
|
|
45883
46053
|
};
|
|
45884
46054
|
CANDIDATE_DIRS = [
|
|
@@ -45894,8 +46064,11 @@ var init_load_data = __esm({
|
|
|
45894
46064
|
import {
|
|
45895
46065
|
geoPath,
|
|
45896
46066
|
geoNaturalEarth1,
|
|
45897
|
-
|
|
45898
|
-
|
|
46067
|
+
geoEquirectangular,
|
|
46068
|
+
geoConicEqualArea,
|
|
46069
|
+
geoMercator,
|
|
46070
|
+
geoBounds as geoBounds2,
|
|
46071
|
+
geoTransform
|
|
45899
46072
|
} from "d3-geo";
|
|
45900
46073
|
import { feature as feature2 } from "topojson-client";
|
|
45901
46074
|
function geomObject2(topo) {
|
|
@@ -45913,36 +46086,67 @@ function decodeLayer(topo) {
|
|
|
45913
46086
|
function projectionFor(family) {
|
|
45914
46087
|
switch (family) {
|
|
45915
46088
|
case "albers-usa":
|
|
45916
|
-
return
|
|
46089
|
+
return usConusProjection();
|
|
45917
46090
|
case "mercator":
|
|
45918
46091
|
return geoMercator();
|
|
45919
46092
|
case "natural-earth":
|
|
45920
|
-
default:
|
|
45921
46093
|
return geoNaturalEarth1();
|
|
46094
|
+
case "equirectangular":
|
|
46095
|
+
default:
|
|
46096
|
+
return geoEquirectangular();
|
|
45922
46097
|
}
|
|
45923
46098
|
}
|
|
46099
|
+
function mapBackgroundColor(palette) {
|
|
46100
|
+
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
46101
|
+
}
|
|
45924
46102
|
function layoutMap(resolved, data, size, opts) {
|
|
45925
46103
|
const { palette, isDark } = opts;
|
|
45926
46104
|
const { width, height } = size;
|
|
45927
|
-
const
|
|
46105
|
+
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46106
|
+
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
46107
|
+
const worldTopo = usCrisp ? data.naLand : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
45928
46108
|
const worldLayer = decodeLayer(worldTopo);
|
|
45929
|
-
const usLayer =
|
|
45930
|
-
const
|
|
45931
|
-
const
|
|
46109
|
+
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
46110
|
+
const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
|
|
46111
|
+
const neutralFill = mix(palette.colors.green, palette.bg, landTint);
|
|
46112
|
+
const water = mapBackgroundColor(palette);
|
|
46113
|
+
const usContext = usLayer !== null;
|
|
46114
|
+
const foreignFill = mix(
|
|
46115
|
+
palette.colors.gray,
|
|
46116
|
+
palette.bg,
|
|
46117
|
+
isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46118
|
+
);
|
|
46119
|
+
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
45932
46120
|
const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
|
|
45933
46121
|
const scaleOverride = resolved.directives.scale;
|
|
45934
46122
|
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
|
|
45935
46123
|
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
|
|
45936
|
-
const rampHue = palette.
|
|
46124
|
+
const rampHue = palette.colors.red;
|
|
45937
46125
|
const hasRamp = scores.length > 0;
|
|
45938
|
-
const
|
|
45939
|
-
|
|
45940
|
-
|
|
45941
|
-
|
|
46126
|
+
const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
|
|
46127
|
+
const matchColorGroup = (v) => {
|
|
46128
|
+
const lv = v.trim().toLowerCase();
|
|
46129
|
+
if (lv === "none") return null;
|
|
46130
|
+
if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
|
|
46131
|
+
return SCORE_NAME;
|
|
46132
|
+
const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
46133
|
+
return tg ? tg.name : v;
|
|
46134
|
+
};
|
|
46135
|
+
const override = opts.activeGroup;
|
|
46136
|
+
let activeGroup;
|
|
46137
|
+
if (override !== void 0) {
|
|
46138
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
46139
|
+
} else if (resolved.directives.activeTag !== void 0) {
|
|
46140
|
+
activeGroup = matchColorGroup(resolved.directives.activeTag);
|
|
46141
|
+
} else {
|
|
46142
|
+
activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46143
|
+
}
|
|
46144
|
+
const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
|
|
46145
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
45942
46146
|
const fillForScore = (s) => {
|
|
45943
46147
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
45944
46148
|
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
45945
|
-
return mix(rampHue,
|
|
46149
|
+
return mix(rampHue, rampBase, pct);
|
|
45946
46150
|
};
|
|
45947
46151
|
const tagFill = (tags, groupName) => {
|
|
45948
46152
|
if (!groupName) return null;
|
|
@@ -45956,40 +46160,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
45956
46160
|
(e) => e.value.toLowerCase() === val.toLowerCase()
|
|
45957
46161
|
);
|
|
45958
46162
|
if (!entry?.color) return null;
|
|
45959
|
-
return
|
|
46163
|
+
return mix(
|
|
46164
|
+
entry.color,
|
|
46165
|
+
palette.bg,
|
|
46166
|
+
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46167
|
+
);
|
|
46168
|
+
};
|
|
46169
|
+
const regionFill = (r) => {
|
|
46170
|
+
if (activeIsScore) {
|
|
46171
|
+
return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
|
|
46172
|
+
}
|
|
46173
|
+
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
45960
46174
|
};
|
|
45961
46175
|
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 = () => {
|
|
46176
|
+
const extentOutline = () => {
|
|
45968
46177
|
const [[w, s], [e, n]] = resolved.extent;
|
|
46178
|
+
const N = 16;
|
|
46179
|
+
const coords = [];
|
|
46180
|
+
for (let i = 0; i <= N; i++) {
|
|
46181
|
+
const t = i / N;
|
|
46182
|
+
const lon = w + (e - w) * t;
|
|
46183
|
+
const lat = s + (n - s) * t;
|
|
46184
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46185
|
+
}
|
|
45969
46186
|
return {
|
|
45970
46187
|
type: "Feature",
|
|
45971
46188
|
properties: {},
|
|
45972
|
-
geometry: {
|
|
45973
|
-
type: "MultiPoint",
|
|
45974
|
-
coordinates: [
|
|
45975
|
-
[w, s],
|
|
45976
|
-
[e, s],
|
|
45977
|
-
[e, n],
|
|
45978
|
-
[w, n]
|
|
45979
|
-
]
|
|
45980
|
-
}
|
|
46189
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
45981
46190
|
};
|
|
45982
46191
|
};
|
|
45983
46192
|
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
|
-
}
|
|
46193
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46194
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
45991
46195
|
} else {
|
|
45992
|
-
fitFeatures = [
|
|
46196
|
+
fitFeatures = [extentOutline()];
|
|
45993
46197
|
}
|
|
45994
46198
|
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
45995
46199
|
const projection = projectionFor(resolved.projection);
|
|
@@ -45998,32 +46202,311 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
45998
46202
|
if (centerLon > 180) centerLon -= 360;
|
|
45999
46203
|
projection.rotate([-centerLon, 0]);
|
|
46000
46204
|
}
|
|
46001
|
-
|
|
46205
|
+
const TITLE_GAP = 16;
|
|
46206
|
+
let topPad = FIT_PAD;
|
|
46207
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
46208
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46209
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP);
|
|
46210
|
+
}
|
|
46211
|
+
const fitBox = [
|
|
46212
|
+
[FIT_PAD, topPad],
|
|
46002
46213
|
[
|
|
46003
|
-
|
|
46004
|
-
|
|
46005
|
-
|
|
46006
|
-
|
|
46007
|
-
|
|
46008
|
-
|
|
46009
|
-
|
|
46010
|
-
|
|
46011
|
-
|
|
46012
|
-
|
|
46214
|
+
Math.max(FIT_PAD + 1, width - FIT_PAD),
|
|
46215
|
+
Math.max(topPad + 1, height - FIT_PAD)
|
|
46216
|
+
]
|
|
46217
|
+
];
|
|
46218
|
+
projection.fitExtent(fitBox, fitTarget);
|
|
46219
|
+
const fitGB = geoBounds2(fitTarget);
|
|
46220
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46221
|
+
let path;
|
|
46222
|
+
let project;
|
|
46223
|
+
if (fitIsGlobal) {
|
|
46224
|
+
const cb = geoPath(projection).bounds(fitTarget);
|
|
46225
|
+
const bx0 = cb[0][0];
|
|
46226
|
+
const by0 = cb[0][1];
|
|
46227
|
+
const cw = cb[1][0] - bx0;
|
|
46228
|
+
const ch = cb[1][1] - by0;
|
|
46229
|
+
const ox = fitBox[0][0];
|
|
46230
|
+
const oy = fitBox[0][1];
|
|
46231
|
+
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46232
|
+
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
46233
|
+
const stretch = (x, y) => [
|
|
46234
|
+
ox + (x - bx0) * sx,
|
|
46235
|
+
oy + (y - by0) * sy
|
|
46236
|
+
];
|
|
46237
|
+
const baseProjection = projection;
|
|
46238
|
+
const tx = geoTransform({
|
|
46239
|
+
point(x, y) {
|
|
46240
|
+
const [px, py] = stretch(x, y);
|
|
46241
|
+
this.stream.point(px, py);
|
|
46242
|
+
}
|
|
46243
|
+
});
|
|
46244
|
+
path = geoPath({
|
|
46245
|
+
stream: (s) => baseProjection.stream(
|
|
46246
|
+
tx.stream(s)
|
|
46247
|
+
)
|
|
46248
|
+
});
|
|
46249
|
+
project = (lon, lat) => {
|
|
46250
|
+
const p = baseProjection([lon, lat]);
|
|
46251
|
+
return p ? stretch(p[0], p[1]) : null;
|
|
46252
|
+
};
|
|
46253
|
+
} else {
|
|
46254
|
+
path = geoPath(projection);
|
|
46255
|
+
project = (lon, lat) => projection([lon, lat]) ?? null;
|
|
46256
|
+
}
|
|
46257
|
+
const insets = [];
|
|
46258
|
+
const insetRegions = [];
|
|
46259
|
+
const insetLabelSeeds = [];
|
|
46260
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46261
|
+
const PAD = 8;
|
|
46262
|
+
const GAP = 12;
|
|
46263
|
+
const yB = height - FIT_PAD;
|
|
46264
|
+
const BW = 8;
|
|
46265
|
+
const coast = /* @__PURE__ */ new Map();
|
|
46266
|
+
const addPt = (lon, lat) => {
|
|
46267
|
+
const p = projection([lon, lat]);
|
|
46268
|
+
if (!p) return;
|
|
46269
|
+
const bi = Math.floor(p[0] / BW);
|
|
46270
|
+
const cur = coast.get(bi);
|
|
46271
|
+
if (cur === void 0 || p[1] > cur) coast.set(bi, p[1]);
|
|
46272
|
+
};
|
|
46273
|
+
const walk = (co) => {
|
|
46274
|
+
if (Array.isArray(co) && typeof co[0] === "number")
|
|
46275
|
+
addPt(co[0], co[1]);
|
|
46276
|
+
else if (Array.isArray(co)) for (const c of co) walk(c);
|
|
46277
|
+
};
|
|
46278
|
+
for (const [iso, f] of usLayer) {
|
|
46279
|
+
if (US_NON_CONUS.has(iso)) continue;
|
|
46280
|
+
walk(f.geometry.coordinates);
|
|
46281
|
+
}
|
|
46282
|
+
const at = (x) => {
|
|
46283
|
+
const bi = Math.floor(x / BW);
|
|
46284
|
+
let y = -Infinity;
|
|
46285
|
+
for (let k = bi - 1; k <= bi + 1; k++) {
|
|
46286
|
+
const v = coast.get(k);
|
|
46287
|
+
if (v !== void 0 && v > y) y = v;
|
|
46288
|
+
}
|
|
46289
|
+
return y;
|
|
46290
|
+
};
|
|
46291
|
+
const coastTop = (x0, xr) => {
|
|
46292
|
+
const n = 24;
|
|
46293
|
+
const pts = [];
|
|
46294
|
+
let maxY = -Infinity;
|
|
46295
|
+
for (let i = 0; i <= n; i++) {
|
|
46296
|
+
const x = x0 + (xr - x0) * i / n;
|
|
46297
|
+
const y = at(x);
|
|
46298
|
+
if (y > -Infinity) {
|
|
46299
|
+
pts.push([x, y]);
|
|
46300
|
+
if (y > maxY) maxY = y;
|
|
46301
|
+
}
|
|
46302
|
+
}
|
|
46303
|
+
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46304
|
+
let m = 0;
|
|
46305
|
+
if (pts.length >= 2) {
|
|
46306
|
+
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46307
|
+
for (const [x, y] of pts) {
|
|
46308
|
+
sx += x;
|
|
46309
|
+
sy += y;
|
|
46310
|
+
sxx += x * x;
|
|
46311
|
+
sxy += x * y;
|
|
46312
|
+
}
|
|
46313
|
+
const den = pts.length * sxx - sx * sx;
|
|
46314
|
+
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46315
|
+
}
|
|
46316
|
+
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46317
|
+
let c = -Infinity;
|
|
46318
|
+
for (const [x, y] of pts) {
|
|
46319
|
+
const need = y - m * x + GAP;
|
|
46320
|
+
if (need > c) c = need;
|
|
46321
|
+
}
|
|
46322
|
+
return (x) => m * x + c;
|
|
46323
|
+
};
|
|
46324
|
+
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46325
|
+
const f = usLayer.get(iso);
|
|
46326
|
+
if (!f) return boxX;
|
|
46327
|
+
const x0 = boxX;
|
|
46328
|
+
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46329
|
+
if (iw < 24) return boxX;
|
|
46330
|
+
const xr = x0 + iw + 2 * PAD;
|
|
46331
|
+
const top = coastTop(x0, xr);
|
|
46332
|
+
const yL = top(x0);
|
|
46333
|
+
const yR = top(xr);
|
|
46334
|
+
proj.fitWidth(iw, f);
|
|
46335
|
+
const bb = geoPath(proj).bounds(f);
|
|
46336
|
+
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46337
|
+
const needH = sh + 2 * PAD;
|
|
46338
|
+
let topFit = Math.max(yL, yR);
|
|
46339
|
+
const bottom = Math.min(topFit + needH, yB);
|
|
46340
|
+
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46341
|
+
const lift = topFit - Math.max(yL, yR);
|
|
46342
|
+
const topL = yL + lift;
|
|
46343
|
+
const topR = yR + lift;
|
|
46344
|
+
proj.fitExtent(
|
|
46345
|
+
[
|
|
46346
|
+
[x0 + PAD, topFit + PAD],
|
|
46347
|
+
[xr - PAD, bottom - PAD]
|
|
46348
|
+
],
|
|
46349
|
+
f
|
|
46350
|
+
);
|
|
46351
|
+
const d = geoPath(proj)(f) ?? "";
|
|
46352
|
+
if (!d) return xr;
|
|
46353
|
+
const r = regionById.get(iso);
|
|
46354
|
+
let fill2 = neutralFill;
|
|
46355
|
+
let lineNumber = -1;
|
|
46356
|
+
if (r?.layer === "us-state") {
|
|
46357
|
+
fill2 = regionFill(r);
|
|
46358
|
+
lineNumber = r.lineNumber;
|
|
46359
|
+
}
|
|
46360
|
+
insets.push({
|
|
46361
|
+
x: x0,
|
|
46362
|
+
y: Math.min(topL, topR),
|
|
46363
|
+
w: xr - x0,
|
|
46364
|
+
h: bottom - Math.min(topL, topR),
|
|
46365
|
+
points: [
|
|
46366
|
+
[x0, topL],
|
|
46367
|
+
[xr, topR],
|
|
46368
|
+
[xr, bottom],
|
|
46369
|
+
[x0, bottom]
|
|
46370
|
+
]
|
|
46371
|
+
});
|
|
46372
|
+
insetRegions.push({
|
|
46373
|
+
id: iso,
|
|
46374
|
+
d,
|
|
46375
|
+
fill: fill2,
|
|
46376
|
+
stroke: regionStroke,
|
|
46377
|
+
lineNumber,
|
|
46378
|
+
layer: "us-state",
|
|
46379
|
+
...r?.score !== void 0 && { score: r.score },
|
|
46380
|
+
...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46381
|
+
});
|
|
46382
|
+
const ctr = geoPath(proj).centroid(f);
|
|
46383
|
+
if (Number.isFinite(ctr[0])) {
|
|
46384
|
+
const name = f.properties?.name ?? iso;
|
|
46385
|
+
insetLabelSeeds.push({ x: ctr[0], y: ctr[1], iso, name, lineNumber });
|
|
46386
|
+
}
|
|
46387
|
+
return xr;
|
|
46388
|
+
};
|
|
46389
|
+
const akRight = placeInset(
|
|
46390
|
+
"US-AK",
|
|
46391
|
+
alaskaProjection(),
|
|
46392
|
+
FIT_PAD,
|
|
46393
|
+
width * 0.15
|
|
46394
|
+
);
|
|
46395
|
+
placeInset("US-HI", hawaiiProjection(), akRight + 24, width * 0.1);
|
|
46396
|
+
}
|
|
46397
|
+
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46398
|
+
const cullExtent = conusFit ? geoBounds2(fitTarget) : resolved.extent;
|
|
46399
|
+
const [[exW, exS], [exE, exN]] = cullExtent;
|
|
46400
|
+
const lonSpan = exE - exW;
|
|
46401
|
+
const latSpan = exN - exS;
|
|
46402
|
+
const isGlobalView = lonSpan >= 270 || latSpan >= 130;
|
|
46403
|
+
const padLon = Math.max(8, lonSpan * 0.35);
|
|
46404
|
+
const padLat = Math.max(8, latSpan * 0.35);
|
|
46405
|
+
const vW = exW - padLon;
|
|
46406
|
+
const vE = exE + padLon;
|
|
46407
|
+
const vS = exS - padLat;
|
|
46408
|
+
const vN = exN + padLat;
|
|
46409
|
+
const vLonCenter = (exW + exE) / 2;
|
|
46410
|
+
const normLon = (lon) => {
|
|
46411
|
+
let L = lon;
|
|
46412
|
+
while (L < vLonCenter - 180) L += 360;
|
|
46413
|
+
while (L > vLonCenter + 180) L -= 360;
|
|
46414
|
+
return L;
|
|
46415
|
+
};
|
|
46416
|
+
const ringOverlapsView = (ring) => {
|
|
46417
|
+
let anyIn = false;
|
|
46418
|
+
let loMin = Infinity, loMax = -Infinity, laMin = Infinity, laMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
46419
|
+
for (const [rawLon, lat] of ring) {
|
|
46420
|
+
const lon = normLon(rawLon);
|
|
46421
|
+
if (lon >= vW && lon <= vE && lat >= vS && lat <= vN) anyIn = true;
|
|
46422
|
+
if (lon < loMin) loMin = lon;
|
|
46423
|
+
if (lon > loMax) loMax = lon;
|
|
46424
|
+
if (rawLon < rawMin) rawMin = rawLon;
|
|
46425
|
+
if (rawLon > rawMax) rawMax = rawLon;
|
|
46426
|
+
if (lat < laMin) laMin = lat;
|
|
46427
|
+
if (lat > laMax) laMax = lat;
|
|
46428
|
+
}
|
|
46429
|
+
if (loMax - loMin > 270) return false;
|
|
46430
|
+
if (rawMax - rawMin > 180 && loMax - loMin < 90) return false;
|
|
46431
|
+
if (anyIn) return true;
|
|
46432
|
+
if (loMax - loMin > 180) return false;
|
|
46433
|
+
return !(loMax < vW || loMin > vE || laMax < vS || laMin > vN);
|
|
46434
|
+
};
|
|
46435
|
+
const cullFeatureToView = (f) => {
|
|
46436
|
+
if (isGlobalView) return f;
|
|
46437
|
+
const g = f.geometry;
|
|
46438
|
+
if (!g) return f;
|
|
46439
|
+
if (g.type === "Polygon") {
|
|
46440
|
+
const ring = g.coordinates[0];
|
|
46441
|
+
return ringOverlapsView(ring) ? f : null;
|
|
46442
|
+
}
|
|
46443
|
+
if (g.type === "MultiPolygon") {
|
|
46444
|
+
const polys = g.coordinates;
|
|
46445
|
+
const keep = polys.filter(
|
|
46446
|
+
(p) => ringOverlapsView(p[0])
|
|
46447
|
+
);
|
|
46448
|
+
if (!keep.length) return null;
|
|
46449
|
+
if (keep.length === polys.length) return f;
|
|
46450
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46451
|
+
}
|
|
46452
|
+
return f;
|
|
46453
|
+
};
|
|
46454
|
+
const SEAM_SLIVER_MAX_SPAN = 100;
|
|
46455
|
+
const ringIsFrameFiller = (ring) => {
|
|
46456
|
+
const lons = ring.map(([lon]) => lon).sort((a, b) => a - b);
|
|
46457
|
+
if (lons.length < 2) return false;
|
|
46458
|
+
let maxGap = -1;
|
|
46459
|
+
let gapIdx = 0;
|
|
46460
|
+
for (let i = 1; i < lons.length; i++) {
|
|
46461
|
+
const g = lons[i] - lons[i - 1];
|
|
46462
|
+
if (g > maxGap) {
|
|
46463
|
+
maxGap = g;
|
|
46464
|
+
gapIdx = i;
|
|
46465
|
+
}
|
|
46466
|
+
}
|
|
46467
|
+
const wrapGap = lons[0] + 360 - lons[lons.length - 1];
|
|
46468
|
+
if (wrapGap >= maxGap) return false;
|
|
46469
|
+
const span = 360 - maxGap;
|
|
46470
|
+
const east = lons[gapIdx - 1] + 360;
|
|
46471
|
+
return east > 180 && span < SEAM_SLIVER_MAX_SPAN;
|
|
46472
|
+
};
|
|
46473
|
+
const dropFrameFillers = (f) => {
|
|
46474
|
+
const g = f.geometry;
|
|
46475
|
+
if (!g) return f;
|
|
46476
|
+
if (g.type === "Polygon") {
|
|
46477
|
+
const ring = g.coordinates[0];
|
|
46478
|
+
return ringIsFrameFiller(ring) ? null : f;
|
|
46479
|
+
}
|
|
46480
|
+
if (g.type === "MultiPolygon") {
|
|
46481
|
+
const polys = g.coordinates;
|
|
46482
|
+
const keep = polys.filter(
|
|
46483
|
+
(p) => !ringIsFrameFiller(p[0])
|
|
46484
|
+
);
|
|
46485
|
+
if (!keep.length) return null;
|
|
46486
|
+
if (keep.length === polys.length) return f;
|
|
46487
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46488
|
+
}
|
|
46489
|
+
return f;
|
|
46490
|
+
};
|
|
46013
46491
|
const regions = [];
|
|
46014
|
-
const pushRegionLayer = (layerFeatures, layerKind) => {
|
|
46492
|
+
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46015
46493
|
for (const [iso, f] of layerFeatures) {
|
|
46016
|
-
|
|
46017
|
-
|
|
46494
|
+
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
46495
|
+
continue;
|
|
46496
|
+
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46018
46497
|
const r = regionById.get(iso);
|
|
46498
|
+
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
46499
|
+
if (!viewF) continue;
|
|
46500
|
+
const d = path(viewF) ?? "";
|
|
46501
|
+
if (!d) continue;
|
|
46019
46502
|
const isThisLayer = r?.layer === layerKind;
|
|
46020
|
-
|
|
46503
|
+
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46504
|
+
let fill2 = isForeign ? foreignFill : neutralFill;
|
|
46021
46505
|
let label;
|
|
46022
46506
|
let lineNumber = -1;
|
|
46023
46507
|
let layer = "base";
|
|
46024
46508
|
if (isThisLayer) {
|
|
46025
|
-
|
|
46026
|
-
else fill2 = tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46509
|
+
fill2 = regionFill(r);
|
|
46027
46510
|
lineNumber = r.lineNumber;
|
|
46028
46511
|
layer = layerKind;
|
|
46029
46512
|
label = r.name;
|
|
@@ -46035,12 +46518,42 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46035
46518
|
stroke: regionStroke,
|
|
46036
46519
|
lineNumber,
|
|
46037
46520
|
layer,
|
|
46038
|
-
...label !== void 0 && { label }
|
|
46521
|
+
...label !== void 0 && { label },
|
|
46522
|
+
...isThisLayer && r.score !== void 0 && { score: r.score },
|
|
46523
|
+
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46039
46524
|
});
|
|
46040
46525
|
}
|
|
46041
46526
|
};
|
|
46042
|
-
pushRegionLayer(worldLayer, "country");
|
|
46043
|
-
if (usLayer) pushRegionLayer(usLayer, "us-state");
|
|
46527
|
+
pushRegionLayer(worldLayer, "country", !isGlobalView);
|
|
46528
|
+
if (usLayer) pushRegionLayer(usLayer, "us-state", !conusFit && !isGlobalView);
|
|
46529
|
+
const lakesTopo = usCrisp && data.naLakes ? data.naLakes : data.lakes;
|
|
46530
|
+
if (lakesTopo) {
|
|
46531
|
+
for (const [, f] of decodeLayer(lakesTopo)) {
|
|
46532
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46533
|
+
if (!viewF) continue;
|
|
46534
|
+
const d = path(viewF) ?? "";
|
|
46535
|
+
if (!d) continue;
|
|
46536
|
+
regions.push({
|
|
46537
|
+
id: "lake",
|
|
46538
|
+
d,
|
|
46539
|
+
fill: water,
|
|
46540
|
+
stroke: "none",
|
|
46541
|
+
lineNumber: -1,
|
|
46542
|
+
layer: "base"
|
|
46543
|
+
});
|
|
46544
|
+
}
|
|
46545
|
+
}
|
|
46546
|
+
const riverColor = water;
|
|
46547
|
+
const rivers = [];
|
|
46548
|
+
if (data.rivers) {
|
|
46549
|
+
for (const [, f] of decodeLayer(data.rivers)) {
|
|
46550
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46551
|
+
if (!viewF) continue;
|
|
46552
|
+
const d = path(viewF) ?? "";
|
|
46553
|
+
if (!d) continue;
|
|
46554
|
+
rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
|
|
46555
|
+
}
|
|
46556
|
+
}
|
|
46044
46557
|
const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
46045
46558
|
const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
|
|
46046
46559
|
const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
|
|
@@ -46061,8 +46574,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46061
46574
|
if (hex) return { fill: hex, stroke: mix(hex, palette.text, 18) };
|
|
46062
46575
|
}
|
|
46063
46576
|
return {
|
|
46064
|
-
fill: palette.
|
|
46065
|
-
stroke: mix(palette.
|
|
46577
|
+
fill: palette.colors.orange,
|
|
46578
|
+
stroke: mix(palette.colors.orange, palette.text, 18)
|
|
46066
46579
|
};
|
|
46067
46580
|
};
|
|
46068
46581
|
const routeNumberById = /* @__PURE__ */ new Map();
|
|
@@ -46100,7 +46613,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46100
46613
|
cy += Math.sin(ang) * COLO_R;
|
|
46101
46614
|
}
|
|
46102
46615
|
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
46103
|
-
poiScreen.set(e.p.id, { cx, cy });
|
|
46616
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
46104
46617
|
const num = routeNumberById.get(e.p.id);
|
|
46105
46618
|
pois.push({
|
|
46106
46619
|
id: e.p.id,
|
|
@@ -46117,17 +46630,36 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46117
46630
|
});
|
|
46118
46631
|
}
|
|
46119
46632
|
const legs = [];
|
|
46633
|
+
const RIM_GAP = 1.5;
|
|
46120
46634
|
const legPath = (a, b, curved, offset) => {
|
|
46121
|
-
if (!curved && offset === 0) return `M${a.cx},${a.cy}L${b.cx},${b.cy}`;
|
|
46122
46635
|
const mx = (a.cx + b.cx) / 2;
|
|
46123
46636
|
const my = (a.cy + b.cy) / 2;
|
|
46124
46637
|
const dx = b.cx - a.cx;
|
|
46125
46638
|
const dy = b.cy - a.cy;
|
|
46126
46639
|
const len = Math.hypot(dx, dy) || 1;
|
|
46640
|
+
const trimA = Math.min(a.r + RIM_GAP, len * 0.45);
|
|
46641
|
+
const trimB = Math.min(b.r + RIM_GAP, len * 0.45);
|
|
46642
|
+
if (!curved && offset === 0) {
|
|
46643
|
+
const ux = dx / len;
|
|
46644
|
+
const uy = dy / len;
|
|
46645
|
+
const ax2 = a.cx + ux * trimA;
|
|
46646
|
+
const ay2 = a.cy + uy * trimA;
|
|
46647
|
+
const bx2 = b.cx - ux * trimB;
|
|
46648
|
+
const by2 = b.cy - uy * trimB;
|
|
46649
|
+
return `M${ax2},${ay2}L${bx2},${by2}`;
|
|
46650
|
+
}
|
|
46127
46651
|
const nx = -dy / len;
|
|
46128
46652
|
const ny = dx / len;
|
|
46129
46653
|
const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
|
|
46130
|
-
|
|
46654
|
+
const px = mx + nx * bow;
|
|
46655
|
+
const py = my + ny * bow;
|
|
46656
|
+
const ta = Math.hypot(px - a.cx, py - a.cy) || 1;
|
|
46657
|
+
const tb = Math.hypot(b.cx - px, b.cy - py) || 1;
|
|
46658
|
+
const ax = a.cx + (px - a.cx) / ta * trimA;
|
|
46659
|
+
const ay = a.cy + (py - a.cy) / ta * trimA;
|
|
46660
|
+
const bx = b.cx - (b.cx - px) / tb * trimB;
|
|
46661
|
+
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
46662
|
+
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
46131
46663
|
};
|
|
46132
46664
|
for (const rt of resolved.routes) {
|
|
46133
46665
|
const curved = rt.meta["style"] === "arc";
|
|
@@ -46138,7 +46670,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46138
46670
|
legs.push({
|
|
46139
46671
|
d: legPath(a, b, curved, 0),
|
|
46140
46672
|
width: W_MIN,
|
|
46141
|
-
color: mix(palette.text, palette.bg,
|
|
46673
|
+
color: mix(palette.text, palette.bg, 72),
|
|
46142
46674
|
arrow: true,
|
|
46143
46675
|
lineNumber: rt.lineNumber
|
|
46144
46676
|
});
|
|
@@ -46174,7 +46706,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46174
46706
|
legs.push({
|
|
46175
46707
|
d: legPath(a, b, curved, offset),
|
|
46176
46708
|
width: widthFor(e),
|
|
46177
|
-
color: mix(palette.text, palette.bg,
|
|
46709
|
+
color: mix(palette.text, palette.bg, 66),
|
|
46178
46710
|
arrow: e.directed,
|
|
46179
46711
|
lineNumber: e.lineNumber,
|
|
46180
46712
|
...e.label !== void 0 && {
|
|
@@ -46186,38 +46718,92 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46186
46718
|
});
|
|
46187
46719
|
}
|
|
46188
46720
|
const labels = [];
|
|
46189
|
-
const pinList = [];
|
|
46190
46721
|
const obstacles = [];
|
|
46191
46722
|
const markers = pois.map((p) => ({
|
|
46192
46723
|
cx: p.cx,
|
|
46193
46724
|
cy: p.cy,
|
|
46194
46725
|
r: p.r
|
|
46195
46726
|
}));
|
|
46196
|
-
const
|
|
46727
|
+
const legSegments = [];
|
|
46728
|
+
for (const leg of legs) {
|
|
46729
|
+
const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
46730
|
+
leg.d
|
|
46731
|
+
);
|
|
46732
|
+
if (!m) continue;
|
|
46733
|
+
const x0 = +m[1];
|
|
46734
|
+
const y0 = +m[2];
|
|
46735
|
+
if (m[3] !== void 0) {
|
|
46736
|
+
legSegments.push([x0, y0, +m[3], +m[4]]);
|
|
46737
|
+
} else {
|
|
46738
|
+
const cx = +m[5];
|
|
46739
|
+
const cy = +m[6];
|
|
46740
|
+
const ex = +m[7];
|
|
46741
|
+
const ey = +m[8];
|
|
46742
|
+
const N = 8;
|
|
46743
|
+
let px = x0;
|
|
46744
|
+
let py = y0;
|
|
46745
|
+
for (let i = 1; i <= N; i++) {
|
|
46746
|
+
const t = i / N;
|
|
46747
|
+
const u = 1 - t;
|
|
46748
|
+
const qx = u * u * x0 + 2 * u * t * cx + t * t * ex;
|
|
46749
|
+
const qy = u * u * y0 + 2 * u * t * cy + t * t * ey;
|
|
46750
|
+
legSegments.push([px, py, qx, qy]);
|
|
46751
|
+
px = qx;
|
|
46752
|
+
py = qy;
|
|
46753
|
+
}
|
|
46754
|
+
}
|
|
46755
|
+
}
|
|
46756
|
+
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
46757
|
const regionLabelMode = resolved.directives.regionLabels ?? "off";
|
|
46758
|
+
const LABEL_PADX = 6;
|
|
46759
|
+
const LABEL_PADY = 3;
|
|
46760
|
+
const labelW = (text) => measureLegendText(text, FONT) + 2 * LABEL_PADX;
|
|
46761
|
+
const labelH = FONT + 2 * LABEL_PADY;
|
|
46762
|
+
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
46763
|
+
const color = contrastText(
|
|
46764
|
+
fill2,
|
|
46765
|
+
palette.textOnFillLight,
|
|
46766
|
+
palette.textOnFillDark
|
|
46767
|
+
);
|
|
46768
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
46769
|
+
labels.push({
|
|
46770
|
+
x,
|
|
46771
|
+
y,
|
|
46772
|
+
text,
|
|
46773
|
+
anchor: "middle",
|
|
46774
|
+
color,
|
|
46775
|
+
halo: true,
|
|
46776
|
+
haloColor,
|
|
46777
|
+
lineNumber
|
|
46778
|
+
});
|
|
46779
|
+
};
|
|
46780
|
+
const WORLD_LABEL_ANCHORS = {
|
|
46781
|
+
US: [-98.5, 39.5]
|
|
46782
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
46783
|
+
};
|
|
46198
46784
|
if (regionLabelMode === "full" || regionLabelMode === "abbrev") {
|
|
46199
46785
|
for (const r of regions) {
|
|
46200
46786
|
if (r.layer === "base" || r.label === void 0) continue;
|
|
46201
46787
|
const f = r.layer === "us-state" ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
46202
46788
|
if (!f) continue;
|
|
46203
46789
|
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
46790
|
const text = regionLabelMode === "abbrev" ? r.id.replace(/^US-/, "") : r.label;
|
|
46208
|
-
|
|
46209
|
-
|
|
46210
|
-
|
|
46791
|
+
if (labelW(text) > x1 - x0 || labelH > y1 - y0) continue;
|
|
46792
|
+
const anchor = r.layer !== "us-state" ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
46793
|
+
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
46794
|
+
if (!c || !Number.isFinite(c[0])) continue;
|
|
46795
|
+
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
46796
|
+
}
|
|
46797
|
+
for (const seed of insetLabelSeeds) {
|
|
46798
|
+
const text = regionLabelMode === "abbrev" ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
46799
|
+
const src = regionById.get(seed.iso);
|
|
46800
|
+
pushRegionLabel(
|
|
46801
|
+
seed.x,
|
|
46802
|
+
seed.y,
|
|
46211
46803
|
text,
|
|
46212
|
-
|
|
46213
|
-
|
|
46214
|
-
|
|
46215
|
-
palette.textOnFillLight,
|
|
46216
|
-
palette.textOnFillDark
|
|
46217
|
-
),
|
|
46218
|
-
halo: true,
|
|
46219
|
-
lineNumber: r.lineNumber
|
|
46220
|
-
});
|
|
46804
|
+
src ? regionFill(src) : neutralFill,
|
|
46805
|
+
seed.lineNumber
|
|
46806
|
+
);
|
|
46221
46807
|
}
|
|
46222
46808
|
}
|
|
46223
46809
|
const poiLabelMode = resolved.directives.poiLabels ?? "auto";
|
|
@@ -46230,68 +46816,106 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46230
46816
|
const src = poiById.get(p.id);
|
|
46231
46817
|
return src?.label ?? src?.name ?? p.id;
|
|
46232
46818
|
};
|
|
46233
|
-
|
|
46234
|
-
|
|
46819
|
+
const poiLabH = FONT * 1.25;
|
|
46820
|
+
const labelInfo = (p) => {
|
|
46235
46821
|
const text = labelText(p);
|
|
46236
|
-
|
|
46237
|
-
|
|
46238
|
-
|
|
46239
|
-
|
|
46240
|
-
|
|
46822
|
+
return { text, w: measureLegendText(text, FONT) };
|
|
46823
|
+
};
|
|
46824
|
+
const pushInline = (p, text, w, side) => {
|
|
46825
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46826
|
+
obstacles.push({
|
|
46827
|
+
x: side === "right" ? tx : tx - w,
|
|
46828
|
+
y: p.cy - poiLabH / 2,
|
|
46829
|
+
w,
|
|
46830
|
+
h: poiLabH
|
|
46831
|
+
});
|
|
46832
|
+
labels.push({
|
|
46833
|
+
x: tx,
|
|
46834
|
+
y: p.cy + FONT / 3,
|
|
46835
|
+
text,
|
|
46836
|
+
anchor: side === "right" ? "start" : "end",
|
|
46837
|
+
color: palette.text,
|
|
46838
|
+
halo: true,
|
|
46839
|
+
haloColor: palette.bg,
|
|
46840
|
+
poiId: p.id,
|
|
46841
|
+
lineNumber: p.lineNumber
|
|
46842
|
+
});
|
|
46843
|
+
};
|
|
46844
|
+
const inlineFits = (p, w, side) => {
|
|
46845
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46846
|
+
const rect = {
|
|
46847
|
+
x: side === "right" ? tx : tx - w,
|
|
46848
|
+
y: p.cy - poiLabH / 2,
|
|
46849
|
+
w,
|
|
46850
|
+
h: poiLabH
|
|
46851
|
+
};
|
|
46852
|
+
return rect.x >= 0 && rect.x + rect.w <= width && !collides(rect);
|
|
46853
|
+
};
|
|
46854
|
+
const GROUP_R = 30;
|
|
46855
|
+
const groups = [];
|
|
46856
|
+
for (const p of ordered) {
|
|
46857
|
+
const near = groups.find(
|
|
46858
|
+
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
46859
|
+
);
|
|
46860
|
+
if (near) near.push(p);
|
|
46861
|
+
else groups.push([p]);
|
|
46862
|
+
}
|
|
46863
|
+
const ROW_GAP2 = 3;
|
|
46864
|
+
const step = poiLabH + ROW_GAP2;
|
|
46865
|
+
const COL_GAP = 16;
|
|
46866
|
+
const placeColumn = (group) => {
|
|
46867
|
+
const items = group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
46868
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
46869
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
46870
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
46871
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
46872
|
+
const side = right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
46873
|
+
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
46874
|
+
const totalH = items.length * step;
|
|
46875
|
+
let startY = cyMid - totalH / 2;
|
|
46876
|
+
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
46877
|
+
items.forEach((o, i) => {
|
|
46878
|
+
const rowCy = startY + i * step + step / 2;
|
|
46879
|
+
obstacles.push({
|
|
46880
|
+
x: side === "right" ? colX : colX - o.w,
|
|
46881
|
+
y: rowCy - poiLabH / 2,
|
|
46882
|
+
w: o.w,
|
|
46883
|
+
h: poiLabH
|
|
46884
|
+
});
|
|
46241
46885
|
labels.push({
|
|
46242
|
-
x:
|
|
46243
|
-
y:
|
|
46244
|
-
text,
|
|
46245
|
-
anchor: "start",
|
|
46886
|
+
x: colX,
|
|
46887
|
+
y: rowCy + FONT / 3,
|
|
46888
|
+
text: o.text,
|
|
46889
|
+
anchor: side === "right" ? "start" : "end",
|
|
46246
46890
|
color: palette.text,
|
|
46247
46891
|
halo: true,
|
|
46248
|
-
|
|
46892
|
+
haloColor: palette.bg,
|
|
46893
|
+
leader: {
|
|
46894
|
+
x1: o.p.cx,
|
|
46895
|
+
y1: o.p.cy,
|
|
46896
|
+
x2: side === "right" ? colX - 2 : colX + 2,
|
|
46897
|
+
y2: rowCy
|
|
46898
|
+
},
|
|
46899
|
+
leaderColor: o.p.fill,
|
|
46900
|
+
poiId: o.p.id,
|
|
46901
|
+
lineNumber: o.p.lineNumber
|
|
46249
46902
|
});
|
|
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;
|
|
46903
|
+
});
|
|
46904
|
+
};
|
|
46905
|
+
for (const g of groups) {
|
|
46906
|
+
if (g.length === 1) {
|
|
46907
|
+
const p = g[0];
|
|
46908
|
+
const { text, w } = labelInfo(p);
|
|
46909
|
+
if (inlineFits(p, w, "right")) {
|
|
46910
|
+
pushInline(p, text, w, "right");
|
|
46911
|
+
continue;
|
|
46912
|
+
}
|
|
46913
|
+
if (inlineFits(p, w, "left")) {
|
|
46914
|
+
pushInline(p, text, w, "left");
|
|
46915
|
+
continue;
|
|
46280
46916
|
}
|
|
46281
46917
|
}
|
|
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
|
-
});
|
|
46918
|
+
placeColumn(g);
|
|
46295
46919
|
}
|
|
46296
46920
|
}
|
|
46297
46921
|
let legend = null;
|
|
@@ -46300,8 +46924,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46300
46924
|
name: g.name,
|
|
46301
46925
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
46302
46926
|
}));
|
|
46303
|
-
|
|
46304
|
-
if (hasAnything) {
|
|
46927
|
+
if (tagGroups.length > 0 || hasRamp) {
|
|
46305
46928
|
legend = {
|
|
46306
46929
|
tagGroups,
|
|
46307
46930
|
activeGroup,
|
|
@@ -46312,20 +46935,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46312
46935
|
},
|
|
46313
46936
|
min: rampMin,
|
|
46314
46937
|
max: rampMax,
|
|
46315
|
-
hue: rampHue
|
|
46316
|
-
|
|
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
|
|
46938
|
+
hue: rampHue,
|
|
46939
|
+
base: rampBase
|
|
46325
46940
|
}
|
|
46326
|
-
},
|
|
46327
|
-
...weightVals.length > 0 && {
|
|
46328
|
-
weight: { min: wMin, max: wMax }
|
|
46329
46941
|
}
|
|
46330
46942
|
};
|
|
46331
46943
|
}
|
|
@@ -46333,26 +46945,28 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46333
46945
|
return {
|
|
46334
46946
|
width,
|
|
46335
46947
|
height,
|
|
46336
|
-
background:
|
|
46948
|
+
background: water,
|
|
46337
46949
|
title: resolved.title,
|
|
46338
46950
|
...resolved.subtitle !== void 0 && { subtitle: resolved.subtitle },
|
|
46339
46951
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
46340
46952
|
regions,
|
|
46953
|
+
rivers,
|
|
46341
46954
|
legs,
|
|
46342
46955
|
pois,
|
|
46343
46956
|
labels,
|
|
46344
|
-
|
|
46345
|
-
|
|
46957
|
+
legend,
|
|
46958
|
+
insets,
|
|
46959
|
+
insetRegions
|
|
46346
46960
|
};
|
|
46347
46961
|
}
|
|
46348
|
-
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT,
|
|
46962
|
+
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
46963
|
var init_layout15 = __esm({
|
|
46350
46964
|
"src/map/layout.ts"() {
|
|
46351
46965
|
"use strict";
|
|
46352
46966
|
init_color_utils();
|
|
46353
|
-
init_tag_groups();
|
|
46354
46967
|
init_label_layout();
|
|
46355
46968
|
init_legend_constants();
|
|
46969
|
+
init_title_constants();
|
|
46356
46970
|
FIT_PAD = 24;
|
|
46357
46971
|
RAMP_FLOOR = 15;
|
|
46358
46972
|
R_DEFAULT = 6;
|
|
@@ -46361,23 +46975,32 @@ var init_layout15 = __esm({
|
|
|
46361
46975
|
W_MIN = 1.25;
|
|
46362
46976
|
W_MAX = 8;
|
|
46363
46977
|
FONT = 11;
|
|
46364
|
-
LEADER_STEP = 14;
|
|
46365
46978
|
COLO_EPS = 1.5;
|
|
46979
|
+
LAND_TINT_LIGHT = 58;
|
|
46980
|
+
LAND_TINT_DARK = 75;
|
|
46981
|
+
TAG_TINT_LIGHT = 60;
|
|
46982
|
+
TAG_TINT_DARK = 68;
|
|
46983
|
+
WATER_TINT = 55;
|
|
46984
|
+
RIVER_WIDTH = 1.3;
|
|
46985
|
+
FOREIGN_TINT_LIGHT = 30;
|
|
46986
|
+
FOREIGN_TINT_DARK = 62;
|
|
46366
46987
|
COLO_R = 9;
|
|
46367
46988
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
46368
46989
|
FAN_STEP = 16;
|
|
46369
|
-
TINY_REGION_AREA = 600;
|
|
46370
46990
|
ARC_CURVE_FRAC = 0.18;
|
|
46371
|
-
|
|
46372
|
-
|
|
46373
|
-
|
|
46374
|
-
|
|
46375
|
-
|
|
46376
|
-
|
|
46377
|
-
|
|
46378
|
-
|
|
46379
|
-
|
|
46380
|
-
|
|
46991
|
+
usConusProjection = () => geoConicEqualArea().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
46992
|
+
alaskaProjection = () => geoConicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
46993
|
+
hawaiiProjection = () => geoMercator();
|
|
46994
|
+
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
46995
|
+
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
46996
|
+
"US-AK",
|
|
46997
|
+
"US-HI",
|
|
46998
|
+
"US-AS",
|
|
46999
|
+
"US-GU",
|
|
47000
|
+
"US-MP",
|
|
47001
|
+
"US-PR",
|
|
47002
|
+
"US-VI"
|
|
47003
|
+
]);
|
|
46381
47004
|
}
|
|
46382
47005
|
});
|
|
46383
47006
|
|
|
@@ -46388,7 +47011,7 @@ __export(renderer_exports16, {
|
|
|
46388
47011
|
renderMapForExport: () => renderMapForExport
|
|
46389
47012
|
});
|
|
46390
47013
|
import * as d3Selection18 from "d3-selection";
|
|
46391
|
-
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims) {
|
|
47014
|
+
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
46392
47015
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
46393
47016
|
const width = exportDims?.width ?? container.clientWidth;
|
|
46394
47017
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -46399,27 +47022,29 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46399
47022
|
{ width, height },
|
|
46400
47023
|
{
|
|
46401
47024
|
palette,
|
|
46402
|
-
isDark
|
|
47025
|
+
isDark,
|
|
47026
|
+
...activeGroupOverride !== void 0 && {
|
|
47027
|
+
activeGroup: activeGroupOverride
|
|
47028
|
+
}
|
|
46403
47029
|
}
|
|
46404
47030
|
);
|
|
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);
|
|
47031
|
+
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
47032
|
svg.append("rect").attr("width", width).attr("height", height).attr("fill", layout.background);
|
|
46407
|
-
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
46408
47033
|
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
|
-
}
|
|
47034
|
+
const arrowSize = (w) => Math.min(15, 7 + w * 0.95);
|
|
47035
|
+
const haloColor = palette.bg;
|
|
46420
47036
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
46421
|
-
|
|
46422
|
-
const p =
|
|
47037
|
+
const drawRegion = (g, r, strokeWidth) => {
|
|
47038
|
+
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
47039
|
+
if (r.layer !== "base") {
|
|
47040
|
+
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47041
|
+
if (r.score !== void 0) p.attr("data-score", r.score);
|
|
47042
|
+
if (r.tags) {
|
|
47043
|
+
for (const [group, value] of Object.entries(r.tags)) {
|
|
47044
|
+
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
47045
|
+
}
|
|
47046
|
+
}
|
|
47047
|
+
}
|
|
46423
47048
|
if (r.lineNumber >= 0) {
|
|
46424
47049
|
p.attr("data-line-number", r.lineNumber);
|
|
46425
47050
|
if (onClickItem) {
|
|
@@ -46429,11 +47054,31 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46429
47054
|
);
|
|
46430
47055
|
}
|
|
46431
47056
|
}
|
|
47057
|
+
};
|
|
47058
|
+
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
47059
|
+
if (layout.rivers.length) {
|
|
47060
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47061
|
+
for (const r of layout.rivers) {
|
|
47062
|
+
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
47063
|
+
}
|
|
47064
|
+
}
|
|
47065
|
+
if (layout.insets.length) {
|
|
47066
|
+
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47067
|
+
for (const box of layout.insets) {
|
|
47068
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47069
|
+
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");
|
|
47070
|
+
}
|
|
47071
|
+
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
46432
47072
|
}
|
|
46433
47073
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
46434
|
-
|
|
47074
|
+
layout.legs.forEach((leg, i) => {
|
|
46435
47075
|
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)
|
|
47076
|
+
if (leg.arrow) {
|
|
47077
|
+
const id = `dgmo-map-arrow-${i}`;
|
|
47078
|
+
const s = arrowSize(leg.width);
|
|
47079
|
+
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);
|
|
47080
|
+
p.attr("marker-end", `url(#${id})`);
|
|
47081
|
+
}
|
|
46437
47082
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
46438
47083
|
emitText(
|
|
46439
47084
|
gLegs,
|
|
@@ -46447,13 +47092,13 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46447
47092
|
LABEL_FONT - 1
|
|
46448
47093
|
);
|
|
46449
47094
|
}
|
|
46450
|
-
}
|
|
47095
|
+
});
|
|
46451
47096
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
46452
47097
|
for (const poi of layout.pois) {
|
|
46453
47098
|
if (poi.isOrigin) {
|
|
46454
47099
|
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
47100
|
}
|
|
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);
|
|
47101
|
+
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
47102
|
if (onClickItem) {
|
|
46458
47103
|
c.style("cursor", "pointer").on(
|
|
46459
47104
|
"click",
|
|
@@ -46477,48 +47122,66 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46477
47122
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
46478
47123
|
for (const lab of layout.labels) {
|
|
46479
47124
|
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(
|
|
47125
|
+
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(
|
|
47126
|
+
"stroke",
|
|
47127
|
+
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47128
|
+
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47129
|
+
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
46481
47130
|
}
|
|
46482
|
-
|
|
46483
|
-
gLabels.append("rect").attr("x", lab.x - 1).attr("y", lab.y - LABEL_FONT).attr("width", LABEL_FONT * 1.3).attr("height", LABEL_FONT * 1.3).attr("rx", 2).attr("fill", palette.surface).attr("stroke", palette.border);
|
|
46484
|
-
}
|
|
46485
|
-
emitText(
|
|
47131
|
+
const t = emitText(
|
|
46486
47132
|
gLabels,
|
|
46487
47133
|
lab.x,
|
|
46488
47134
|
lab.y,
|
|
46489
47135
|
lab.text,
|
|
46490
47136
|
lab.anchor,
|
|
46491
47137
|
lab.color,
|
|
46492
|
-
haloColor,
|
|
47138
|
+
lab.haloColor,
|
|
46493
47139
|
lab.halo,
|
|
46494
47140
|
LABEL_FONT
|
|
46495
47141
|
);
|
|
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
|
-
});
|
|
47142
|
+
if (lab.poiId !== void 0) {
|
|
47143
|
+
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47144
|
+
}
|
|
46505
47145
|
}
|
|
46506
47146
|
if (layout.legend) {
|
|
46507
47147
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
46508
47148
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
46509
|
-
const
|
|
47149
|
+
const ramp = layout.legend.ramp;
|
|
47150
|
+
const scoreGroup = ramp ? {
|
|
47151
|
+
name: ramp.metric?.trim() || "Score",
|
|
47152
|
+
entries: [],
|
|
47153
|
+
gradient: {
|
|
47154
|
+
min: ramp.min,
|
|
47155
|
+
max: ramp.max,
|
|
47156
|
+
hue: ramp.hue,
|
|
47157
|
+
base: ramp.base
|
|
47158
|
+
}
|
|
47159
|
+
} : null;
|
|
47160
|
+
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47161
|
+
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
46510
47162
|
if (groups.length > 0) {
|
|
46511
47163
|
const config = {
|
|
46512
|
-
groups
|
|
47164
|
+
groups,
|
|
46513
47165
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
46514
47166
|
mode: exportDims ? "export" : "preview",
|
|
46515
|
-
showEmptyGroups: false
|
|
47167
|
+
showEmptyGroups: false,
|
|
47168
|
+
// Keep inactive siblings visible as pills so the user can click to flip
|
|
47169
|
+
// the active colouring dimension (preview only — export shows just the
|
|
47170
|
+
// active group).
|
|
47171
|
+
showInactivePills: true
|
|
46516
47172
|
};
|
|
46517
47173
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
46518
47174
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
46519
47175
|
}
|
|
46520
|
-
|
|
46521
|
-
|
|
47176
|
+
}
|
|
47177
|
+
if (layout.title) {
|
|
47178
|
+
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);
|
|
47179
|
+
}
|
|
47180
|
+
if (layout.subtitle) {
|
|
47181
|
+
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);
|
|
47182
|
+
}
|
|
47183
|
+
if (layout.caption) {
|
|
47184
|
+
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
47185
|
}
|
|
46523
47186
|
}
|
|
46524
47187
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
@@ -46529,54 +47192,7 @@ function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
|
46529
47192
|
if (withHalo) {
|
|
46530
47193
|
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7);
|
|
46531
47194
|
}
|
|
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();
|
|
47195
|
+
return t;
|
|
46580
47196
|
}
|
|
46581
47197
|
var LABEL_FONT;
|
|
46582
47198
|
var init_renderer16 = __esm({
|
|
@@ -53048,18 +53664,18 @@ function getRotateFn(mode) {
|
|
|
53048
53664
|
return () => 0;
|
|
53049
53665
|
}
|
|
53050
53666
|
function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
|
|
53051
|
-
return new Promise((
|
|
53667
|
+
return new Promise((resolve) => {
|
|
53052
53668
|
d3Selection23.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
53053
53669
|
const { words, cloudOptions } = parsed;
|
|
53054
53670
|
const title = parsed.noTitle ? null : parsed.title;
|
|
53055
53671
|
if (words.length === 0) {
|
|
53056
|
-
|
|
53672
|
+
resolve();
|
|
53057
53673
|
return;
|
|
53058
53674
|
}
|
|
53059
53675
|
const width = exportDims?.width ?? container.clientWidth;
|
|
53060
53676
|
const height = exportDims?.height ?? container.clientHeight;
|
|
53061
53677
|
if (width <= 0 || height <= 0) {
|
|
53062
|
-
|
|
53678
|
+
resolve();
|
|
53063
53679
|
return;
|
|
53064
53680
|
}
|
|
53065
53681
|
const titleHeight = title ? 40 : 0;
|
|
@@ -53088,7 +53704,7 @@ function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
|
|
|
53088
53704
|
"transform",
|
|
53089
53705
|
(d) => `translate(${d.x},${d.y}) rotate(${d.rotate})`
|
|
53090
53706
|
).text((d) => d.text);
|
|
53091
|
-
|
|
53707
|
+
resolve();
|
|
53092
53708
|
}).start();
|
|
53093
53709
|
});
|
|
53094
53710
|
}
|
|
@@ -56435,7 +57051,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
|
|
|
56435
57051
|
|
|
56436
57052
|
// src/auto/index.ts
|
|
56437
57053
|
init_safe_href();
|
|
56438
|
-
var VERSION = "0.
|
|
57054
|
+
var VERSION = "0.20.1";
|
|
56439
57055
|
var DEFAULTS = {
|
|
56440
57056
|
theme: "auto",
|
|
56441
57057
|
palette: "nord",
|