@diagrammo/dgmo 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.cjs +948 -321
- package/dist/advanced.d.cts +148 -54
- package/dist/advanced.d.ts +148 -54
- package/dist/advanced.js +949 -321
- package/dist/auto.cjs +930 -317
- package/dist/auto.js +117 -117
- package/dist/auto.mjs +934 -318
- package/dist/cli.cjs +160 -160
- package/dist/index.cjs +929 -316
- package/dist/index.js +933 -317
- package/dist/internal.cjs +948 -321
- package/dist/internal.d.cts +148 -54
- package/dist/internal.d.ts +148 -54
- package/dist/internal.js +949 -321
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/lakes.json +1 -0
- package/dist/map-data/na-lakes.json +1 -0
- package/dist/map-data/na-land.json +1 -0
- package/dist/map-data/rivers.json +1 -0
- package/docs/language-reference.md +12 -7
- package/gallery/fixtures/map-region-scope.dgmo +15 -0
- package/package.json +4 -4
- package/src/advanced.ts +7 -6
- package/src/c4/parser.ts +6 -6
- package/src/completion.ts +6 -2
- package/src/echarts.ts +1 -1
- package/src/infra/parser.ts +10 -10
- package/src/journey-map/parser.ts +1 -1
- package/src/label-layout.ts +36 -0
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/README.md +2 -0
- package/src/map/data/lakes.json +1 -0
- package/src/map/data/na-lakes.json +1 -0
- package/src/map/data/na-land.json +1 -0
- package/src/map/data/rivers.json +1 -0
- package/src/map/layout.ts +1022 -205
- package/src/map/load-data.ts +73 -17
- package/src/map/parser.ts +22 -13
- package/src/map/renderer.ts +200 -219
- package/src/map/resolved-types.ts +18 -1
- package/src/map/resolver.ts +79 -7
- package/src/map/types.ts +4 -0
- package/src/mindmap/parser.ts +1 -1
- package/src/sitemap/parser.ts +1 -1
- package/src/utils/legend-d3.ts +42 -0
- package/src/utils/legend-layout.ts +83 -3
- package/src/utils/legend-svg.ts +1 -8
- package/src/utils/legend-types.ts +44 -1
package/dist/index.cjs
CHANGED
|
@@ -53,6 +53,33 @@ function rectCircleOverlap(rect, circle) {
|
|
|
53
53
|
const dy = nearestY - circle.cy;
|
|
54
54
|
return dx * dx + dy * dy < circle.r * circle.r;
|
|
55
55
|
}
|
|
56
|
+
function segmentRectOverlap(x0, y0, x1, y1, rect) {
|
|
57
|
+
const dx = x1 - x0;
|
|
58
|
+
const dy = y1 - y0;
|
|
59
|
+
let t0 = 0;
|
|
60
|
+
let t1 = 1;
|
|
61
|
+
const edges = [
|
|
62
|
+
[-dx, x0 - rect.x],
|
|
63
|
+
[dx, rect.x + rect.w - x0],
|
|
64
|
+
[-dy, y0 - rect.y],
|
|
65
|
+
[dy, rect.y + rect.h - y0]
|
|
66
|
+
];
|
|
67
|
+
for (const [p, q] of edges) {
|
|
68
|
+
if (p === 0) {
|
|
69
|
+
if (q < 0) return false;
|
|
70
|
+
} else {
|
|
71
|
+
const t = q / p;
|
|
72
|
+
if (p < 0) {
|
|
73
|
+
if (t > t1) return false;
|
|
74
|
+
if (t > t0) t0 = t;
|
|
75
|
+
} else {
|
|
76
|
+
if (t < t0) return false;
|
|
77
|
+
if (t < t1) t1 = t;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
56
83
|
function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius, fontSize) {
|
|
57
84
|
const labelHeight = fontSize + 4;
|
|
58
85
|
const stepSize = labelHeight + 2;
|
|
@@ -3256,6 +3283,57 @@ var init_legend_constants = __esm({
|
|
|
3256
3283
|
});
|
|
3257
3284
|
|
|
3258
3285
|
// src/utils/legend-layout.ts
|
|
3286
|
+
function fmtRamp(n) {
|
|
3287
|
+
return Number.isInteger(n) ? String(n) : String(Math.round(n * 10) / 10);
|
|
3288
|
+
}
|
|
3289
|
+
function gradientCapsuleWidth(name, gradient) {
|
|
3290
|
+
const pw = pillWidth(name);
|
|
3291
|
+
const minW = measureLegendText(fmtRamp(gradient.min), LEGEND_ENTRY_FONT_SIZE);
|
|
3292
|
+
const maxW = measureLegendText(fmtRamp(gradient.max), LEGEND_ENTRY_FONT_SIZE);
|
|
3293
|
+
return LEGEND_CAPSULE_PAD + pw + 4 + minW + RAMP_LABEL_GAP + RAMP_LEGEND_W + RAMP_LABEL_GAP + maxW + LEGEND_CAPSULE_PAD;
|
|
3294
|
+
}
|
|
3295
|
+
function buildGradientCapsuleLayout(group, gradient) {
|
|
3296
|
+
const pw = pillWidth(group.name);
|
|
3297
|
+
const minText = fmtRamp(gradient.min);
|
|
3298
|
+
const maxText = fmtRamp(gradient.max);
|
|
3299
|
+
const minW = measureLegendText(minText, LEGEND_ENTRY_FONT_SIZE);
|
|
3300
|
+
const gx = LEGEND_CAPSULE_PAD + pw + 4;
|
|
3301
|
+
const minX = gx;
|
|
3302
|
+
const rampX = gx + minW + RAMP_LABEL_GAP;
|
|
3303
|
+
const maxX = rampX + RAMP_LEGEND_W + RAMP_LABEL_GAP;
|
|
3304
|
+
const width = gradientCapsuleWidth(group.name, gradient);
|
|
3305
|
+
return {
|
|
3306
|
+
groupName: group.name,
|
|
3307
|
+
x: 0,
|
|
3308
|
+
y: 0,
|
|
3309
|
+
width,
|
|
3310
|
+
height: LEGEND_HEIGHT,
|
|
3311
|
+
pill: {
|
|
3312
|
+
groupName: group.name,
|
|
3313
|
+
x: LEGEND_CAPSULE_PAD,
|
|
3314
|
+
y: LEGEND_CAPSULE_PAD,
|
|
3315
|
+
width: pw,
|
|
3316
|
+
height: LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2,
|
|
3317
|
+
isActive: true
|
|
3318
|
+
},
|
|
3319
|
+
entries: [],
|
|
3320
|
+
gradient: {
|
|
3321
|
+
rampX,
|
|
3322
|
+
rampY: (LEGEND_HEIGHT - RAMP_LEGEND_H) / 2,
|
|
3323
|
+
rampW: RAMP_LEGEND_W,
|
|
3324
|
+
rampH: RAMP_LEGEND_H,
|
|
3325
|
+
min: gradient.min,
|
|
3326
|
+
max: gradient.max,
|
|
3327
|
+
minText,
|
|
3328
|
+
minX,
|
|
3329
|
+
maxText,
|
|
3330
|
+
maxX,
|
|
3331
|
+
textY: LEGEND_HEIGHT / 2,
|
|
3332
|
+
hue: gradient.hue,
|
|
3333
|
+
base: gradient.base
|
|
3334
|
+
}
|
|
3335
|
+
};
|
|
3336
|
+
}
|
|
3259
3337
|
function pillWidth(name) {
|
|
3260
3338
|
return measureLegendText(name, LEGEND_PILL_FONT_SIZE) + LEGEND_PILL_PAD;
|
|
3261
3339
|
}
|
|
@@ -3398,7 +3476,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3398
3476
|
};
|
|
3399
3477
|
}
|
|
3400
3478
|
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3401
|
-
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0);
|
|
3479
|
+
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3402
3480
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3403
3481
|
return {
|
|
3404
3482
|
height: 0,
|
|
@@ -3477,7 +3555,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3477
3555
|
groupAvailW,
|
|
3478
3556
|
config.capsulePillAddonWidth ?? 0
|
|
3479
3557
|
);
|
|
3480
|
-
} else if (!activeGroupName) {
|
|
3558
|
+
} else if (!activeGroupName || config.showInactivePills) {
|
|
3481
3559
|
const pw = pillWidth(g.name);
|
|
3482
3560
|
pills.push({
|
|
3483
3561
|
groupName: g.name,
|
|
@@ -3515,6 +3593,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3515
3593
|
};
|
|
3516
3594
|
}
|
|
3517
3595
|
function buildCapsuleLayout(group, containerWidth, addonWidth = 0) {
|
|
3596
|
+
if (group.gradient) return buildGradientCapsuleLayout(group, group.gradient);
|
|
3518
3597
|
const pw = pillWidth(group.name);
|
|
3519
3598
|
const info = capsuleWidth(
|
|
3520
3599
|
group.name,
|
|
@@ -3685,7 +3764,7 @@ function getMaxLegendReservedHeight(config, containerWidth) {
|
|
|
3685
3764
|
}
|
|
3686
3765
|
return max;
|
|
3687
3766
|
}
|
|
3688
|
-
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
|
|
3767
|
+
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP, RAMP_LEGEND_W, RAMP_LEGEND_H, RAMP_LABEL_GAP;
|
|
3689
3768
|
var init_legend_layout = __esm({
|
|
3690
3769
|
"src/utils/legend-layout.ts"() {
|
|
3691
3770
|
"use strict";
|
|
@@ -3694,6 +3773,9 @@ var init_legend_layout = __esm({
|
|
|
3694
3773
|
CONTROL_FONT_SIZE = 11;
|
|
3695
3774
|
CONTROL_ICON_GAP = 4;
|
|
3696
3775
|
CONTROL_GAP = 8;
|
|
3776
|
+
RAMP_LEGEND_W = 80;
|
|
3777
|
+
RAMP_LEGEND_H = 8;
|
|
3778
|
+
RAMP_LABEL_GAP = 6;
|
|
3697
3779
|
}
|
|
3698
3780
|
});
|
|
3699
3781
|
|
|
@@ -3781,6 +3863,16 @@ function renderCapsule(parent, capsule, palette, groupBg, pillBorder, _isDark, c
|
|
|
3781
3863
|
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);
|
|
3782
3864
|
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);
|
|
3783
3865
|
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);
|
|
3866
|
+
if (capsule.gradient) {
|
|
3867
|
+
const gr = capsule.gradient;
|
|
3868
|
+
const gradId = `dgmo-legend-ramp-${capsule.groupName.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
3869
|
+
const def = g.append("defs").append("linearGradient").attr("id", gradId);
|
|
3870
|
+
def.append("stop").attr("offset", "0%").attr("stop-color", mix(gr.hue, gr.base, 15));
|
|
3871
|
+
def.append("stop").attr("offset", "100%").attr("stop-color", gr.hue);
|
|
3872
|
+
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);
|
|
3873
|
+
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})`);
|
|
3874
|
+
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);
|
|
3875
|
+
}
|
|
3784
3876
|
for (const entry of capsule.entries) {
|
|
3785
3877
|
const entryG = g.append("g").attr("data-legend-entry", entry.value.toLowerCase()).attr("data-series-name", entry.value).style("cursor", "pointer");
|
|
3786
3878
|
entryG.append("circle").attr("cx", entry.dotCx).attr("cy", entry.dotCy).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
|
|
@@ -11254,23 +11346,22 @@ function parseC4(content, palette) {
|
|
|
11254
11346
|
}
|
|
11255
11347
|
}
|
|
11256
11348
|
const parent = findParentElement(indent, stack);
|
|
11257
|
-
|
|
11258
|
-
|
|
11349
|
+
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
11350
|
+
if (parent && descResult.isKeyword) {
|
|
11259
11351
|
if (descResult.needsColon) {
|
|
11260
11352
|
pushError(
|
|
11261
11353
|
lineNumber,
|
|
11262
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11354
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`,
|
|
11263
11355
|
"warning"
|
|
11264
11356
|
);
|
|
11265
11357
|
}
|
|
11266
|
-
const descText = descResult.isKeyword ? descResult.text : trimmed;
|
|
11267
11358
|
let desc = elementDescription.get(parent.element);
|
|
11268
11359
|
if (!desc) {
|
|
11269
11360
|
desc = [];
|
|
11270
11361
|
elementDescription.set(parent.element, desc);
|
|
11271
11362
|
parent.element.description = desc;
|
|
11272
11363
|
}
|
|
11273
|
-
desc.push(
|
|
11364
|
+
desc.push(descResult.text);
|
|
11274
11365
|
} else {
|
|
11275
11366
|
pushError(lineNumber, `Unexpected content: "${trimmed}"`);
|
|
11276
11367
|
}
|
|
@@ -11737,7 +11828,7 @@ function parseSitemap(content, palette) {
|
|
|
11737
11828
|
if (descResult.needsColon) {
|
|
11738
11829
|
pushWarning(
|
|
11739
11830
|
lineNumber,
|
|
11740
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11831
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
11741
11832
|
);
|
|
11742
11833
|
}
|
|
11743
11834
|
const parent = findParentNode(indent, indentStack);
|
|
@@ -12565,23 +12656,22 @@ function parseInfra(content) {
|
|
|
12565
12656
|
}
|
|
12566
12657
|
}
|
|
12567
12658
|
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
12568
|
-
if (descResult.isKeyword
|
|
12569
|
-
|
|
12570
|
-
|
|
12571
|
-
|
|
12659
|
+
if (descResult.isKeyword) {
|
|
12660
|
+
if (currentNode.isEdge) {
|
|
12661
|
+
continue;
|
|
12662
|
+
}
|
|
12572
12663
|
if (descResult.needsColon) {
|
|
12573
12664
|
warn(
|
|
12574
12665
|
lineNumber,
|
|
12575
|
-
`Use "description: ${descResult.text}" \u2014
|
|
12666
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
12576
12667
|
);
|
|
12577
12668
|
}
|
|
12578
|
-
|
|
12579
|
-
pushDescription(currentNode, descText);
|
|
12669
|
+
pushDescription(currentNode, descResult.text);
|
|
12580
12670
|
continue;
|
|
12581
12671
|
}
|
|
12582
12672
|
warn(
|
|
12583
12673
|
lineNumber,
|
|
12584
|
-
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or description text.`
|
|
12674
|
+
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or a description (description: text).`
|
|
12585
12675
|
);
|
|
12586
12676
|
continue;
|
|
12587
12677
|
}
|
|
@@ -15718,9 +15808,6 @@ function parseMap(content) {
|
|
|
15718
15808
|
const pushWarning = (line12, message) => {
|
|
15719
15809
|
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15720
15810
|
};
|
|
15721
|
-
const pushInfo = (line12, message) => {
|
|
15722
|
-
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15723
|
-
};
|
|
15724
15811
|
const lines = content.split("\n");
|
|
15725
15812
|
let firstIdx = 0;
|
|
15726
15813
|
while (firstIdx < lines.length) {
|
|
@@ -15850,10 +15937,15 @@ function parseMap(content) {
|
|
|
15850
15937
|
break;
|
|
15851
15938
|
case "projection":
|
|
15852
15939
|
dup(d.projection);
|
|
15853
|
-
if (value && ![
|
|
15940
|
+
if (value && ![
|
|
15941
|
+
"equirectangular",
|
|
15942
|
+
"natural-earth",
|
|
15943
|
+
"albers-usa",
|
|
15944
|
+
"mercator"
|
|
15945
|
+
].includes(value))
|
|
15854
15946
|
pushWarning(
|
|
15855
15947
|
line12,
|
|
15856
|
-
`Unknown projection "${value}" (expected natural-earth | albers-usa | mercator).`
|
|
15948
|
+
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15857
15949
|
);
|
|
15858
15950
|
d.projection = value;
|
|
15859
15951
|
break;
|
|
@@ -15992,17 +16084,21 @@ function parseMap(content) {
|
|
|
15992
16084
|
scoreNum = void 0;
|
|
15993
16085
|
}
|
|
15994
16086
|
}
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16087
|
+
let regionName = split.name;
|
|
16088
|
+
let regionScope;
|
|
16089
|
+
const rToks = regionName.split(/\s+/);
|
|
16090
|
+
const rLast = rToks[rToks.length - 1];
|
|
16091
|
+
if (rToks.length > 1 && SCOPE_RE.test(rLast)) {
|
|
16092
|
+
regionName = rToks.slice(0, -1).join(" ");
|
|
16093
|
+
regionScope = rLast;
|
|
16094
|
+
}
|
|
16000
16095
|
const region = {
|
|
16001
|
-
name:
|
|
16096
|
+
name: regionName,
|
|
16002
16097
|
tags,
|
|
16003
16098
|
meta,
|
|
16004
16099
|
lineNumber: line12
|
|
16005
16100
|
};
|
|
16101
|
+
if (regionScope !== void 0) region.scope = regionScope;
|
|
16006
16102
|
if (scoreNum !== void 0) region.score = scoreNum;
|
|
16007
16103
|
regions.push(region);
|
|
16008
16104
|
}
|
|
@@ -17126,7 +17222,7 @@ function parseMindmap(content, palette) {
|
|
|
17126
17222
|
if (descResult.needsColon) {
|
|
17127
17223
|
pushWarning(
|
|
17128
17224
|
lineNumber,
|
|
17129
|
-
`Use "description: ${descResult.text}" \u2014
|
|
17225
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
17130
17226
|
);
|
|
17131
17227
|
}
|
|
17132
17228
|
const parent = findMetadataParent2(indent, indentStack);
|
|
@@ -18914,7 +19010,7 @@ function parseJourneyMap(content, palette) {
|
|
|
18914
19010
|
if (descResult.needsColon) {
|
|
18915
19011
|
warn(
|
|
18916
19012
|
lineNumber,
|
|
18917
|
-
`Use "description: ${descResult.text}" \u2014
|
|
19013
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
18918
19014
|
);
|
|
18919
19015
|
}
|
|
18920
19016
|
currentStep.description = descResult.text;
|
|
@@ -45503,7 +45599,9 @@ function resolveMap(parsed, data) {
|
|
|
45503
45599
|
const usScoped = parsed.directives.region === "us-states" || parsed.directives.defaultCountry?.toUpperCase() === "US" || parsed.regions.some((r) => {
|
|
45504
45600
|
const f = fold(r.name);
|
|
45505
45601
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45506
|
-
}) || parsed.
|
|
45602
|
+
}) || parsed.regions.some(
|
|
45603
|
+
(r) => r.scope === "US" || r.scope?.startsWith("US-")
|
|
45604
|
+
) || parsed.pois.some(
|
|
45507
45605
|
(p) => p.pos.kind === "name" && p.pos.scope?.startsWith("US-")
|
|
45508
45606
|
);
|
|
45509
45607
|
const regions = [];
|
|
@@ -45515,7 +45613,30 @@ function resolveMap(parsed, data) {
|
|
|
45515
45613
|
const inCountry = countryIndex.get(f) ?? (REGION_ALIASES[f] ? countryIndex.get(REGION_ALIASES[f]) : void 0);
|
|
45516
45614
|
const inState = usStateIndex.get(f);
|
|
45517
45615
|
let chosen = null;
|
|
45518
|
-
|
|
45616
|
+
const scope = r.scope;
|
|
45617
|
+
if (scope) {
|
|
45618
|
+
const wantsState = scope === "US" || scope.startsWith("US-");
|
|
45619
|
+
if (wantsState && inState) {
|
|
45620
|
+
if (scope.startsWith("US-") && inState.id !== scope) {
|
|
45621
|
+
err(
|
|
45622
|
+
r.lineNumber,
|
|
45623
|
+
`No subdivision "${r.name}" in scope ${scope} (it is ${inState.id}).`,
|
|
45624
|
+
"E_MAP_SCOPE_MISS"
|
|
45625
|
+
);
|
|
45626
|
+
continue;
|
|
45627
|
+
}
|
|
45628
|
+
chosen = { ...inState, layer: "us-state" };
|
|
45629
|
+
} else if (!wantsState && inCountry) {
|
|
45630
|
+
chosen = { ...inCountry, layer: "country" };
|
|
45631
|
+
} else {
|
|
45632
|
+
err(
|
|
45633
|
+
r.lineNumber,
|
|
45634
|
+
`No region "${r.name}" found in scope ${scope}.`,
|
|
45635
|
+
"E_MAP_SCOPE_MISS"
|
|
45636
|
+
);
|
|
45637
|
+
continue;
|
|
45638
|
+
}
|
|
45639
|
+
} else if (inCountry && inState) {
|
|
45519
45640
|
if (usScoped) {
|
|
45520
45641
|
chosen = { ...inState, layer: "us-state" };
|
|
45521
45642
|
} else {
|
|
@@ -45523,7 +45644,7 @@ function resolveMap(parsed, data) {
|
|
|
45523
45644
|
}
|
|
45524
45645
|
warn(
|
|
45525
45646
|
r.lineNumber,
|
|
45526
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}).`,
|
|
45647
|
+
`"${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}").`,
|
|
45527
45648
|
"W_MAP_REGION_AMBIGUOUS"
|
|
45528
45649
|
);
|
|
45529
45650
|
} else if (inState) {
|
|
@@ -45695,9 +45816,17 @@ function resolveMap(parsed, data) {
|
|
|
45695
45816
|
};
|
|
45696
45817
|
registerPoi(id, poi, p.lineNumber);
|
|
45697
45818
|
}
|
|
45819
|
+
const declaredByName = /* @__PURE__ */ new Map();
|
|
45820
|
+
for (const p of pois) {
|
|
45821
|
+
const fn = p.name ? fold(p.name) : void 0;
|
|
45822
|
+
if (fn && fn !== p.id && !declaredByName.has(fn))
|
|
45823
|
+
declaredByName.set(fn, p.id);
|
|
45824
|
+
}
|
|
45698
45825
|
const resolveEndpoint2 = (ref, line12) => {
|
|
45699
45826
|
const f = fold(ref);
|
|
45700
45827
|
if (registry.has(f)) return f;
|
|
45828
|
+
const aliased = declaredByName.get(f);
|
|
45829
|
+
if (aliased) return aliased;
|
|
45701
45830
|
const got = lookupName(ref, void 0, line12, inferredCountry, true);
|
|
45702
45831
|
if (got.kind !== "ok") return null;
|
|
45703
45832
|
noteCountry(got.iso);
|
|
@@ -45777,23 +45906,29 @@ function resolveMap(parsed, data) {
|
|
|
45777
45906
|
[-180, -85],
|
|
45778
45907
|
[180, 85]
|
|
45779
45908
|
];
|
|
45780
|
-
|
|
45909
|
+
let extent2 = unioned ? pad(unioned, PAD_FRACTION) : DEFAULT_EXTENT;
|
|
45781
45910
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
45782
45911
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
45783
45912
|
const span = Math.max(lonSpan, latSpan);
|
|
45784
45913
|
const usDominant = (inferredCountry === "US" || subdivisions.includes("us-states")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
45785
45914
|
let projection;
|
|
45786
45915
|
const override = parsed.directives.projection;
|
|
45787
|
-
if (override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
45916
|
+
if (override === "equirectangular" || override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
45788
45917
|
projection = override;
|
|
45789
45918
|
} else if (usDominant) {
|
|
45790
45919
|
projection = "albers-usa";
|
|
45791
45920
|
} else if (span > WORLD_SPAN) {
|
|
45792
|
-
projection = "
|
|
45921
|
+
projection = "equirectangular";
|
|
45793
45922
|
} else if (span < MERCATOR_MAX_SPAN) {
|
|
45794
45923
|
projection = "mercator";
|
|
45795
45924
|
} else {
|
|
45796
|
-
projection = "
|
|
45925
|
+
projection = "equirectangular";
|
|
45926
|
+
}
|
|
45927
|
+
if (lonSpan >= 180) {
|
|
45928
|
+
extent2 = [
|
|
45929
|
+
[-180, Math.min(extent2[0][1], WORLD_LAT_SOUTH)],
|
|
45930
|
+
[180, Math.max(extent2[1][1], WORLD_LAT_NORTH)]
|
|
45931
|
+
];
|
|
45797
45932
|
}
|
|
45798
45933
|
result.regions = regions;
|
|
45799
45934
|
result.pois = pois;
|
|
@@ -45841,7 +45976,7 @@ function firstError(diags) {
|
|
|
45841
45976
|
const e = diags.find((d) => d.severity === "error");
|
|
45842
45977
|
return e ? formatDgmoError(e) : null;
|
|
45843
45978
|
}
|
|
45844
|
-
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, REGION_ALIASES;
|
|
45979
|
+
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES;
|
|
45845
45980
|
var init_resolver2 = __esm({
|
|
45846
45981
|
"src/map/resolver.ts"() {
|
|
45847
45982
|
"use strict";
|
|
@@ -45850,6 +45985,8 @@ var init_resolver2 = __esm({
|
|
|
45850
45985
|
WORLD_SPAN = 90;
|
|
45851
45986
|
MERCATOR_MAX_SPAN = 25;
|
|
45852
45987
|
PAD_FRACTION = 0.05;
|
|
45988
|
+
WORLD_LAT_SOUTH = -58;
|
|
45989
|
+
WORLD_LAT_NORTH = 78;
|
|
45853
45990
|
REGION_ALIASES = {
|
|
45854
45991
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
45855
45992
|
"united states": "united states of america",
|
|
@@ -45879,14 +46016,22 @@ var load_data_exports = {};
|
|
|
45879
46016
|
__export(load_data_exports, {
|
|
45880
46017
|
loadMapData: () => loadMapData
|
|
45881
46018
|
});
|
|
45882
|
-
async function
|
|
45883
|
-
|
|
46019
|
+
async function loadNodeBuiltins() {
|
|
46020
|
+
const [{ readFile }, { fileURLToPath }, { dirname, resolve }] = await Promise.all([
|
|
46021
|
+
import("fs/promises"),
|
|
46022
|
+
import("url"),
|
|
46023
|
+
import("path")
|
|
46024
|
+
]);
|
|
46025
|
+
return { readFile, fileURLToPath, dirname, resolve };
|
|
46026
|
+
}
|
|
46027
|
+
async function readJson(nb, dir, name) {
|
|
46028
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
45884
46029
|
}
|
|
45885
|
-
async function firstExistingDir(baseDir) {
|
|
46030
|
+
async function firstExistingDir(nb, baseDir) {
|
|
45886
46031
|
for (const rel of CANDIDATE_DIRS) {
|
|
45887
|
-
const dir =
|
|
46032
|
+
const dir = nb.resolve(baseDir, rel);
|
|
45888
46033
|
try {
|
|
45889
|
-
await
|
|
46034
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
45890
46035
|
return dir;
|
|
45891
46036
|
} catch {
|
|
45892
46037
|
}
|
|
@@ -45902,10 +46047,10 @@ function validate(data) {
|
|
|
45902
46047
|
}
|
|
45903
46048
|
return data;
|
|
45904
46049
|
}
|
|
45905
|
-
function moduleBaseDir() {
|
|
46050
|
+
function moduleBaseDir(nb) {
|
|
45906
46051
|
try {
|
|
45907
46052
|
const url = import_meta.url;
|
|
45908
|
-
if (url) return
|
|
46053
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
45909
46054
|
} catch {
|
|
45910
46055
|
}
|
|
45911
46056
|
if (typeof __dirname !== "undefined") return __dirname;
|
|
@@ -45913,32 +46058,57 @@ function moduleBaseDir() {
|
|
|
45913
46058
|
}
|
|
45914
46059
|
function loadMapData() {
|
|
45915
46060
|
cache ??= (async () => {
|
|
45916
|
-
const
|
|
45917
|
-
const
|
|
45918
|
-
|
|
45919
|
-
|
|
45920
|
-
|
|
45921
|
-
|
|
46061
|
+
const nb = await loadNodeBuiltins();
|
|
46062
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
46063
|
+
const [
|
|
46064
|
+
worldCoarse,
|
|
46065
|
+
worldDetail,
|
|
46066
|
+
usStates,
|
|
46067
|
+
lakes,
|
|
46068
|
+
rivers,
|
|
46069
|
+
naLand,
|
|
46070
|
+
naLakes,
|
|
46071
|
+
gazetteer
|
|
46072
|
+
] = await Promise.all([
|
|
46073
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
46074
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
46075
|
+
readJson(nb, dir, FILES.usStates),
|
|
46076
|
+
// Lakes/rivers/NA assets are optional — older bundles may predate them.
|
|
46077
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
46078
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
46079
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
46080
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
46081
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
45922
46082
|
]);
|
|
45923
|
-
return validate({
|
|
46083
|
+
return validate({
|
|
46084
|
+
worldCoarse,
|
|
46085
|
+
worldDetail,
|
|
46086
|
+
usStates,
|
|
46087
|
+
gazetteer,
|
|
46088
|
+
...lakes && { lakes },
|
|
46089
|
+
...rivers && { rivers },
|
|
46090
|
+
...naLand && { naLand },
|
|
46091
|
+
...naLakes && { naLakes }
|
|
46092
|
+
});
|
|
45924
46093
|
})().catch((e) => {
|
|
45925
46094
|
cache = void 0;
|
|
45926
46095
|
throw e;
|
|
45927
46096
|
});
|
|
45928
46097
|
return cache;
|
|
45929
46098
|
}
|
|
45930
|
-
var
|
|
46099
|
+
var import_meta, FILES, CANDIDATE_DIRS, cache;
|
|
45931
46100
|
var init_load_data = __esm({
|
|
45932
46101
|
"src/map/load-data.ts"() {
|
|
45933
46102
|
"use strict";
|
|
45934
|
-
import_promises = require("fs/promises");
|
|
45935
|
-
import_node_url = require("url");
|
|
45936
|
-
import_node_path = require("path");
|
|
45937
46103
|
import_meta = {};
|
|
45938
46104
|
FILES = {
|
|
45939
46105
|
worldCoarse: "world-coarse.json",
|
|
45940
46106
|
worldDetail: "world-detail.json",
|
|
45941
46107
|
usStates: "us-states.json",
|
|
46108
|
+
lakes: "lakes.json",
|
|
46109
|
+
rivers: "rivers.json",
|
|
46110
|
+
naLand: "na-land.json",
|
|
46111
|
+
naLakes: "na-lakes.json",
|
|
45942
46112
|
gazetteer: "gazetteer.json"
|
|
45943
46113
|
};
|
|
45944
46114
|
CANDIDATE_DIRS = [
|
|
@@ -45966,36 +46136,67 @@ function decodeLayer(topo) {
|
|
|
45966
46136
|
function projectionFor(family) {
|
|
45967
46137
|
switch (family) {
|
|
45968
46138
|
case "albers-usa":
|
|
45969
|
-
return (
|
|
46139
|
+
return usConusProjection();
|
|
45970
46140
|
case "mercator":
|
|
45971
46141
|
return (0, import_d3_geo2.geoMercator)();
|
|
45972
46142
|
case "natural-earth":
|
|
45973
|
-
default:
|
|
45974
46143
|
return (0, import_d3_geo2.geoNaturalEarth1)();
|
|
46144
|
+
case "equirectangular":
|
|
46145
|
+
default:
|
|
46146
|
+
return (0, import_d3_geo2.geoEquirectangular)();
|
|
45975
46147
|
}
|
|
45976
46148
|
}
|
|
46149
|
+
function mapBackgroundColor(palette) {
|
|
46150
|
+
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
46151
|
+
}
|
|
45977
46152
|
function layoutMap(resolved, data, size, opts) {
|
|
45978
46153
|
const { palette, isDark } = opts;
|
|
45979
46154
|
const { width, height } = size;
|
|
45980
|
-
const
|
|
46155
|
+
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46156
|
+
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
46157
|
+
const worldTopo = usCrisp ? data.naLand : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
45981
46158
|
const worldLayer = decodeLayer(worldTopo);
|
|
45982
|
-
const usLayer =
|
|
45983
|
-
const
|
|
45984
|
-
const
|
|
46159
|
+
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
46160
|
+
const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
|
|
46161
|
+
const neutralFill = mix(palette.colors.green, palette.bg, landTint);
|
|
46162
|
+
const water = mapBackgroundColor(palette);
|
|
46163
|
+
const usContext = usLayer !== null;
|
|
46164
|
+
const foreignFill = mix(
|
|
46165
|
+
palette.colors.gray,
|
|
46166
|
+
palette.bg,
|
|
46167
|
+
isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46168
|
+
);
|
|
46169
|
+
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
45985
46170
|
const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
|
|
45986
46171
|
const scaleOverride = resolved.directives.scale;
|
|
45987
46172
|
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
|
|
45988
46173
|
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
|
|
45989
|
-
const rampHue = palette.
|
|
46174
|
+
const rampHue = palette.colors.red;
|
|
45990
46175
|
const hasRamp = scores.length > 0;
|
|
45991
|
-
const
|
|
45992
|
-
|
|
45993
|
-
|
|
45994
|
-
|
|
46176
|
+
const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
|
|
46177
|
+
const matchColorGroup = (v) => {
|
|
46178
|
+
const lv = v.trim().toLowerCase();
|
|
46179
|
+
if (lv === "none") return null;
|
|
46180
|
+
if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
|
|
46181
|
+
return SCORE_NAME;
|
|
46182
|
+
const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
46183
|
+
return tg ? tg.name : v;
|
|
46184
|
+
};
|
|
46185
|
+
const override = opts.activeGroup;
|
|
46186
|
+
let activeGroup;
|
|
46187
|
+
if (override !== void 0) {
|
|
46188
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
46189
|
+
} else if (resolved.directives.activeTag !== void 0) {
|
|
46190
|
+
activeGroup = matchColorGroup(resolved.directives.activeTag);
|
|
46191
|
+
} else {
|
|
46192
|
+
activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46193
|
+
}
|
|
46194
|
+
const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
|
|
46195
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
45995
46196
|
const fillForScore = (s) => {
|
|
45996
46197
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
45997
46198
|
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
45998
|
-
return mix(rampHue,
|
|
46199
|
+
return mix(rampHue, rampBase, pct);
|
|
45999
46200
|
};
|
|
46000
46201
|
const tagFill = (tags, groupName) => {
|
|
46001
46202
|
if (!groupName) return null;
|
|
@@ -46009,40 +46210,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46009
46210
|
(e) => e.value.toLowerCase() === val.toLowerCase()
|
|
46010
46211
|
);
|
|
46011
46212
|
if (!entry?.color) return null;
|
|
46012
|
-
return
|
|
46213
|
+
return mix(
|
|
46214
|
+
entry.color,
|
|
46215
|
+
palette.bg,
|
|
46216
|
+
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46217
|
+
);
|
|
46218
|
+
};
|
|
46219
|
+
const regionFill = (r) => {
|
|
46220
|
+
if (activeIsScore) {
|
|
46221
|
+
return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
|
|
46222
|
+
}
|
|
46223
|
+
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46013
46224
|
};
|
|
46014
46225
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46015
|
-
const
|
|
46016
|
-
for (const r of resolved.regions) {
|
|
46017
|
-
const f = r.layer === "us-state" ? usLayer?.get(r.iso) : worldLayer.get(r.iso);
|
|
46018
|
-
if (f) regionFeatures.push(f);
|
|
46019
|
-
}
|
|
46020
|
-
const extentCorners = () => {
|
|
46226
|
+
const extentOutline = () => {
|
|
46021
46227
|
const [[w, s], [e, n]] = resolved.extent;
|
|
46228
|
+
const N = 16;
|
|
46229
|
+
const coords = [];
|
|
46230
|
+
for (let i = 0; i <= N; i++) {
|
|
46231
|
+
const t = i / N;
|
|
46232
|
+
const lon = w + (e - w) * t;
|
|
46233
|
+
const lat = s + (n - s) * t;
|
|
46234
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46235
|
+
}
|
|
46022
46236
|
return {
|
|
46023
46237
|
type: "Feature",
|
|
46024
46238
|
properties: {},
|
|
46025
|
-
geometry: {
|
|
46026
|
-
type: "MultiPoint",
|
|
46027
|
-
coordinates: [
|
|
46028
|
-
[w, s],
|
|
46029
|
-
[e, s],
|
|
46030
|
-
[e, n],
|
|
46031
|
-
[w, n]
|
|
46032
|
-
]
|
|
46033
|
-
}
|
|
46239
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46034
46240
|
};
|
|
46035
46241
|
};
|
|
46036
46242
|
let fitFeatures;
|
|
46037
|
-
if (resolved.projection === "albers-usa") {
|
|
46038
|
-
|
|
46039
|
-
else if (usLayer) fitFeatures = [...usLayer.values()];
|
|
46040
|
-
else {
|
|
46041
|
-
const us = worldLayer.get("US");
|
|
46042
|
-
fitFeatures = us ? [us] : [...worldLayer.values()];
|
|
46043
|
-
}
|
|
46243
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46244
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46044
46245
|
} else {
|
|
46045
|
-
fitFeatures = [
|
|
46246
|
+
fitFeatures = [extentOutline()];
|
|
46046
46247
|
}
|
|
46047
46248
|
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46048
46249
|
const projection = projectionFor(resolved.projection);
|
|
@@ -46051,32 +46252,311 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46051
46252
|
if (centerLon > 180) centerLon -= 360;
|
|
46052
46253
|
projection.rotate([-centerLon, 0]);
|
|
46053
46254
|
}
|
|
46054
|
-
|
|
46255
|
+
const TITLE_GAP = 16;
|
|
46256
|
+
let topPad = FIT_PAD;
|
|
46257
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
46258
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46259
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP);
|
|
46260
|
+
}
|
|
46261
|
+
const fitBox = [
|
|
46262
|
+
[FIT_PAD, topPad],
|
|
46055
46263
|
[
|
|
46056
|
-
|
|
46057
|
-
|
|
46058
|
-
|
|
46059
|
-
|
|
46060
|
-
|
|
46061
|
-
|
|
46062
|
-
|
|
46063
|
-
|
|
46064
|
-
|
|
46065
|
-
|
|
46264
|
+
Math.max(FIT_PAD + 1, width - FIT_PAD),
|
|
46265
|
+
Math.max(topPad + 1, height - FIT_PAD)
|
|
46266
|
+
]
|
|
46267
|
+
];
|
|
46268
|
+
projection.fitExtent(fitBox, fitTarget);
|
|
46269
|
+
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
46270
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46271
|
+
let path;
|
|
46272
|
+
let project;
|
|
46273
|
+
if (fitIsGlobal) {
|
|
46274
|
+
const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
|
|
46275
|
+
const bx0 = cb[0][0];
|
|
46276
|
+
const by0 = cb[0][1];
|
|
46277
|
+
const cw = cb[1][0] - bx0;
|
|
46278
|
+
const ch = cb[1][1] - by0;
|
|
46279
|
+
const ox = fitBox[0][0];
|
|
46280
|
+
const oy = fitBox[0][1];
|
|
46281
|
+
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46282
|
+
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
46283
|
+
const stretch = (x, y) => [
|
|
46284
|
+
ox + (x - bx0) * sx,
|
|
46285
|
+
oy + (y - by0) * sy
|
|
46286
|
+
];
|
|
46287
|
+
const baseProjection = projection;
|
|
46288
|
+
const tx = (0, import_d3_geo2.geoTransform)({
|
|
46289
|
+
point(x, y) {
|
|
46290
|
+
const [px, py] = stretch(x, y);
|
|
46291
|
+
this.stream.point(px, py);
|
|
46292
|
+
}
|
|
46293
|
+
});
|
|
46294
|
+
path = (0, import_d3_geo2.geoPath)({
|
|
46295
|
+
stream: (s) => baseProjection.stream(
|
|
46296
|
+
tx.stream(s)
|
|
46297
|
+
)
|
|
46298
|
+
});
|
|
46299
|
+
project = (lon, lat) => {
|
|
46300
|
+
const p = baseProjection([lon, lat]);
|
|
46301
|
+
return p ? stretch(p[0], p[1]) : null;
|
|
46302
|
+
};
|
|
46303
|
+
} else {
|
|
46304
|
+
path = (0, import_d3_geo2.geoPath)(projection);
|
|
46305
|
+
project = (lon, lat) => projection([lon, lat]) ?? null;
|
|
46306
|
+
}
|
|
46307
|
+
const insets = [];
|
|
46308
|
+
const insetRegions = [];
|
|
46309
|
+
const insetLabelSeeds = [];
|
|
46310
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46311
|
+
const PAD = 8;
|
|
46312
|
+
const GAP = 12;
|
|
46313
|
+
const yB = height - FIT_PAD;
|
|
46314
|
+
const BW = 8;
|
|
46315
|
+
const coast = /* @__PURE__ */ new Map();
|
|
46316
|
+
const addPt = (lon, lat) => {
|
|
46317
|
+
const p = projection([lon, lat]);
|
|
46318
|
+
if (!p) return;
|
|
46319
|
+
const bi = Math.floor(p[0] / BW);
|
|
46320
|
+
const cur = coast.get(bi);
|
|
46321
|
+
if (cur === void 0 || p[1] > cur) coast.set(bi, p[1]);
|
|
46322
|
+
};
|
|
46323
|
+
const walk = (co) => {
|
|
46324
|
+
if (Array.isArray(co) && typeof co[0] === "number")
|
|
46325
|
+
addPt(co[0], co[1]);
|
|
46326
|
+
else if (Array.isArray(co)) for (const c of co) walk(c);
|
|
46327
|
+
};
|
|
46328
|
+
for (const [iso, f] of usLayer) {
|
|
46329
|
+
if (US_NON_CONUS.has(iso)) continue;
|
|
46330
|
+
walk(f.geometry.coordinates);
|
|
46331
|
+
}
|
|
46332
|
+
const at = (x) => {
|
|
46333
|
+
const bi = Math.floor(x / BW);
|
|
46334
|
+
let y = -Infinity;
|
|
46335
|
+
for (let k = bi - 1; k <= bi + 1; k++) {
|
|
46336
|
+
const v = coast.get(k);
|
|
46337
|
+
if (v !== void 0 && v > y) y = v;
|
|
46338
|
+
}
|
|
46339
|
+
return y;
|
|
46340
|
+
};
|
|
46341
|
+
const coastTop = (x0, xr) => {
|
|
46342
|
+
const n = 24;
|
|
46343
|
+
const pts = [];
|
|
46344
|
+
let maxY = -Infinity;
|
|
46345
|
+
for (let i = 0; i <= n; i++) {
|
|
46346
|
+
const x = x0 + (xr - x0) * i / n;
|
|
46347
|
+
const y = at(x);
|
|
46348
|
+
if (y > -Infinity) {
|
|
46349
|
+
pts.push([x, y]);
|
|
46350
|
+
if (y > maxY) maxY = y;
|
|
46351
|
+
}
|
|
46352
|
+
}
|
|
46353
|
+
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46354
|
+
let m = 0;
|
|
46355
|
+
if (pts.length >= 2) {
|
|
46356
|
+
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46357
|
+
for (const [x, y] of pts) {
|
|
46358
|
+
sx += x;
|
|
46359
|
+
sy += y;
|
|
46360
|
+
sxx += x * x;
|
|
46361
|
+
sxy += x * y;
|
|
46362
|
+
}
|
|
46363
|
+
const den = pts.length * sxx - sx * sx;
|
|
46364
|
+
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46365
|
+
}
|
|
46366
|
+
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46367
|
+
let c = -Infinity;
|
|
46368
|
+
for (const [x, y] of pts) {
|
|
46369
|
+
const need = y - m * x + GAP;
|
|
46370
|
+
if (need > c) c = need;
|
|
46371
|
+
}
|
|
46372
|
+
return (x) => m * x + c;
|
|
46373
|
+
};
|
|
46374
|
+
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46375
|
+
const f = usLayer.get(iso);
|
|
46376
|
+
if (!f) return boxX;
|
|
46377
|
+
const x0 = boxX;
|
|
46378
|
+
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46379
|
+
if (iw < 24) return boxX;
|
|
46380
|
+
const xr = x0 + iw + 2 * PAD;
|
|
46381
|
+
const top = coastTop(x0, xr);
|
|
46382
|
+
const yL = top(x0);
|
|
46383
|
+
const yR = top(xr);
|
|
46384
|
+
proj.fitWidth(iw, f);
|
|
46385
|
+
const bb = (0, import_d3_geo2.geoPath)(proj).bounds(f);
|
|
46386
|
+
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46387
|
+
const needH = sh + 2 * PAD;
|
|
46388
|
+
let topFit = Math.max(yL, yR);
|
|
46389
|
+
const bottom = Math.min(topFit + needH, yB);
|
|
46390
|
+
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46391
|
+
const lift = topFit - Math.max(yL, yR);
|
|
46392
|
+
const topL = yL + lift;
|
|
46393
|
+
const topR = yR + lift;
|
|
46394
|
+
proj.fitExtent(
|
|
46395
|
+
[
|
|
46396
|
+
[x0 + PAD, topFit + PAD],
|
|
46397
|
+
[xr - PAD, bottom - PAD]
|
|
46398
|
+
],
|
|
46399
|
+
f
|
|
46400
|
+
);
|
|
46401
|
+
const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
|
|
46402
|
+
if (!d) return xr;
|
|
46403
|
+
const r = regionById.get(iso);
|
|
46404
|
+
let fill2 = neutralFill;
|
|
46405
|
+
let lineNumber = -1;
|
|
46406
|
+
if (r?.layer === "us-state") {
|
|
46407
|
+
fill2 = regionFill(r);
|
|
46408
|
+
lineNumber = r.lineNumber;
|
|
46409
|
+
}
|
|
46410
|
+
insets.push({
|
|
46411
|
+
x: x0,
|
|
46412
|
+
y: Math.min(topL, topR),
|
|
46413
|
+
w: xr - x0,
|
|
46414
|
+
h: bottom - Math.min(topL, topR),
|
|
46415
|
+
points: [
|
|
46416
|
+
[x0, topL],
|
|
46417
|
+
[xr, topR],
|
|
46418
|
+
[xr, bottom],
|
|
46419
|
+
[x0, bottom]
|
|
46420
|
+
]
|
|
46421
|
+
});
|
|
46422
|
+
insetRegions.push({
|
|
46423
|
+
id: iso,
|
|
46424
|
+
d,
|
|
46425
|
+
fill: fill2,
|
|
46426
|
+
stroke: regionStroke,
|
|
46427
|
+
lineNumber,
|
|
46428
|
+
layer: "us-state",
|
|
46429
|
+
...r?.score !== void 0 && { score: r.score },
|
|
46430
|
+
...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46431
|
+
});
|
|
46432
|
+
const ctr = (0, import_d3_geo2.geoPath)(proj).centroid(f);
|
|
46433
|
+
if (Number.isFinite(ctr[0])) {
|
|
46434
|
+
const name = f.properties?.name ?? iso;
|
|
46435
|
+
insetLabelSeeds.push({ x: ctr[0], y: ctr[1], iso, name, lineNumber });
|
|
46436
|
+
}
|
|
46437
|
+
return xr;
|
|
46438
|
+
};
|
|
46439
|
+
const akRight = placeInset(
|
|
46440
|
+
"US-AK",
|
|
46441
|
+
alaskaProjection(),
|
|
46442
|
+
FIT_PAD,
|
|
46443
|
+
width * 0.15
|
|
46444
|
+
);
|
|
46445
|
+
placeInset("US-HI", hawaiiProjection(), akRight + 24, width * 0.1);
|
|
46446
|
+
}
|
|
46447
|
+
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46448
|
+
const cullExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
|
|
46449
|
+
const [[exW, exS], [exE, exN]] = cullExtent;
|
|
46450
|
+
const lonSpan = exE - exW;
|
|
46451
|
+
const latSpan = exN - exS;
|
|
46452
|
+
const isGlobalView = lonSpan >= 270 || latSpan >= 130;
|
|
46453
|
+
const padLon = Math.max(8, lonSpan * 0.35);
|
|
46454
|
+
const padLat = Math.max(8, latSpan * 0.35);
|
|
46455
|
+
const vW = exW - padLon;
|
|
46456
|
+
const vE = exE + padLon;
|
|
46457
|
+
const vS = exS - padLat;
|
|
46458
|
+
const vN = exN + padLat;
|
|
46459
|
+
const vLonCenter = (exW + exE) / 2;
|
|
46460
|
+
const normLon = (lon) => {
|
|
46461
|
+
let L = lon;
|
|
46462
|
+
while (L < vLonCenter - 180) L += 360;
|
|
46463
|
+
while (L > vLonCenter + 180) L -= 360;
|
|
46464
|
+
return L;
|
|
46465
|
+
};
|
|
46466
|
+
const ringOverlapsView = (ring) => {
|
|
46467
|
+
let anyIn = false;
|
|
46468
|
+
let loMin = Infinity, loMax = -Infinity, laMin = Infinity, laMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
46469
|
+
for (const [rawLon, lat] of ring) {
|
|
46470
|
+
const lon = normLon(rawLon);
|
|
46471
|
+
if (lon >= vW && lon <= vE && lat >= vS && lat <= vN) anyIn = true;
|
|
46472
|
+
if (lon < loMin) loMin = lon;
|
|
46473
|
+
if (lon > loMax) loMax = lon;
|
|
46474
|
+
if (rawLon < rawMin) rawMin = rawLon;
|
|
46475
|
+
if (rawLon > rawMax) rawMax = rawLon;
|
|
46476
|
+
if (lat < laMin) laMin = lat;
|
|
46477
|
+
if (lat > laMax) laMax = lat;
|
|
46478
|
+
}
|
|
46479
|
+
if (loMax - loMin > 270) return false;
|
|
46480
|
+
if (rawMax - rawMin > 180 && loMax - loMin < 90) return false;
|
|
46481
|
+
if (anyIn) return true;
|
|
46482
|
+
if (loMax - loMin > 180) return false;
|
|
46483
|
+
return !(loMax < vW || loMin > vE || laMax < vS || laMin > vN);
|
|
46484
|
+
};
|
|
46485
|
+
const cullFeatureToView = (f) => {
|
|
46486
|
+
if (isGlobalView) return f;
|
|
46487
|
+
const g = f.geometry;
|
|
46488
|
+
if (!g) return f;
|
|
46489
|
+
if (g.type === "Polygon") {
|
|
46490
|
+
const ring = g.coordinates[0];
|
|
46491
|
+
return ringOverlapsView(ring) ? f : null;
|
|
46492
|
+
}
|
|
46493
|
+
if (g.type === "MultiPolygon") {
|
|
46494
|
+
const polys = g.coordinates;
|
|
46495
|
+
const keep = polys.filter(
|
|
46496
|
+
(p) => ringOverlapsView(p[0])
|
|
46497
|
+
);
|
|
46498
|
+
if (!keep.length) return null;
|
|
46499
|
+
if (keep.length === polys.length) return f;
|
|
46500
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46501
|
+
}
|
|
46502
|
+
return f;
|
|
46503
|
+
};
|
|
46504
|
+
const SEAM_SLIVER_MAX_SPAN = 100;
|
|
46505
|
+
const ringIsFrameFiller = (ring) => {
|
|
46506
|
+
const lons = ring.map(([lon]) => lon).sort((a, b) => a - b);
|
|
46507
|
+
if (lons.length < 2) return false;
|
|
46508
|
+
let maxGap = -1;
|
|
46509
|
+
let gapIdx = 0;
|
|
46510
|
+
for (let i = 1; i < lons.length; i++) {
|
|
46511
|
+
const g = lons[i] - lons[i - 1];
|
|
46512
|
+
if (g > maxGap) {
|
|
46513
|
+
maxGap = g;
|
|
46514
|
+
gapIdx = i;
|
|
46515
|
+
}
|
|
46516
|
+
}
|
|
46517
|
+
const wrapGap = lons[0] + 360 - lons[lons.length - 1];
|
|
46518
|
+
if (wrapGap >= maxGap) return false;
|
|
46519
|
+
const span = 360 - maxGap;
|
|
46520
|
+
const east = lons[gapIdx - 1] + 360;
|
|
46521
|
+
return east > 180 && span < SEAM_SLIVER_MAX_SPAN;
|
|
46522
|
+
};
|
|
46523
|
+
const dropFrameFillers = (f) => {
|
|
46524
|
+
const g = f.geometry;
|
|
46525
|
+
if (!g) return f;
|
|
46526
|
+
if (g.type === "Polygon") {
|
|
46527
|
+
const ring = g.coordinates[0];
|
|
46528
|
+
return ringIsFrameFiller(ring) ? null : f;
|
|
46529
|
+
}
|
|
46530
|
+
if (g.type === "MultiPolygon") {
|
|
46531
|
+
const polys = g.coordinates;
|
|
46532
|
+
const keep = polys.filter(
|
|
46533
|
+
(p) => !ringIsFrameFiller(p[0])
|
|
46534
|
+
);
|
|
46535
|
+
if (!keep.length) return null;
|
|
46536
|
+
if (keep.length === polys.length) return f;
|
|
46537
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46538
|
+
}
|
|
46539
|
+
return f;
|
|
46540
|
+
};
|
|
46066
46541
|
const regions = [];
|
|
46067
|
-
const pushRegionLayer = (layerFeatures, layerKind) => {
|
|
46542
|
+
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46068
46543
|
for (const [iso, f] of layerFeatures) {
|
|
46069
|
-
|
|
46070
|
-
|
|
46544
|
+
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
46545
|
+
continue;
|
|
46546
|
+
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46071
46547
|
const r = regionById.get(iso);
|
|
46548
|
+
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
46549
|
+
if (!viewF) continue;
|
|
46550
|
+
const d = path(viewF) ?? "";
|
|
46551
|
+
if (!d) continue;
|
|
46072
46552
|
const isThisLayer = r?.layer === layerKind;
|
|
46073
|
-
|
|
46553
|
+
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46554
|
+
let fill2 = isForeign ? foreignFill : neutralFill;
|
|
46074
46555
|
let label;
|
|
46075
46556
|
let lineNumber = -1;
|
|
46076
46557
|
let layer = "base";
|
|
46077
46558
|
if (isThisLayer) {
|
|
46078
|
-
|
|
46079
|
-
else fill2 = tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46559
|
+
fill2 = regionFill(r);
|
|
46080
46560
|
lineNumber = r.lineNumber;
|
|
46081
46561
|
layer = layerKind;
|
|
46082
46562
|
label = r.name;
|
|
@@ -46088,12 +46568,42 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46088
46568
|
stroke: regionStroke,
|
|
46089
46569
|
lineNumber,
|
|
46090
46570
|
layer,
|
|
46091
|
-
...label !== void 0 && { label }
|
|
46571
|
+
...label !== void 0 && { label },
|
|
46572
|
+
...isThisLayer && r.score !== void 0 && { score: r.score },
|
|
46573
|
+
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46092
46574
|
});
|
|
46093
46575
|
}
|
|
46094
46576
|
};
|
|
46095
|
-
pushRegionLayer(worldLayer, "country");
|
|
46096
|
-
if (usLayer) pushRegionLayer(usLayer, "us-state");
|
|
46577
|
+
pushRegionLayer(worldLayer, "country", !isGlobalView);
|
|
46578
|
+
if (usLayer) pushRegionLayer(usLayer, "us-state", !conusFit && !isGlobalView);
|
|
46579
|
+
const lakesTopo = usCrisp && data.naLakes ? data.naLakes : data.lakes;
|
|
46580
|
+
if (lakesTopo) {
|
|
46581
|
+
for (const [, f] of decodeLayer(lakesTopo)) {
|
|
46582
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46583
|
+
if (!viewF) continue;
|
|
46584
|
+
const d = path(viewF) ?? "";
|
|
46585
|
+
if (!d) continue;
|
|
46586
|
+
regions.push({
|
|
46587
|
+
id: "lake",
|
|
46588
|
+
d,
|
|
46589
|
+
fill: water,
|
|
46590
|
+
stroke: "none",
|
|
46591
|
+
lineNumber: -1,
|
|
46592
|
+
layer: "base"
|
|
46593
|
+
});
|
|
46594
|
+
}
|
|
46595
|
+
}
|
|
46596
|
+
const riverColor = water;
|
|
46597
|
+
const rivers = [];
|
|
46598
|
+
if (data.rivers) {
|
|
46599
|
+
for (const [, f] of decodeLayer(data.rivers)) {
|
|
46600
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46601
|
+
if (!viewF) continue;
|
|
46602
|
+
const d = path(viewF) ?? "";
|
|
46603
|
+
if (!d) continue;
|
|
46604
|
+
rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
|
|
46605
|
+
}
|
|
46606
|
+
}
|
|
46097
46607
|
const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
46098
46608
|
const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
|
|
46099
46609
|
const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
|
|
@@ -46114,8 +46624,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46114
46624
|
if (hex) return { fill: hex, stroke: mix(hex, palette.text, 18) };
|
|
46115
46625
|
}
|
|
46116
46626
|
return {
|
|
46117
|
-
fill: palette.
|
|
46118
|
-
stroke: mix(palette.
|
|
46627
|
+
fill: palette.colors.orange,
|
|
46628
|
+
stroke: mix(palette.colors.orange, palette.text, 18)
|
|
46119
46629
|
};
|
|
46120
46630
|
};
|
|
46121
46631
|
const routeNumberById = /* @__PURE__ */ new Map();
|
|
@@ -46153,7 +46663,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46153
46663
|
cy += Math.sin(ang) * COLO_R;
|
|
46154
46664
|
}
|
|
46155
46665
|
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
46156
|
-
poiScreen.set(e.p.id, { cx, cy });
|
|
46666
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
46157
46667
|
const num = routeNumberById.get(e.p.id);
|
|
46158
46668
|
pois.push({
|
|
46159
46669
|
id: e.p.id,
|
|
@@ -46170,17 +46680,36 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46170
46680
|
});
|
|
46171
46681
|
}
|
|
46172
46682
|
const legs = [];
|
|
46683
|
+
const RIM_GAP = 1.5;
|
|
46173
46684
|
const legPath = (a, b, curved, offset) => {
|
|
46174
|
-
if (!curved && offset === 0) return `M${a.cx},${a.cy}L${b.cx},${b.cy}`;
|
|
46175
46685
|
const mx = (a.cx + b.cx) / 2;
|
|
46176
46686
|
const my = (a.cy + b.cy) / 2;
|
|
46177
46687
|
const dx = b.cx - a.cx;
|
|
46178
46688
|
const dy = b.cy - a.cy;
|
|
46179
46689
|
const len = Math.hypot(dx, dy) || 1;
|
|
46690
|
+
const trimA = Math.min(a.r + RIM_GAP, len * 0.45);
|
|
46691
|
+
const trimB = Math.min(b.r + RIM_GAP, len * 0.45);
|
|
46692
|
+
if (!curved && offset === 0) {
|
|
46693
|
+
const ux = dx / len;
|
|
46694
|
+
const uy = dy / len;
|
|
46695
|
+
const ax2 = a.cx + ux * trimA;
|
|
46696
|
+
const ay2 = a.cy + uy * trimA;
|
|
46697
|
+
const bx2 = b.cx - ux * trimB;
|
|
46698
|
+
const by2 = b.cy - uy * trimB;
|
|
46699
|
+
return `M${ax2},${ay2}L${bx2},${by2}`;
|
|
46700
|
+
}
|
|
46180
46701
|
const nx = -dy / len;
|
|
46181
46702
|
const ny = dx / len;
|
|
46182
46703
|
const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
|
|
46183
|
-
|
|
46704
|
+
const px = mx + nx * bow;
|
|
46705
|
+
const py = my + ny * bow;
|
|
46706
|
+
const ta = Math.hypot(px - a.cx, py - a.cy) || 1;
|
|
46707
|
+
const tb = Math.hypot(b.cx - px, b.cy - py) || 1;
|
|
46708
|
+
const ax = a.cx + (px - a.cx) / ta * trimA;
|
|
46709
|
+
const ay = a.cy + (py - a.cy) / ta * trimA;
|
|
46710
|
+
const bx = b.cx - (b.cx - px) / tb * trimB;
|
|
46711
|
+
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
46712
|
+
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
46184
46713
|
};
|
|
46185
46714
|
for (const rt of resolved.routes) {
|
|
46186
46715
|
const curved = rt.meta["style"] === "arc";
|
|
@@ -46191,7 +46720,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46191
46720
|
legs.push({
|
|
46192
46721
|
d: legPath(a, b, curved, 0),
|
|
46193
46722
|
width: W_MIN,
|
|
46194
|
-
color: mix(palette.text, palette.bg,
|
|
46723
|
+
color: mix(palette.text, palette.bg, 72),
|
|
46195
46724
|
arrow: true,
|
|
46196
46725
|
lineNumber: rt.lineNumber
|
|
46197
46726
|
});
|
|
@@ -46227,7 +46756,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46227
46756
|
legs.push({
|
|
46228
46757
|
d: legPath(a, b, curved, offset),
|
|
46229
46758
|
width: widthFor(e),
|
|
46230
|
-
color: mix(palette.text, palette.bg,
|
|
46759
|
+
color: mix(palette.text, palette.bg, 66),
|
|
46231
46760
|
arrow: e.directed,
|
|
46232
46761
|
lineNumber: e.lineNumber,
|
|
46233
46762
|
...e.label !== void 0 && {
|
|
@@ -46239,38 +46768,92 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46239
46768
|
});
|
|
46240
46769
|
}
|
|
46241
46770
|
const labels = [];
|
|
46242
|
-
const pinList = [];
|
|
46243
46771
|
const obstacles = [];
|
|
46244
46772
|
const markers = pois.map((p) => ({
|
|
46245
46773
|
cx: p.cx,
|
|
46246
46774
|
cy: p.cy,
|
|
46247
46775
|
r: p.r
|
|
46248
46776
|
}));
|
|
46249
|
-
const
|
|
46777
|
+
const legSegments = [];
|
|
46778
|
+
for (const leg of legs) {
|
|
46779
|
+
const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
46780
|
+
leg.d
|
|
46781
|
+
);
|
|
46782
|
+
if (!m) continue;
|
|
46783
|
+
const x0 = +m[1];
|
|
46784
|
+
const y0 = +m[2];
|
|
46785
|
+
if (m[3] !== void 0) {
|
|
46786
|
+
legSegments.push([x0, y0, +m[3], +m[4]]);
|
|
46787
|
+
} else {
|
|
46788
|
+
const cx = +m[5];
|
|
46789
|
+
const cy = +m[6];
|
|
46790
|
+
const ex = +m[7];
|
|
46791
|
+
const ey = +m[8];
|
|
46792
|
+
const N = 8;
|
|
46793
|
+
let px = x0;
|
|
46794
|
+
let py = y0;
|
|
46795
|
+
for (let i = 1; i <= N; i++) {
|
|
46796
|
+
const t = i / N;
|
|
46797
|
+
const u = 1 - t;
|
|
46798
|
+
const qx = u * u * x0 + 2 * u * t * cx + t * t * ex;
|
|
46799
|
+
const qy = u * u * y0 + 2 * u * t * cy + t * t * ey;
|
|
46800
|
+
legSegments.push([px, py, qx, qy]);
|
|
46801
|
+
px = qx;
|
|
46802
|
+
py = qy;
|
|
46803
|
+
}
|
|
46804
|
+
}
|
|
46805
|
+
}
|
|
46806
|
+
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));
|
|
46250
46807
|
const regionLabelMode = resolved.directives.regionLabels ?? "off";
|
|
46808
|
+
const LABEL_PADX = 6;
|
|
46809
|
+
const LABEL_PADY = 3;
|
|
46810
|
+
const labelW = (text) => measureLegendText(text, FONT) + 2 * LABEL_PADX;
|
|
46811
|
+
const labelH = FONT + 2 * LABEL_PADY;
|
|
46812
|
+
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
46813
|
+
const color = contrastText(
|
|
46814
|
+
fill2,
|
|
46815
|
+
palette.textOnFillLight,
|
|
46816
|
+
palette.textOnFillDark
|
|
46817
|
+
);
|
|
46818
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
46819
|
+
labels.push({
|
|
46820
|
+
x,
|
|
46821
|
+
y,
|
|
46822
|
+
text,
|
|
46823
|
+
anchor: "middle",
|
|
46824
|
+
color,
|
|
46825
|
+
halo: true,
|
|
46826
|
+
haloColor,
|
|
46827
|
+
lineNumber
|
|
46828
|
+
});
|
|
46829
|
+
};
|
|
46830
|
+
const WORLD_LABEL_ANCHORS = {
|
|
46831
|
+
US: [-98.5, 39.5]
|
|
46832
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
46833
|
+
};
|
|
46251
46834
|
if (regionLabelMode === "full" || regionLabelMode === "abbrev") {
|
|
46252
46835
|
for (const r of regions) {
|
|
46253
46836
|
if (r.layer === "base" || r.label === void 0) continue;
|
|
46254
46837
|
const f = r.layer === "us-state" ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
46255
46838
|
if (!f) continue;
|
|
46256
46839
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
46257
|
-
if ((x1 - x0) * (y1 - y0) < TINY_REGION_AREA) continue;
|
|
46258
|
-
const c = path.centroid(f);
|
|
46259
|
-
if (!Number.isFinite(c[0])) continue;
|
|
46260
46840
|
const text = regionLabelMode === "abbrev" ? r.id.replace(/^US-/, "") : r.label;
|
|
46261
|
-
|
|
46262
|
-
|
|
46263
|
-
|
|
46841
|
+
if (labelW(text) > x1 - x0 || labelH > y1 - y0) continue;
|
|
46842
|
+
const anchor = r.layer !== "us-state" ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
46843
|
+
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
46844
|
+
if (!c || !Number.isFinite(c[0])) continue;
|
|
46845
|
+
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
46846
|
+
}
|
|
46847
|
+
for (const seed of insetLabelSeeds) {
|
|
46848
|
+
const text = regionLabelMode === "abbrev" ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
46849
|
+
const src = regionById.get(seed.iso);
|
|
46850
|
+
pushRegionLabel(
|
|
46851
|
+
seed.x,
|
|
46852
|
+
seed.y,
|
|
46264
46853
|
text,
|
|
46265
|
-
|
|
46266
|
-
|
|
46267
|
-
|
|
46268
|
-
palette.textOnFillLight,
|
|
46269
|
-
palette.textOnFillDark
|
|
46270
|
-
),
|
|
46271
|
-
halo: true,
|
|
46272
|
-
lineNumber: r.lineNumber
|
|
46273
|
-
});
|
|
46854
|
+
src ? regionFill(src) : neutralFill,
|
|
46855
|
+
seed.lineNumber
|
|
46856
|
+
);
|
|
46274
46857
|
}
|
|
46275
46858
|
}
|
|
46276
46859
|
const poiLabelMode = resolved.directives.poiLabels ?? "auto";
|
|
@@ -46283,68 +46866,106 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46283
46866
|
const src = poiById.get(p.id);
|
|
46284
46867
|
return src?.label ?? src?.name ?? p.id;
|
|
46285
46868
|
};
|
|
46286
|
-
|
|
46287
|
-
|
|
46869
|
+
const poiLabH = FONT * 1.25;
|
|
46870
|
+
const labelInfo = (p) => {
|
|
46288
46871
|
const text = labelText(p);
|
|
46289
|
-
|
|
46290
|
-
|
|
46291
|
-
|
|
46292
|
-
|
|
46293
|
-
|
|
46872
|
+
return { text, w: measureLegendText(text, FONT) };
|
|
46873
|
+
};
|
|
46874
|
+
const pushInline = (p, text, w, side) => {
|
|
46875
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46876
|
+
obstacles.push({
|
|
46877
|
+
x: side === "right" ? tx : tx - w,
|
|
46878
|
+
y: p.cy - poiLabH / 2,
|
|
46879
|
+
w,
|
|
46880
|
+
h: poiLabH
|
|
46881
|
+
});
|
|
46882
|
+
labels.push({
|
|
46883
|
+
x: tx,
|
|
46884
|
+
y: p.cy + FONT / 3,
|
|
46885
|
+
text,
|
|
46886
|
+
anchor: side === "right" ? "start" : "end",
|
|
46887
|
+
color: palette.text,
|
|
46888
|
+
halo: true,
|
|
46889
|
+
haloColor: palette.bg,
|
|
46890
|
+
poiId: p.id,
|
|
46891
|
+
lineNumber: p.lineNumber
|
|
46892
|
+
});
|
|
46893
|
+
};
|
|
46894
|
+
const inlineFits = (p, w, side) => {
|
|
46895
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46896
|
+
const rect = {
|
|
46897
|
+
x: side === "right" ? tx : tx - w,
|
|
46898
|
+
y: p.cy - poiLabH / 2,
|
|
46899
|
+
w,
|
|
46900
|
+
h: poiLabH
|
|
46901
|
+
};
|
|
46902
|
+
return rect.x >= 0 && rect.x + rect.w <= width && !collides(rect);
|
|
46903
|
+
};
|
|
46904
|
+
const GROUP_R = 30;
|
|
46905
|
+
const groups = [];
|
|
46906
|
+
for (const p of ordered) {
|
|
46907
|
+
const near = groups.find(
|
|
46908
|
+
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
46909
|
+
);
|
|
46910
|
+
if (near) near.push(p);
|
|
46911
|
+
else groups.push([p]);
|
|
46912
|
+
}
|
|
46913
|
+
const ROW_GAP2 = 3;
|
|
46914
|
+
const step = poiLabH + ROW_GAP2;
|
|
46915
|
+
const COL_GAP = 16;
|
|
46916
|
+
const placeColumn = (group) => {
|
|
46917
|
+
const items = group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
46918
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
46919
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
46920
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
46921
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
46922
|
+
const side = right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
46923
|
+
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
46924
|
+
const totalH = items.length * step;
|
|
46925
|
+
let startY = cyMid - totalH / 2;
|
|
46926
|
+
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
46927
|
+
items.forEach((o, i) => {
|
|
46928
|
+
const rowCy = startY + i * step + step / 2;
|
|
46929
|
+
obstacles.push({
|
|
46930
|
+
x: side === "right" ? colX : colX - o.w,
|
|
46931
|
+
y: rowCy - poiLabH / 2,
|
|
46932
|
+
w: o.w,
|
|
46933
|
+
h: poiLabH
|
|
46934
|
+
});
|
|
46294
46935
|
labels.push({
|
|
46295
|
-
x:
|
|
46296
|
-
y:
|
|
46297
|
-
text,
|
|
46298
|
-
anchor: "start",
|
|
46936
|
+
x: colX,
|
|
46937
|
+
y: rowCy + FONT / 3,
|
|
46938
|
+
text: o.text,
|
|
46939
|
+
anchor: side === "right" ? "start" : "end",
|
|
46299
46940
|
color: palette.text,
|
|
46300
46941
|
halo: true,
|
|
46301
|
-
|
|
46942
|
+
haloColor: palette.bg,
|
|
46943
|
+
leader: {
|
|
46944
|
+
x1: o.p.cx,
|
|
46945
|
+
y1: o.p.cy,
|
|
46946
|
+
x2: side === "right" ? colX - 2 : colX + 2,
|
|
46947
|
+
y2: rowCy
|
|
46948
|
+
},
|
|
46949
|
+
leaderColor: o.p.fill,
|
|
46950
|
+
poiId: o.p.id,
|
|
46951
|
+
lineNumber: o.p.lineNumber
|
|
46302
46952
|
});
|
|
46303
|
-
|
|
46304
|
-
|
|
46305
|
-
|
|
46306
|
-
|
|
46307
|
-
|
|
46308
|
-
|
|
46309
|
-
|
|
46310
|
-
|
|
46311
|
-
|
|
46312
|
-
|
|
46313
|
-
|
|
46314
|
-
|
|
46315
|
-
|
|
46316
|
-
if (rect.x < 0 || rect.x + rect.w > width || rect.y < 0 || rect.y + rect.h > height) {
|
|
46317
|
-
continue;
|
|
46318
|
-
}
|
|
46319
|
-
if (collides(rect)) continue;
|
|
46320
|
-
obstacles.push(rect);
|
|
46321
|
-
labels.push({
|
|
46322
|
-
x: cx,
|
|
46323
|
-
y: cy + FONT / 3,
|
|
46324
|
-
text,
|
|
46325
|
-
anchor: dx >= 0 ? "start" : "end",
|
|
46326
|
-
color: palette.text,
|
|
46327
|
-
halo: true,
|
|
46328
|
-
leader: { x1: p.cx, y1: p.cy, x2: cx, y2: cy },
|
|
46329
|
-
lineNumber: p.lineNumber
|
|
46330
|
-
});
|
|
46331
|
-
placed = true;
|
|
46332
|
-
break;
|
|
46953
|
+
});
|
|
46954
|
+
};
|
|
46955
|
+
for (const g of groups) {
|
|
46956
|
+
if (g.length === 1) {
|
|
46957
|
+
const p = g[0];
|
|
46958
|
+
const { text, w } = labelInfo(p);
|
|
46959
|
+
if (inlineFits(p, w, "right")) {
|
|
46960
|
+
pushInline(p, text, w, "right");
|
|
46961
|
+
continue;
|
|
46962
|
+
}
|
|
46963
|
+
if (inlineFits(p, w, "left")) {
|
|
46964
|
+
pushInline(p, text, w, "left");
|
|
46965
|
+
continue;
|
|
46333
46966
|
}
|
|
46334
46967
|
}
|
|
46335
|
-
|
|
46336
|
-
pinCounter += 1;
|
|
46337
|
-
pinList.push({ pin: pinCounter, label: text });
|
|
46338
|
-
labels.push({
|
|
46339
|
-
x: p.cx + p.r + 2,
|
|
46340
|
-
y: p.cy - p.r,
|
|
46341
|
-
text: String(pinCounter),
|
|
46342
|
-
anchor: "start",
|
|
46343
|
-
color: palette.text,
|
|
46344
|
-
halo: true,
|
|
46345
|
-
pin: pinCounter,
|
|
46346
|
-
lineNumber: p.lineNumber
|
|
46347
|
-
});
|
|
46968
|
+
placeColumn(g);
|
|
46348
46969
|
}
|
|
46349
46970
|
}
|
|
46350
46971
|
let legend = null;
|
|
@@ -46353,8 +46974,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46353
46974
|
name: g.name,
|
|
46354
46975
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
46355
46976
|
}));
|
|
46356
|
-
|
|
46357
|
-
if (hasAnything) {
|
|
46977
|
+
if (tagGroups.length > 0 || hasRamp) {
|
|
46358
46978
|
legend = {
|
|
46359
46979
|
tagGroups,
|
|
46360
46980
|
activeGroup,
|
|
@@ -46365,20 +46985,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46365
46985
|
},
|
|
46366
46986
|
min: rampMin,
|
|
46367
46987
|
max: rampMax,
|
|
46368
|
-
hue: rampHue
|
|
46369
|
-
|
|
46370
|
-
},
|
|
46371
|
-
...sizeVals.length > 0 && {
|
|
46372
|
-
size: {
|
|
46373
|
-
...resolved.directives.sizeMetric !== void 0 && {
|
|
46374
|
-
metric: resolved.directives.sizeMetric
|
|
46375
|
-
},
|
|
46376
|
-
min: sizeMin,
|
|
46377
|
-
max: sizeMax
|
|
46988
|
+
hue: rampHue,
|
|
46989
|
+
base: rampBase
|
|
46378
46990
|
}
|
|
46379
|
-
},
|
|
46380
|
-
...weightVals.length > 0 && {
|
|
46381
|
-
weight: { min: wMin, max: wMax }
|
|
46382
46991
|
}
|
|
46383
46992
|
};
|
|
46384
46993
|
}
|
|
@@ -46386,28 +46995,30 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46386
46995
|
return {
|
|
46387
46996
|
width,
|
|
46388
46997
|
height,
|
|
46389
|
-
background:
|
|
46998
|
+
background: water,
|
|
46390
46999
|
title: resolved.title,
|
|
46391
47000
|
...resolved.subtitle !== void 0 && { subtitle: resolved.subtitle },
|
|
46392
47001
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
46393
47002
|
regions,
|
|
47003
|
+
rivers,
|
|
46394
47004
|
legs,
|
|
46395
47005
|
pois,
|
|
46396
47006
|
labels,
|
|
46397
|
-
|
|
46398
|
-
|
|
47007
|
+
legend,
|
|
47008
|
+
insets,
|
|
47009
|
+
insetRegions
|
|
46399
47010
|
};
|
|
46400
47011
|
}
|
|
46401
|
-
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT,
|
|
47012
|
+
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT, COLO_EPS, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT, RIVER_WIDTH, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, COLO_R, GOLDEN_ANGLE, FAN_STEP, ARC_CURVE_FRAC, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, US_NON_CONUS;
|
|
46402
47013
|
var init_layout15 = __esm({
|
|
46403
47014
|
"src/map/layout.ts"() {
|
|
46404
47015
|
"use strict";
|
|
46405
47016
|
import_d3_geo2 = require("d3-geo");
|
|
46406
47017
|
import_topojson_client2 = require("topojson-client");
|
|
46407
47018
|
init_color_utils();
|
|
46408
|
-
init_tag_groups();
|
|
46409
47019
|
init_label_layout();
|
|
46410
47020
|
init_legend_constants();
|
|
47021
|
+
init_title_constants();
|
|
46411
47022
|
FIT_PAD = 24;
|
|
46412
47023
|
RAMP_FLOOR = 15;
|
|
46413
47024
|
R_DEFAULT = 6;
|
|
@@ -46416,23 +47027,32 @@ var init_layout15 = __esm({
|
|
|
46416
47027
|
W_MIN = 1.25;
|
|
46417
47028
|
W_MAX = 8;
|
|
46418
47029
|
FONT = 11;
|
|
46419
|
-
LEADER_STEP = 14;
|
|
46420
47030
|
COLO_EPS = 1.5;
|
|
47031
|
+
LAND_TINT_LIGHT = 58;
|
|
47032
|
+
LAND_TINT_DARK = 75;
|
|
47033
|
+
TAG_TINT_LIGHT = 60;
|
|
47034
|
+
TAG_TINT_DARK = 68;
|
|
47035
|
+
WATER_TINT = 55;
|
|
47036
|
+
RIVER_WIDTH = 1.3;
|
|
47037
|
+
FOREIGN_TINT_LIGHT = 30;
|
|
47038
|
+
FOREIGN_TINT_DARK = 62;
|
|
46421
47039
|
COLO_R = 9;
|
|
46422
47040
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
46423
47041
|
FAN_STEP = 16;
|
|
46424
|
-
TINY_REGION_AREA = 600;
|
|
46425
47042
|
ARC_CURVE_FRAC = 0.18;
|
|
46426
|
-
|
|
46427
|
-
|
|
46428
|
-
|
|
46429
|
-
|
|
46430
|
-
|
|
46431
|
-
|
|
46432
|
-
|
|
46433
|
-
|
|
46434
|
-
|
|
46435
|
-
|
|
47043
|
+
usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47044
|
+
alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47045
|
+
hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
|
|
47046
|
+
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
47047
|
+
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47048
|
+
"US-AK",
|
|
47049
|
+
"US-HI",
|
|
47050
|
+
"US-AS",
|
|
47051
|
+
"US-GU",
|
|
47052
|
+
"US-MP",
|
|
47053
|
+
"US-PR",
|
|
47054
|
+
"US-VI"
|
|
47055
|
+
]);
|
|
46436
47056
|
}
|
|
46437
47057
|
});
|
|
46438
47058
|
|
|
@@ -46442,7 +47062,7 @@ __export(renderer_exports16, {
|
|
|
46442
47062
|
renderMap: () => renderMap,
|
|
46443
47063
|
renderMapForExport: () => renderMapForExport
|
|
46444
47064
|
});
|
|
46445
|
-
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims) {
|
|
47065
|
+
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
46446
47066
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
46447
47067
|
const width = exportDims?.width ?? container.clientWidth;
|
|
46448
47068
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -46453,27 +47073,29 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46453
47073
|
{ width, height },
|
|
46454
47074
|
{
|
|
46455
47075
|
palette,
|
|
46456
|
-
isDark
|
|
47076
|
+
isDark,
|
|
47077
|
+
...activeGroupOverride !== void 0 && {
|
|
47078
|
+
activeGroup: activeGroupOverride
|
|
47079
|
+
}
|
|
46457
47080
|
}
|
|
46458
47081
|
);
|
|
46459
|
-
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);
|
|
47082
|
+
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);
|
|
46460
47083
|
svg.append("rect").attr("width", width).attr("height", height).attr("fill", layout.background);
|
|
46461
|
-
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
46462
47084
|
const defs = svg.append("defs");
|
|
46463
|
-
|
|
46464
|
-
const haloColor =
|
|
46465
|
-
if (layout.title) {
|
|
46466
|
-
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);
|
|
46467
|
-
}
|
|
46468
|
-
if (layout.subtitle) {
|
|
46469
|
-
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);
|
|
46470
|
-
}
|
|
46471
|
-
if (layout.caption) {
|
|
46472
|
-
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);
|
|
46473
|
-
}
|
|
47085
|
+
const arrowSize = (w) => Math.min(15, 7 + w * 0.95);
|
|
47086
|
+
const haloColor = palette.bg;
|
|
46474
47087
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
46475
|
-
|
|
46476
|
-
const p =
|
|
47088
|
+
const drawRegion = (g, r, strokeWidth) => {
|
|
47089
|
+
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
47090
|
+
if (r.layer !== "base") {
|
|
47091
|
+
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47092
|
+
if (r.score !== void 0) p.attr("data-score", r.score);
|
|
47093
|
+
if (r.tags) {
|
|
47094
|
+
for (const [group, value] of Object.entries(r.tags)) {
|
|
47095
|
+
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
47096
|
+
}
|
|
47097
|
+
}
|
|
47098
|
+
}
|
|
46477
47099
|
if (r.lineNumber >= 0) {
|
|
46478
47100
|
p.attr("data-line-number", r.lineNumber);
|
|
46479
47101
|
if (onClickItem) {
|
|
@@ -46483,11 +47105,31 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46483
47105
|
);
|
|
46484
47106
|
}
|
|
46485
47107
|
}
|
|
47108
|
+
};
|
|
47109
|
+
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
47110
|
+
if (layout.rivers.length) {
|
|
47111
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47112
|
+
for (const r of layout.rivers) {
|
|
47113
|
+
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
47114
|
+
}
|
|
47115
|
+
}
|
|
47116
|
+
if (layout.insets.length) {
|
|
47117
|
+
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47118
|
+
for (const box of layout.insets) {
|
|
47119
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47120
|
+
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");
|
|
47121
|
+
}
|
|
47122
|
+
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
46486
47123
|
}
|
|
46487
47124
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
46488
|
-
|
|
47125
|
+
layout.legs.forEach((leg, i) => {
|
|
46489
47126
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
46490
|
-
if (leg.arrow)
|
|
47127
|
+
if (leg.arrow) {
|
|
47128
|
+
const id = `dgmo-map-arrow-${i}`;
|
|
47129
|
+
const s = arrowSize(leg.width);
|
|
47130
|
+
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);
|
|
47131
|
+
p.attr("marker-end", `url(#${id})`);
|
|
47132
|
+
}
|
|
46491
47133
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
46492
47134
|
emitText(
|
|
46493
47135
|
gLegs,
|
|
@@ -46501,13 +47143,13 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46501
47143
|
LABEL_FONT - 1
|
|
46502
47144
|
);
|
|
46503
47145
|
}
|
|
46504
|
-
}
|
|
47146
|
+
});
|
|
46505
47147
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
46506
47148
|
for (const poi of layout.pois) {
|
|
46507
47149
|
if (poi.isOrigin) {
|
|
46508
47150
|
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);
|
|
46509
47151
|
}
|
|
46510
|
-
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);
|
|
47152
|
+
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);
|
|
46511
47153
|
if (onClickItem) {
|
|
46512
47154
|
c.style("cursor", "pointer").on(
|
|
46513
47155
|
"click",
|
|
@@ -46531,48 +47173,66 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46531
47173
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
46532
47174
|
for (const lab of layout.labels) {
|
|
46533
47175
|
if (lab.leader) {
|
|
46534
|
-
gLabels.append("line").attr("x1", lab.leader.x1).attr("y1", lab.leader.y1).attr("x2", lab.leader.x2).attr("y2", lab.leader.y2).attr(
|
|
47176
|
+
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(
|
|
47177
|
+
"stroke",
|
|
47178
|
+
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47179
|
+
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47180
|
+
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
46535
47181
|
}
|
|
46536
|
-
|
|
46537
|
-
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);
|
|
46538
|
-
}
|
|
46539
|
-
emitText(
|
|
47182
|
+
const t = emitText(
|
|
46540
47183
|
gLabels,
|
|
46541
47184
|
lab.x,
|
|
46542
47185
|
lab.y,
|
|
46543
47186
|
lab.text,
|
|
46544
47187
|
lab.anchor,
|
|
46545
47188
|
lab.color,
|
|
46546
|
-
haloColor,
|
|
47189
|
+
lab.haloColor,
|
|
46547
47190
|
lab.halo,
|
|
46548
47191
|
LABEL_FONT
|
|
46549
47192
|
);
|
|
46550
|
-
|
|
46551
|
-
|
|
46552
|
-
|
|
46553
|
-
"transform",
|
|
46554
|
-
`translate(12, ${height - layout.pinList.length * 14 - 8})`
|
|
46555
|
-
);
|
|
46556
|
-
layout.pinList.forEach((entry, i) => {
|
|
46557
|
-
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}`);
|
|
46558
|
-
});
|
|
47193
|
+
if (lab.poiId !== void 0) {
|
|
47194
|
+
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47195
|
+
}
|
|
46559
47196
|
}
|
|
46560
47197
|
if (layout.legend) {
|
|
46561
47198
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
46562
47199
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
46563
|
-
const
|
|
47200
|
+
const ramp = layout.legend.ramp;
|
|
47201
|
+
const scoreGroup = ramp ? {
|
|
47202
|
+
name: ramp.metric?.trim() || "Score",
|
|
47203
|
+
entries: [],
|
|
47204
|
+
gradient: {
|
|
47205
|
+
min: ramp.min,
|
|
47206
|
+
max: ramp.max,
|
|
47207
|
+
hue: ramp.hue,
|
|
47208
|
+
base: ramp.base
|
|
47209
|
+
}
|
|
47210
|
+
} : null;
|
|
47211
|
+
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47212
|
+
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
46564
47213
|
if (groups.length > 0) {
|
|
46565
47214
|
const config = {
|
|
46566
|
-
groups
|
|
47215
|
+
groups,
|
|
46567
47216
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
46568
47217
|
mode: exportDims ? "export" : "preview",
|
|
46569
|
-
showEmptyGroups: false
|
|
47218
|
+
showEmptyGroups: false,
|
|
47219
|
+
// Keep inactive siblings visible as pills so the user can click to flip
|
|
47220
|
+
// the active colouring dimension (preview only — export shows just the
|
|
47221
|
+
// active group).
|
|
47222
|
+
showInactivePills: true
|
|
46570
47223
|
};
|
|
46571
47224
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
46572
47225
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
46573
47226
|
}
|
|
46574
|
-
|
|
46575
|
-
|
|
47227
|
+
}
|
|
47228
|
+
if (layout.title) {
|
|
47229
|
+
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);
|
|
47230
|
+
}
|
|
47231
|
+
if (layout.subtitle) {
|
|
47232
|
+
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);
|
|
47233
|
+
}
|
|
47234
|
+
if (layout.caption) {
|
|
47235
|
+
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);
|
|
46576
47236
|
}
|
|
46577
47237
|
}
|
|
46578
47238
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
@@ -46583,54 +47243,7 @@ function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
|
46583
47243
|
if (withHalo) {
|
|
46584
47244
|
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7);
|
|
46585
47245
|
}
|
|
46586
|
-
|
|
46587
|
-
function emitExtraLegend(svg, layout, palette, height, bottomGap) {
|
|
46588
|
-
const { legend } = layout;
|
|
46589
|
-
if (!legend) return;
|
|
46590
|
-
if (!legend.ramp && !legend.size && !legend.weight) return;
|
|
46591
|
-
const blocks = [];
|
|
46592
|
-
const g = svg.append("g").attr("class", "dgmo-map-legend-keys").attr("transform", `translate(12, ${height - 56 - bottomGap})`);
|
|
46593
|
-
let xCursor = 0;
|
|
46594
|
-
if (legend.ramp) {
|
|
46595
|
-
const ramp = legend.ramp;
|
|
46596
|
-
blocks.push(() => {
|
|
46597
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46598
|
-
const gradId = "dgmo-map-ramp";
|
|
46599
|
-
const grad = block.append("defs").append("linearGradient").attr("id", gradId).attr("x1", "0%").attr("x2", "100%");
|
|
46600
|
-
grad.append("stop").attr("offset", "0%").attr("stop-color", mix(ramp.hue, palette.bg, 15));
|
|
46601
|
-
grad.append("stop").attr("offset", "100%").attr("stop-color", ramp.hue);
|
|
46602
|
-
block.append("rect").attr("width", 80).attr("height", 8).attr("fill", `url(#${gradId})`);
|
|
46603
|
-
block.append("text").attr("x", 0).attr("y", 22).attr("font-size", 9).attr("fill", palette.textMuted).text(String(ramp.min));
|
|
46604
|
-
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));
|
|
46605
|
-
if (ramp.metric) {
|
|
46606
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(ramp.metric);
|
|
46607
|
-
}
|
|
46608
|
-
xCursor += 110;
|
|
46609
|
-
});
|
|
46610
|
-
}
|
|
46611
|
-
if (legend.size) {
|
|
46612
|
-
const sz = legend.size;
|
|
46613
|
-
blocks.push(() => {
|
|
46614
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46615
|
-
[3, 6, 10].forEach((r, i) => {
|
|
46616
|
-
block.append("circle").attr("cx", i * 26 + r).attr("cy", 8).attr("r", r).attr("fill", "none").attr("stroke", palette.textMuted);
|
|
46617
|
-
});
|
|
46618
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(sz.metric ?? "size");
|
|
46619
|
-
xCursor += 110;
|
|
46620
|
-
});
|
|
46621
|
-
}
|
|
46622
|
-
if (legend.weight) {
|
|
46623
|
-
const wt = legend.weight;
|
|
46624
|
-
blocks.push(() => {
|
|
46625
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46626
|
-
[1, 3, 6].forEach((w, i) => {
|
|
46627
|
-
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);
|
|
46628
|
-
});
|
|
46629
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(wt.metric ?? "weight");
|
|
46630
|
-
xCursor += 110;
|
|
46631
|
-
});
|
|
46632
|
-
}
|
|
46633
|
-
for (const draw of blocks) draw();
|
|
47246
|
+
return t;
|
|
46634
47247
|
}
|
|
46635
47248
|
var d3Selection18, LABEL_FONT;
|
|
46636
47249
|
var init_renderer16 = __esm({
|
|
@@ -53098,18 +53711,18 @@ function getRotateFn(mode) {
|
|
|
53098
53711
|
return () => 0;
|
|
53099
53712
|
}
|
|
53100
53713
|
function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
|
|
53101
|
-
return new Promise((
|
|
53714
|
+
return new Promise((resolve) => {
|
|
53102
53715
|
d3Selection23.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
53103
53716
|
const { words, cloudOptions } = parsed;
|
|
53104
53717
|
const title = parsed.noTitle ? null : parsed.title;
|
|
53105
53718
|
if (words.length === 0) {
|
|
53106
|
-
|
|
53719
|
+
resolve();
|
|
53107
53720
|
return;
|
|
53108
53721
|
}
|
|
53109
53722
|
const width = exportDims?.width ?? container.clientWidth;
|
|
53110
53723
|
const height = exportDims?.height ?? container.clientHeight;
|
|
53111
53724
|
if (width <= 0 || height <= 0) {
|
|
53112
|
-
|
|
53725
|
+
resolve();
|
|
53113
53726
|
return;
|
|
53114
53727
|
}
|
|
53115
53728
|
const titleHeight = title ? 40 : 0;
|
|
@@ -53138,7 +53751,7 @@ function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
|
|
|
53138
53751
|
"transform",
|
|
53139
53752
|
(d) => `translate(${d.x},${d.y}) rotate(${d.rotate})`
|
|
53140
53753
|
).text((d) => d.text);
|
|
53141
|
-
|
|
53754
|
+
resolve();
|
|
53142
53755
|
}).start();
|
|
53143
53756
|
});
|
|
53144
53757
|
}
|