@diagrammo/dgmo 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.cjs +919 -298
- package/dist/advanced.d.cts +148 -54
- package/dist/advanced.d.ts +148 -54
- package/dist/advanced.js +922 -300
- package/dist/auto.cjs +904 -297
- package/dist/auto.js +117 -117
- package/dist/auto.mjs +909 -299
- package/dist/cli.cjs +159 -159
- package/dist/index.cjs +903 -296
- package/dist/index.js +908 -298
- package/dist/internal.cjs +919 -298
- package/dist/internal.d.cts +148 -54
- package/dist/internal.d.ts +148 -54
- package/dist/internal.js +922 -300
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/lakes.json +1 -0
- package/dist/map-data/na-lakes.json +1 -0
- package/dist/map-data/na-land.json +1 -0
- package/dist/map-data/rivers.json +1 -0
- package/docs/language-reference.md +12 -7
- package/gallery/fixtures/map-region-scope.dgmo +15 -0
- package/package.json +4 -4
- package/src/advanced.ts +6 -2
- package/src/c4/parser.ts +6 -6
- package/src/completion.ts +6 -2
- package/src/echarts.ts +1 -1
- package/src/infra/parser.ts +10 -10
- package/src/journey-map/parser.ts +1 -1
- package/src/label-layout.ts +36 -0
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/README.md +2 -0
- package/src/map/data/lakes.json +1 -0
- package/src/map/data/na-lakes.json +1 -0
- package/src/map/data/na-land.json +1 -0
- package/src/map/data/rivers.json +1 -0
- package/src/map/layout.ts +1022 -205
- package/src/map/load-data.ts +29 -2
- package/src/map/parser.ts +22 -13
- package/src/map/renderer.ts +200 -219
- package/src/map/resolved-types.ts +18 -1
- package/src/map/resolver.ts +79 -7
- package/src/map/types.ts +4 -0
- package/src/mindmap/parser.ts +1 -1
- package/src/sitemap/parser.ts +1 -1
- package/src/utils/legend-d3.ts +42 -0
- package/src/utils/legend-layout.ts +83 -3
- package/src/utils/legend-svg.ts +1 -8
- package/src/utils/legend-types.ts +44 -1
package/dist/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",
|
|
@@ -45914,13 +46051,36 @@ function moduleBaseDir() {
|
|
|
45914
46051
|
function loadMapData() {
|
|
45915
46052
|
cache ??= (async () => {
|
|
45916
46053
|
const dir = await firstExistingDir(moduleBaseDir());
|
|
45917
|
-
const [
|
|
46054
|
+
const [
|
|
46055
|
+
worldCoarse,
|
|
46056
|
+
worldDetail,
|
|
46057
|
+
usStates,
|
|
46058
|
+
lakes,
|
|
46059
|
+
rivers,
|
|
46060
|
+
naLand,
|
|
46061
|
+
naLakes,
|
|
46062
|
+
gazetteer
|
|
46063
|
+
] = await Promise.all([
|
|
45918
46064
|
readJson(dir, FILES.worldCoarse),
|
|
45919
46065
|
readJson(dir, FILES.worldDetail),
|
|
45920
46066
|
readJson(dir, FILES.usStates),
|
|
46067
|
+
// Lakes/rivers/NA assets are optional — older bundles may predate them.
|
|
46068
|
+
readJson(dir, FILES.lakes).catch(() => void 0),
|
|
46069
|
+
readJson(dir, FILES.rivers).catch(() => void 0),
|
|
46070
|
+
readJson(dir, FILES.naLand).catch(() => void 0),
|
|
46071
|
+
readJson(dir, FILES.naLakes).catch(() => void 0),
|
|
45921
46072
|
readJson(dir, FILES.gazetteer)
|
|
45922
46073
|
]);
|
|
45923
|
-
return validate({
|
|
46074
|
+
return validate({
|
|
46075
|
+
worldCoarse,
|
|
46076
|
+
worldDetail,
|
|
46077
|
+
usStates,
|
|
46078
|
+
gazetteer,
|
|
46079
|
+
...lakes && { lakes },
|
|
46080
|
+
...rivers && { rivers },
|
|
46081
|
+
...naLand && { naLand },
|
|
46082
|
+
...naLakes && { naLakes }
|
|
46083
|
+
});
|
|
45924
46084
|
})().catch((e) => {
|
|
45925
46085
|
cache = void 0;
|
|
45926
46086
|
throw e;
|
|
@@ -45939,6 +46099,10 @@ var init_load_data = __esm({
|
|
|
45939
46099
|
worldCoarse: "world-coarse.json",
|
|
45940
46100
|
worldDetail: "world-detail.json",
|
|
45941
46101
|
usStates: "us-states.json",
|
|
46102
|
+
lakes: "lakes.json",
|
|
46103
|
+
rivers: "rivers.json",
|
|
46104
|
+
naLand: "na-land.json",
|
|
46105
|
+
naLakes: "na-lakes.json",
|
|
45942
46106
|
gazetteer: "gazetteer.json"
|
|
45943
46107
|
};
|
|
45944
46108
|
CANDIDATE_DIRS = [
|
|
@@ -45966,36 +46130,67 @@ function decodeLayer(topo) {
|
|
|
45966
46130
|
function projectionFor(family) {
|
|
45967
46131
|
switch (family) {
|
|
45968
46132
|
case "albers-usa":
|
|
45969
|
-
return (
|
|
46133
|
+
return usConusProjection();
|
|
45970
46134
|
case "mercator":
|
|
45971
46135
|
return (0, import_d3_geo2.geoMercator)();
|
|
45972
46136
|
case "natural-earth":
|
|
45973
|
-
default:
|
|
45974
46137
|
return (0, import_d3_geo2.geoNaturalEarth1)();
|
|
46138
|
+
case "equirectangular":
|
|
46139
|
+
default:
|
|
46140
|
+
return (0, import_d3_geo2.geoEquirectangular)();
|
|
45975
46141
|
}
|
|
45976
46142
|
}
|
|
46143
|
+
function mapBackgroundColor(palette) {
|
|
46144
|
+
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
46145
|
+
}
|
|
45977
46146
|
function layoutMap(resolved, data, size, opts) {
|
|
45978
46147
|
const { palette, isDark } = opts;
|
|
45979
46148
|
const { width, height } = size;
|
|
45980
|
-
const
|
|
46149
|
+
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46150
|
+
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
46151
|
+
const worldTopo = usCrisp ? data.naLand : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
45981
46152
|
const worldLayer = decodeLayer(worldTopo);
|
|
45982
|
-
const usLayer =
|
|
45983
|
-
const
|
|
45984
|
-
const
|
|
46153
|
+
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
46154
|
+
const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
|
|
46155
|
+
const neutralFill = mix(palette.colors.green, palette.bg, landTint);
|
|
46156
|
+
const water = mapBackgroundColor(palette);
|
|
46157
|
+
const usContext = usLayer !== null;
|
|
46158
|
+
const foreignFill = mix(
|
|
46159
|
+
palette.colors.gray,
|
|
46160
|
+
palette.bg,
|
|
46161
|
+
isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46162
|
+
);
|
|
46163
|
+
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
45985
46164
|
const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
|
|
45986
46165
|
const scaleOverride = resolved.directives.scale;
|
|
45987
46166
|
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
|
|
45988
46167
|
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
|
|
45989
|
-
const rampHue = palette.
|
|
46168
|
+
const rampHue = palette.colors.red;
|
|
45990
46169
|
const hasRamp = scores.length > 0;
|
|
45991
|
-
const
|
|
45992
|
-
|
|
45993
|
-
|
|
45994
|
-
|
|
46170
|
+
const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
|
|
46171
|
+
const matchColorGroup = (v) => {
|
|
46172
|
+
const lv = v.trim().toLowerCase();
|
|
46173
|
+
if (lv === "none") return null;
|
|
46174
|
+
if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
|
|
46175
|
+
return SCORE_NAME;
|
|
46176
|
+
const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
46177
|
+
return tg ? tg.name : v;
|
|
46178
|
+
};
|
|
46179
|
+
const override = opts.activeGroup;
|
|
46180
|
+
let activeGroup;
|
|
46181
|
+
if (override !== void 0) {
|
|
46182
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
46183
|
+
} else if (resolved.directives.activeTag !== void 0) {
|
|
46184
|
+
activeGroup = matchColorGroup(resolved.directives.activeTag);
|
|
46185
|
+
} else {
|
|
46186
|
+
activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46187
|
+
}
|
|
46188
|
+
const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
|
|
46189
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
45995
46190
|
const fillForScore = (s) => {
|
|
45996
46191
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
45997
46192
|
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
45998
|
-
return mix(rampHue,
|
|
46193
|
+
return mix(rampHue, rampBase, pct);
|
|
45999
46194
|
};
|
|
46000
46195
|
const tagFill = (tags, groupName) => {
|
|
46001
46196
|
if (!groupName) return null;
|
|
@@ -46009,40 +46204,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46009
46204
|
(e) => e.value.toLowerCase() === val.toLowerCase()
|
|
46010
46205
|
);
|
|
46011
46206
|
if (!entry?.color) return null;
|
|
46012
|
-
return
|
|
46207
|
+
return mix(
|
|
46208
|
+
entry.color,
|
|
46209
|
+
palette.bg,
|
|
46210
|
+
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46211
|
+
);
|
|
46212
|
+
};
|
|
46213
|
+
const regionFill = (r) => {
|
|
46214
|
+
if (activeIsScore) {
|
|
46215
|
+
return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
|
|
46216
|
+
}
|
|
46217
|
+
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46013
46218
|
};
|
|
46014
46219
|
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 = () => {
|
|
46220
|
+
const extentOutline = () => {
|
|
46021
46221
|
const [[w, s], [e, n]] = resolved.extent;
|
|
46222
|
+
const N = 16;
|
|
46223
|
+
const coords = [];
|
|
46224
|
+
for (let i = 0; i <= N; i++) {
|
|
46225
|
+
const t = i / N;
|
|
46226
|
+
const lon = w + (e - w) * t;
|
|
46227
|
+
const lat = s + (n - s) * t;
|
|
46228
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46229
|
+
}
|
|
46022
46230
|
return {
|
|
46023
46231
|
type: "Feature",
|
|
46024
46232
|
properties: {},
|
|
46025
|
-
geometry: {
|
|
46026
|
-
type: "MultiPoint",
|
|
46027
|
-
coordinates: [
|
|
46028
|
-
[w, s],
|
|
46029
|
-
[e, s],
|
|
46030
|
-
[e, n],
|
|
46031
|
-
[w, n]
|
|
46032
|
-
]
|
|
46033
|
-
}
|
|
46233
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46034
46234
|
};
|
|
46035
46235
|
};
|
|
46036
46236
|
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
|
-
}
|
|
46237
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46238
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46044
46239
|
} else {
|
|
46045
|
-
fitFeatures = [
|
|
46240
|
+
fitFeatures = [extentOutline()];
|
|
46046
46241
|
}
|
|
46047
46242
|
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46048
46243
|
const projection = projectionFor(resolved.projection);
|
|
@@ -46051,32 +46246,311 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46051
46246
|
if (centerLon > 180) centerLon -= 360;
|
|
46052
46247
|
projection.rotate([-centerLon, 0]);
|
|
46053
46248
|
}
|
|
46054
|
-
|
|
46249
|
+
const TITLE_GAP = 16;
|
|
46250
|
+
let topPad = FIT_PAD;
|
|
46251
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
46252
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46253
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP);
|
|
46254
|
+
}
|
|
46255
|
+
const fitBox = [
|
|
46256
|
+
[FIT_PAD, topPad],
|
|
46055
46257
|
[
|
|
46056
|
-
|
|
46057
|
-
|
|
46058
|
-
|
|
46059
|
-
|
|
46060
|
-
|
|
46061
|
-
|
|
46062
|
-
|
|
46063
|
-
|
|
46064
|
-
|
|
46065
|
-
|
|
46258
|
+
Math.max(FIT_PAD + 1, width - FIT_PAD),
|
|
46259
|
+
Math.max(topPad + 1, height - FIT_PAD)
|
|
46260
|
+
]
|
|
46261
|
+
];
|
|
46262
|
+
projection.fitExtent(fitBox, fitTarget);
|
|
46263
|
+
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
46264
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46265
|
+
let path;
|
|
46266
|
+
let project;
|
|
46267
|
+
if (fitIsGlobal) {
|
|
46268
|
+
const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
|
|
46269
|
+
const bx0 = cb[0][0];
|
|
46270
|
+
const by0 = cb[0][1];
|
|
46271
|
+
const cw = cb[1][0] - bx0;
|
|
46272
|
+
const ch = cb[1][1] - by0;
|
|
46273
|
+
const ox = fitBox[0][0];
|
|
46274
|
+
const oy = fitBox[0][1];
|
|
46275
|
+
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46276
|
+
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
46277
|
+
const stretch = (x, y) => [
|
|
46278
|
+
ox + (x - bx0) * sx,
|
|
46279
|
+
oy + (y - by0) * sy
|
|
46280
|
+
];
|
|
46281
|
+
const baseProjection = projection;
|
|
46282
|
+
const tx = (0, import_d3_geo2.geoTransform)({
|
|
46283
|
+
point(x, y) {
|
|
46284
|
+
const [px, py] = stretch(x, y);
|
|
46285
|
+
this.stream.point(px, py);
|
|
46286
|
+
}
|
|
46287
|
+
});
|
|
46288
|
+
path = (0, import_d3_geo2.geoPath)({
|
|
46289
|
+
stream: (s) => baseProjection.stream(
|
|
46290
|
+
tx.stream(s)
|
|
46291
|
+
)
|
|
46292
|
+
});
|
|
46293
|
+
project = (lon, lat) => {
|
|
46294
|
+
const p = baseProjection([lon, lat]);
|
|
46295
|
+
return p ? stretch(p[0], p[1]) : null;
|
|
46296
|
+
};
|
|
46297
|
+
} else {
|
|
46298
|
+
path = (0, import_d3_geo2.geoPath)(projection);
|
|
46299
|
+
project = (lon, lat) => projection([lon, lat]) ?? null;
|
|
46300
|
+
}
|
|
46301
|
+
const insets = [];
|
|
46302
|
+
const insetRegions = [];
|
|
46303
|
+
const insetLabelSeeds = [];
|
|
46304
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46305
|
+
const PAD = 8;
|
|
46306
|
+
const GAP = 12;
|
|
46307
|
+
const yB = height - FIT_PAD;
|
|
46308
|
+
const BW = 8;
|
|
46309
|
+
const coast = /* @__PURE__ */ new Map();
|
|
46310
|
+
const addPt = (lon, lat) => {
|
|
46311
|
+
const p = projection([lon, lat]);
|
|
46312
|
+
if (!p) return;
|
|
46313
|
+
const bi = Math.floor(p[0] / BW);
|
|
46314
|
+
const cur = coast.get(bi);
|
|
46315
|
+
if (cur === void 0 || p[1] > cur) coast.set(bi, p[1]);
|
|
46316
|
+
};
|
|
46317
|
+
const walk = (co) => {
|
|
46318
|
+
if (Array.isArray(co) && typeof co[0] === "number")
|
|
46319
|
+
addPt(co[0], co[1]);
|
|
46320
|
+
else if (Array.isArray(co)) for (const c of co) walk(c);
|
|
46321
|
+
};
|
|
46322
|
+
for (const [iso, f] of usLayer) {
|
|
46323
|
+
if (US_NON_CONUS.has(iso)) continue;
|
|
46324
|
+
walk(f.geometry.coordinates);
|
|
46325
|
+
}
|
|
46326
|
+
const at = (x) => {
|
|
46327
|
+
const bi = Math.floor(x / BW);
|
|
46328
|
+
let y = -Infinity;
|
|
46329
|
+
for (let k = bi - 1; k <= bi + 1; k++) {
|
|
46330
|
+
const v = coast.get(k);
|
|
46331
|
+
if (v !== void 0 && v > y) y = v;
|
|
46332
|
+
}
|
|
46333
|
+
return y;
|
|
46334
|
+
};
|
|
46335
|
+
const coastTop = (x0, xr) => {
|
|
46336
|
+
const n = 24;
|
|
46337
|
+
const pts = [];
|
|
46338
|
+
let maxY = -Infinity;
|
|
46339
|
+
for (let i = 0; i <= n; i++) {
|
|
46340
|
+
const x = x0 + (xr - x0) * i / n;
|
|
46341
|
+
const y = at(x);
|
|
46342
|
+
if (y > -Infinity) {
|
|
46343
|
+
pts.push([x, y]);
|
|
46344
|
+
if (y > maxY) maxY = y;
|
|
46345
|
+
}
|
|
46346
|
+
}
|
|
46347
|
+
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46348
|
+
let m = 0;
|
|
46349
|
+
if (pts.length >= 2) {
|
|
46350
|
+
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46351
|
+
for (const [x, y] of pts) {
|
|
46352
|
+
sx += x;
|
|
46353
|
+
sy += y;
|
|
46354
|
+
sxx += x * x;
|
|
46355
|
+
sxy += x * y;
|
|
46356
|
+
}
|
|
46357
|
+
const den = pts.length * sxx - sx * sx;
|
|
46358
|
+
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46359
|
+
}
|
|
46360
|
+
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46361
|
+
let c = -Infinity;
|
|
46362
|
+
for (const [x, y] of pts) {
|
|
46363
|
+
const need = y - m * x + GAP;
|
|
46364
|
+
if (need > c) c = need;
|
|
46365
|
+
}
|
|
46366
|
+
return (x) => m * x + c;
|
|
46367
|
+
};
|
|
46368
|
+
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46369
|
+
const f = usLayer.get(iso);
|
|
46370
|
+
if (!f) return boxX;
|
|
46371
|
+
const x0 = boxX;
|
|
46372
|
+
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46373
|
+
if (iw < 24) return boxX;
|
|
46374
|
+
const xr = x0 + iw + 2 * PAD;
|
|
46375
|
+
const top = coastTop(x0, xr);
|
|
46376
|
+
const yL = top(x0);
|
|
46377
|
+
const yR = top(xr);
|
|
46378
|
+
proj.fitWidth(iw, f);
|
|
46379
|
+
const bb = (0, import_d3_geo2.geoPath)(proj).bounds(f);
|
|
46380
|
+
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46381
|
+
const needH = sh + 2 * PAD;
|
|
46382
|
+
let topFit = Math.max(yL, yR);
|
|
46383
|
+
const bottom = Math.min(topFit + needH, yB);
|
|
46384
|
+
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46385
|
+
const lift = topFit - Math.max(yL, yR);
|
|
46386
|
+
const topL = yL + lift;
|
|
46387
|
+
const topR = yR + lift;
|
|
46388
|
+
proj.fitExtent(
|
|
46389
|
+
[
|
|
46390
|
+
[x0 + PAD, topFit + PAD],
|
|
46391
|
+
[xr - PAD, bottom - PAD]
|
|
46392
|
+
],
|
|
46393
|
+
f
|
|
46394
|
+
);
|
|
46395
|
+
const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
|
|
46396
|
+
if (!d) return xr;
|
|
46397
|
+
const r = regionById.get(iso);
|
|
46398
|
+
let fill2 = neutralFill;
|
|
46399
|
+
let lineNumber = -1;
|
|
46400
|
+
if (r?.layer === "us-state") {
|
|
46401
|
+
fill2 = regionFill(r);
|
|
46402
|
+
lineNumber = r.lineNumber;
|
|
46403
|
+
}
|
|
46404
|
+
insets.push({
|
|
46405
|
+
x: x0,
|
|
46406
|
+
y: Math.min(topL, topR),
|
|
46407
|
+
w: xr - x0,
|
|
46408
|
+
h: bottom - Math.min(topL, topR),
|
|
46409
|
+
points: [
|
|
46410
|
+
[x0, topL],
|
|
46411
|
+
[xr, topR],
|
|
46412
|
+
[xr, bottom],
|
|
46413
|
+
[x0, bottom]
|
|
46414
|
+
]
|
|
46415
|
+
});
|
|
46416
|
+
insetRegions.push({
|
|
46417
|
+
id: iso,
|
|
46418
|
+
d,
|
|
46419
|
+
fill: fill2,
|
|
46420
|
+
stroke: regionStroke,
|
|
46421
|
+
lineNumber,
|
|
46422
|
+
layer: "us-state",
|
|
46423
|
+
...r?.score !== void 0 && { score: r.score },
|
|
46424
|
+
...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46425
|
+
});
|
|
46426
|
+
const ctr = (0, import_d3_geo2.geoPath)(proj).centroid(f);
|
|
46427
|
+
if (Number.isFinite(ctr[0])) {
|
|
46428
|
+
const name = f.properties?.name ?? iso;
|
|
46429
|
+
insetLabelSeeds.push({ x: ctr[0], y: ctr[1], iso, name, lineNumber });
|
|
46430
|
+
}
|
|
46431
|
+
return xr;
|
|
46432
|
+
};
|
|
46433
|
+
const akRight = placeInset(
|
|
46434
|
+
"US-AK",
|
|
46435
|
+
alaskaProjection(),
|
|
46436
|
+
FIT_PAD,
|
|
46437
|
+
width * 0.15
|
|
46438
|
+
);
|
|
46439
|
+
placeInset("US-HI", hawaiiProjection(), akRight + 24, width * 0.1);
|
|
46440
|
+
}
|
|
46441
|
+
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46442
|
+
const cullExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
|
|
46443
|
+
const [[exW, exS], [exE, exN]] = cullExtent;
|
|
46444
|
+
const lonSpan = exE - exW;
|
|
46445
|
+
const latSpan = exN - exS;
|
|
46446
|
+
const isGlobalView = lonSpan >= 270 || latSpan >= 130;
|
|
46447
|
+
const padLon = Math.max(8, lonSpan * 0.35);
|
|
46448
|
+
const padLat = Math.max(8, latSpan * 0.35);
|
|
46449
|
+
const vW = exW - padLon;
|
|
46450
|
+
const vE = exE + padLon;
|
|
46451
|
+
const vS = exS - padLat;
|
|
46452
|
+
const vN = exN + padLat;
|
|
46453
|
+
const vLonCenter = (exW + exE) / 2;
|
|
46454
|
+
const normLon = (lon) => {
|
|
46455
|
+
let L = lon;
|
|
46456
|
+
while (L < vLonCenter - 180) L += 360;
|
|
46457
|
+
while (L > vLonCenter + 180) L -= 360;
|
|
46458
|
+
return L;
|
|
46459
|
+
};
|
|
46460
|
+
const ringOverlapsView = (ring) => {
|
|
46461
|
+
let anyIn = false;
|
|
46462
|
+
let loMin = Infinity, loMax = -Infinity, laMin = Infinity, laMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
46463
|
+
for (const [rawLon, lat] of ring) {
|
|
46464
|
+
const lon = normLon(rawLon);
|
|
46465
|
+
if (lon >= vW && lon <= vE && lat >= vS && lat <= vN) anyIn = true;
|
|
46466
|
+
if (lon < loMin) loMin = lon;
|
|
46467
|
+
if (lon > loMax) loMax = lon;
|
|
46468
|
+
if (rawLon < rawMin) rawMin = rawLon;
|
|
46469
|
+
if (rawLon > rawMax) rawMax = rawLon;
|
|
46470
|
+
if (lat < laMin) laMin = lat;
|
|
46471
|
+
if (lat > laMax) laMax = lat;
|
|
46472
|
+
}
|
|
46473
|
+
if (loMax - loMin > 270) return false;
|
|
46474
|
+
if (rawMax - rawMin > 180 && loMax - loMin < 90) return false;
|
|
46475
|
+
if (anyIn) return true;
|
|
46476
|
+
if (loMax - loMin > 180) return false;
|
|
46477
|
+
return !(loMax < vW || loMin > vE || laMax < vS || laMin > vN);
|
|
46478
|
+
};
|
|
46479
|
+
const cullFeatureToView = (f) => {
|
|
46480
|
+
if (isGlobalView) return f;
|
|
46481
|
+
const g = f.geometry;
|
|
46482
|
+
if (!g) return f;
|
|
46483
|
+
if (g.type === "Polygon") {
|
|
46484
|
+
const ring = g.coordinates[0];
|
|
46485
|
+
return ringOverlapsView(ring) ? f : null;
|
|
46486
|
+
}
|
|
46487
|
+
if (g.type === "MultiPolygon") {
|
|
46488
|
+
const polys = g.coordinates;
|
|
46489
|
+
const keep = polys.filter(
|
|
46490
|
+
(p) => ringOverlapsView(p[0])
|
|
46491
|
+
);
|
|
46492
|
+
if (!keep.length) return null;
|
|
46493
|
+
if (keep.length === polys.length) return f;
|
|
46494
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46495
|
+
}
|
|
46496
|
+
return f;
|
|
46497
|
+
};
|
|
46498
|
+
const SEAM_SLIVER_MAX_SPAN = 100;
|
|
46499
|
+
const ringIsFrameFiller = (ring) => {
|
|
46500
|
+
const lons = ring.map(([lon]) => lon).sort((a, b) => a - b);
|
|
46501
|
+
if (lons.length < 2) return false;
|
|
46502
|
+
let maxGap = -1;
|
|
46503
|
+
let gapIdx = 0;
|
|
46504
|
+
for (let i = 1; i < lons.length; i++) {
|
|
46505
|
+
const g = lons[i] - lons[i - 1];
|
|
46506
|
+
if (g > maxGap) {
|
|
46507
|
+
maxGap = g;
|
|
46508
|
+
gapIdx = i;
|
|
46509
|
+
}
|
|
46510
|
+
}
|
|
46511
|
+
const wrapGap = lons[0] + 360 - lons[lons.length - 1];
|
|
46512
|
+
if (wrapGap >= maxGap) return false;
|
|
46513
|
+
const span = 360 - maxGap;
|
|
46514
|
+
const east = lons[gapIdx - 1] + 360;
|
|
46515
|
+
return east > 180 && span < SEAM_SLIVER_MAX_SPAN;
|
|
46516
|
+
};
|
|
46517
|
+
const dropFrameFillers = (f) => {
|
|
46518
|
+
const g = f.geometry;
|
|
46519
|
+
if (!g) return f;
|
|
46520
|
+
if (g.type === "Polygon") {
|
|
46521
|
+
const ring = g.coordinates[0];
|
|
46522
|
+
return ringIsFrameFiller(ring) ? null : f;
|
|
46523
|
+
}
|
|
46524
|
+
if (g.type === "MultiPolygon") {
|
|
46525
|
+
const polys = g.coordinates;
|
|
46526
|
+
const keep = polys.filter(
|
|
46527
|
+
(p) => !ringIsFrameFiller(p[0])
|
|
46528
|
+
);
|
|
46529
|
+
if (!keep.length) return null;
|
|
46530
|
+
if (keep.length === polys.length) return f;
|
|
46531
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46532
|
+
}
|
|
46533
|
+
return f;
|
|
46534
|
+
};
|
|
46066
46535
|
const regions = [];
|
|
46067
|
-
const pushRegionLayer = (layerFeatures, layerKind) => {
|
|
46536
|
+
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46068
46537
|
for (const [iso, f] of layerFeatures) {
|
|
46069
|
-
|
|
46070
|
-
|
|
46538
|
+
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
46539
|
+
continue;
|
|
46540
|
+
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46071
46541
|
const r = regionById.get(iso);
|
|
46542
|
+
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
46543
|
+
if (!viewF) continue;
|
|
46544
|
+
const d = path(viewF) ?? "";
|
|
46545
|
+
if (!d) continue;
|
|
46072
46546
|
const isThisLayer = r?.layer === layerKind;
|
|
46073
|
-
|
|
46547
|
+
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46548
|
+
let fill2 = isForeign ? foreignFill : neutralFill;
|
|
46074
46549
|
let label;
|
|
46075
46550
|
let lineNumber = -1;
|
|
46076
46551
|
let layer = "base";
|
|
46077
46552
|
if (isThisLayer) {
|
|
46078
|
-
|
|
46079
|
-
else fill2 = tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46553
|
+
fill2 = regionFill(r);
|
|
46080
46554
|
lineNumber = r.lineNumber;
|
|
46081
46555
|
layer = layerKind;
|
|
46082
46556
|
label = r.name;
|
|
@@ -46088,12 +46562,42 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46088
46562
|
stroke: regionStroke,
|
|
46089
46563
|
lineNumber,
|
|
46090
46564
|
layer,
|
|
46091
|
-
...label !== void 0 && { label }
|
|
46565
|
+
...label !== void 0 && { label },
|
|
46566
|
+
...isThisLayer && r.score !== void 0 && { score: r.score },
|
|
46567
|
+
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46092
46568
|
});
|
|
46093
46569
|
}
|
|
46094
46570
|
};
|
|
46095
|
-
pushRegionLayer(worldLayer, "country");
|
|
46096
|
-
if (usLayer) pushRegionLayer(usLayer, "us-state");
|
|
46571
|
+
pushRegionLayer(worldLayer, "country", !isGlobalView);
|
|
46572
|
+
if (usLayer) pushRegionLayer(usLayer, "us-state", !conusFit && !isGlobalView);
|
|
46573
|
+
const lakesTopo = usCrisp && data.naLakes ? data.naLakes : data.lakes;
|
|
46574
|
+
if (lakesTopo) {
|
|
46575
|
+
for (const [, f] of decodeLayer(lakesTopo)) {
|
|
46576
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46577
|
+
if (!viewF) continue;
|
|
46578
|
+
const d = path(viewF) ?? "";
|
|
46579
|
+
if (!d) continue;
|
|
46580
|
+
regions.push({
|
|
46581
|
+
id: "lake",
|
|
46582
|
+
d,
|
|
46583
|
+
fill: water,
|
|
46584
|
+
stroke: "none",
|
|
46585
|
+
lineNumber: -1,
|
|
46586
|
+
layer: "base"
|
|
46587
|
+
});
|
|
46588
|
+
}
|
|
46589
|
+
}
|
|
46590
|
+
const riverColor = water;
|
|
46591
|
+
const rivers = [];
|
|
46592
|
+
if (data.rivers) {
|
|
46593
|
+
for (const [, f] of decodeLayer(data.rivers)) {
|
|
46594
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46595
|
+
if (!viewF) continue;
|
|
46596
|
+
const d = path(viewF) ?? "";
|
|
46597
|
+
if (!d) continue;
|
|
46598
|
+
rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
|
|
46599
|
+
}
|
|
46600
|
+
}
|
|
46097
46601
|
const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
46098
46602
|
const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
|
|
46099
46603
|
const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
|
|
@@ -46114,8 +46618,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46114
46618
|
if (hex) return { fill: hex, stroke: mix(hex, palette.text, 18) };
|
|
46115
46619
|
}
|
|
46116
46620
|
return {
|
|
46117
|
-
fill: palette.
|
|
46118
|
-
stroke: mix(palette.
|
|
46621
|
+
fill: palette.colors.orange,
|
|
46622
|
+
stroke: mix(palette.colors.orange, palette.text, 18)
|
|
46119
46623
|
};
|
|
46120
46624
|
};
|
|
46121
46625
|
const routeNumberById = /* @__PURE__ */ new Map();
|
|
@@ -46153,7 +46657,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46153
46657
|
cy += Math.sin(ang) * COLO_R;
|
|
46154
46658
|
}
|
|
46155
46659
|
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
46156
|
-
poiScreen.set(e.p.id, { cx, cy });
|
|
46660
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
46157
46661
|
const num = routeNumberById.get(e.p.id);
|
|
46158
46662
|
pois.push({
|
|
46159
46663
|
id: e.p.id,
|
|
@@ -46170,17 +46674,36 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46170
46674
|
});
|
|
46171
46675
|
}
|
|
46172
46676
|
const legs = [];
|
|
46677
|
+
const RIM_GAP = 1.5;
|
|
46173
46678
|
const legPath = (a, b, curved, offset) => {
|
|
46174
|
-
if (!curved && offset === 0) return `M${a.cx},${a.cy}L${b.cx},${b.cy}`;
|
|
46175
46679
|
const mx = (a.cx + b.cx) / 2;
|
|
46176
46680
|
const my = (a.cy + b.cy) / 2;
|
|
46177
46681
|
const dx = b.cx - a.cx;
|
|
46178
46682
|
const dy = b.cy - a.cy;
|
|
46179
46683
|
const len = Math.hypot(dx, dy) || 1;
|
|
46684
|
+
const trimA = Math.min(a.r + RIM_GAP, len * 0.45);
|
|
46685
|
+
const trimB = Math.min(b.r + RIM_GAP, len * 0.45);
|
|
46686
|
+
if (!curved && offset === 0) {
|
|
46687
|
+
const ux = dx / len;
|
|
46688
|
+
const uy = dy / len;
|
|
46689
|
+
const ax2 = a.cx + ux * trimA;
|
|
46690
|
+
const ay2 = a.cy + uy * trimA;
|
|
46691
|
+
const bx2 = b.cx - ux * trimB;
|
|
46692
|
+
const by2 = b.cy - uy * trimB;
|
|
46693
|
+
return `M${ax2},${ay2}L${bx2},${by2}`;
|
|
46694
|
+
}
|
|
46180
46695
|
const nx = -dy / len;
|
|
46181
46696
|
const ny = dx / len;
|
|
46182
46697
|
const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
|
|
46183
|
-
|
|
46698
|
+
const px = mx + nx * bow;
|
|
46699
|
+
const py = my + ny * bow;
|
|
46700
|
+
const ta = Math.hypot(px - a.cx, py - a.cy) || 1;
|
|
46701
|
+
const tb = Math.hypot(b.cx - px, b.cy - py) || 1;
|
|
46702
|
+
const ax = a.cx + (px - a.cx) / ta * trimA;
|
|
46703
|
+
const ay = a.cy + (py - a.cy) / ta * trimA;
|
|
46704
|
+
const bx = b.cx - (b.cx - px) / tb * trimB;
|
|
46705
|
+
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
46706
|
+
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
46184
46707
|
};
|
|
46185
46708
|
for (const rt of resolved.routes) {
|
|
46186
46709
|
const curved = rt.meta["style"] === "arc";
|
|
@@ -46191,7 +46714,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46191
46714
|
legs.push({
|
|
46192
46715
|
d: legPath(a, b, curved, 0),
|
|
46193
46716
|
width: W_MIN,
|
|
46194
|
-
color: mix(palette.text, palette.bg,
|
|
46717
|
+
color: mix(palette.text, palette.bg, 72),
|
|
46195
46718
|
arrow: true,
|
|
46196
46719
|
lineNumber: rt.lineNumber
|
|
46197
46720
|
});
|
|
@@ -46227,7 +46750,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46227
46750
|
legs.push({
|
|
46228
46751
|
d: legPath(a, b, curved, offset),
|
|
46229
46752
|
width: widthFor(e),
|
|
46230
|
-
color: mix(palette.text, palette.bg,
|
|
46753
|
+
color: mix(palette.text, palette.bg, 66),
|
|
46231
46754
|
arrow: e.directed,
|
|
46232
46755
|
lineNumber: e.lineNumber,
|
|
46233
46756
|
...e.label !== void 0 && {
|
|
@@ -46239,38 +46762,92 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46239
46762
|
});
|
|
46240
46763
|
}
|
|
46241
46764
|
const labels = [];
|
|
46242
|
-
const pinList = [];
|
|
46243
46765
|
const obstacles = [];
|
|
46244
46766
|
const markers = pois.map((p) => ({
|
|
46245
46767
|
cx: p.cx,
|
|
46246
46768
|
cy: p.cy,
|
|
46247
46769
|
r: p.r
|
|
46248
46770
|
}));
|
|
46249
|
-
const
|
|
46771
|
+
const legSegments = [];
|
|
46772
|
+
for (const leg of legs) {
|
|
46773
|
+
const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
46774
|
+
leg.d
|
|
46775
|
+
);
|
|
46776
|
+
if (!m) continue;
|
|
46777
|
+
const x0 = +m[1];
|
|
46778
|
+
const y0 = +m[2];
|
|
46779
|
+
if (m[3] !== void 0) {
|
|
46780
|
+
legSegments.push([x0, y0, +m[3], +m[4]]);
|
|
46781
|
+
} else {
|
|
46782
|
+
const cx = +m[5];
|
|
46783
|
+
const cy = +m[6];
|
|
46784
|
+
const ex = +m[7];
|
|
46785
|
+
const ey = +m[8];
|
|
46786
|
+
const N = 8;
|
|
46787
|
+
let px = x0;
|
|
46788
|
+
let py = y0;
|
|
46789
|
+
for (let i = 1; i <= N; i++) {
|
|
46790
|
+
const t = i / N;
|
|
46791
|
+
const u = 1 - t;
|
|
46792
|
+
const qx = u * u * x0 + 2 * u * t * cx + t * t * ex;
|
|
46793
|
+
const qy = u * u * y0 + 2 * u * t * cy + t * t * ey;
|
|
46794
|
+
legSegments.push([px, py, qx, qy]);
|
|
46795
|
+
px = qx;
|
|
46796
|
+
py = qy;
|
|
46797
|
+
}
|
|
46798
|
+
}
|
|
46799
|
+
}
|
|
46800
|
+
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
46801
|
const regionLabelMode = resolved.directives.regionLabels ?? "off";
|
|
46802
|
+
const LABEL_PADX = 6;
|
|
46803
|
+
const LABEL_PADY = 3;
|
|
46804
|
+
const labelW = (text) => measureLegendText(text, FONT) + 2 * LABEL_PADX;
|
|
46805
|
+
const labelH = FONT + 2 * LABEL_PADY;
|
|
46806
|
+
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
46807
|
+
const color = contrastText(
|
|
46808
|
+
fill2,
|
|
46809
|
+
palette.textOnFillLight,
|
|
46810
|
+
palette.textOnFillDark
|
|
46811
|
+
);
|
|
46812
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
46813
|
+
labels.push({
|
|
46814
|
+
x,
|
|
46815
|
+
y,
|
|
46816
|
+
text,
|
|
46817
|
+
anchor: "middle",
|
|
46818
|
+
color,
|
|
46819
|
+
halo: true,
|
|
46820
|
+
haloColor,
|
|
46821
|
+
lineNumber
|
|
46822
|
+
});
|
|
46823
|
+
};
|
|
46824
|
+
const WORLD_LABEL_ANCHORS = {
|
|
46825
|
+
US: [-98.5, 39.5]
|
|
46826
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
46827
|
+
};
|
|
46251
46828
|
if (regionLabelMode === "full" || regionLabelMode === "abbrev") {
|
|
46252
46829
|
for (const r of regions) {
|
|
46253
46830
|
if (r.layer === "base" || r.label === void 0) continue;
|
|
46254
46831
|
const f = r.layer === "us-state" ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
46255
46832
|
if (!f) continue;
|
|
46256
46833
|
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
46834
|
const text = regionLabelMode === "abbrev" ? r.id.replace(/^US-/, "") : r.label;
|
|
46261
|
-
|
|
46262
|
-
|
|
46263
|
-
|
|
46835
|
+
if (labelW(text) > x1 - x0 || labelH > y1 - y0) continue;
|
|
46836
|
+
const anchor = r.layer !== "us-state" ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
46837
|
+
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
46838
|
+
if (!c || !Number.isFinite(c[0])) continue;
|
|
46839
|
+
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
46840
|
+
}
|
|
46841
|
+
for (const seed of insetLabelSeeds) {
|
|
46842
|
+
const text = regionLabelMode === "abbrev" ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
46843
|
+
const src = regionById.get(seed.iso);
|
|
46844
|
+
pushRegionLabel(
|
|
46845
|
+
seed.x,
|
|
46846
|
+
seed.y,
|
|
46264
46847
|
text,
|
|
46265
|
-
|
|
46266
|
-
|
|
46267
|
-
|
|
46268
|
-
palette.textOnFillLight,
|
|
46269
|
-
palette.textOnFillDark
|
|
46270
|
-
),
|
|
46271
|
-
halo: true,
|
|
46272
|
-
lineNumber: r.lineNumber
|
|
46273
|
-
});
|
|
46848
|
+
src ? regionFill(src) : neutralFill,
|
|
46849
|
+
seed.lineNumber
|
|
46850
|
+
);
|
|
46274
46851
|
}
|
|
46275
46852
|
}
|
|
46276
46853
|
const poiLabelMode = resolved.directives.poiLabels ?? "auto";
|
|
@@ -46283,68 +46860,106 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46283
46860
|
const src = poiById.get(p.id);
|
|
46284
46861
|
return src?.label ?? src?.name ?? p.id;
|
|
46285
46862
|
};
|
|
46286
|
-
|
|
46287
|
-
|
|
46863
|
+
const poiLabH = FONT * 1.25;
|
|
46864
|
+
const labelInfo = (p) => {
|
|
46288
46865
|
const text = labelText(p);
|
|
46289
|
-
|
|
46290
|
-
|
|
46291
|
-
|
|
46292
|
-
|
|
46293
|
-
|
|
46866
|
+
return { text, w: measureLegendText(text, FONT) };
|
|
46867
|
+
};
|
|
46868
|
+
const pushInline = (p, text, w, side) => {
|
|
46869
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46870
|
+
obstacles.push({
|
|
46871
|
+
x: side === "right" ? tx : tx - w,
|
|
46872
|
+
y: p.cy - poiLabH / 2,
|
|
46873
|
+
w,
|
|
46874
|
+
h: poiLabH
|
|
46875
|
+
});
|
|
46876
|
+
labels.push({
|
|
46877
|
+
x: tx,
|
|
46878
|
+
y: p.cy + FONT / 3,
|
|
46879
|
+
text,
|
|
46880
|
+
anchor: side === "right" ? "start" : "end",
|
|
46881
|
+
color: palette.text,
|
|
46882
|
+
halo: true,
|
|
46883
|
+
haloColor: palette.bg,
|
|
46884
|
+
poiId: p.id,
|
|
46885
|
+
lineNumber: p.lineNumber
|
|
46886
|
+
});
|
|
46887
|
+
};
|
|
46888
|
+
const inlineFits = (p, w, side) => {
|
|
46889
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
46890
|
+
const rect = {
|
|
46891
|
+
x: side === "right" ? tx : tx - w,
|
|
46892
|
+
y: p.cy - poiLabH / 2,
|
|
46893
|
+
w,
|
|
46894
|
+
h: poiLabH
|
|
46895
|
+
};
|
|
46896
|
+
return rect.x >= 0 && rect.x + rect.w <= width && !collides(rect);
|
|
46897
|
+
};
|
|
46898
|
+
const GROUP_R = 30;
|
|
46899
|
+
const groups = [];
|
|
46900
|
+
for (const p of ordered) {
|
|
46901
|
+
const near = groups.find(
|
|
46902
|
+
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
46903
|
+
);
|
|
46904
|
+
if (near) near.push(p);
|
|
46905
|
+
else groups.push([p]);
|
|
46906
|
+
}
|
|
46907
|
+
const ROW_GAP2 = 3;
|
|
46908
|
+
const step = poiLabH + ROW_GAP2;
|
|
46909
|
+
const COL_GAP = 16;
|
|
46910
|
+
const placeColumn = (group) => {
|
|
46911
|
+
const items = group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
46912
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
46913
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
46914
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
46915
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
46916
|
+
const side = right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
46917
|
+
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
46918
|
+
const totalH = items.length * step;
|
|
46919
|
+
let startY = cyMid - totalH / 2;
|
|
46920
|
+
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
46921
|
+
items.forEach((o, i) => {
|
|
46922
|
+
const rowCy = startY + i * step + step / 2;
|
|
46923
|
+
obstacles.push({
|
|
46924
|
+
x: side === "right" ? colX : colX - o.w,
|
|
46925
|
+
y: rowCy - poiLabH / 2,
|
|
46926
|
+
w: o.w,
|
|
46927
|
+
h: poiLabH
|
|
46928
|
+
});
|
|
46294
46929
|
labels.push({
|
|
46295
|
-
x:
|
|
46296
|
-
y:
|
|
46297
|
-
text,
|
|
46298
|
-
anchor: "start",
|
|
46930
|
+
x: colX,
|
|
46931
|
+
y: rowCy + FONT / 3,
|
|
46932
|
+
text: o.text,
|
|
46933
|
+
anchor: side === "right" ? "start" : "end",
|
|
46299
46934
|
color: palette.text,
|
|
46300
46935
|
halo: true,
|
|
46301
|
-
|
|
46936
|
+
haloColor: palette.bg,
|
|
46937
|
+
leader: {
|
|
46938
|
+
x1: o.p.cx,
|
|
46939
|
+
y1: o.p.cy,
|
|
46940
|
+
x2: side === "right" ? colX - 2 : colX + 2,
|
|
46941
|
+
y2: rowCy
|
|
46942
|
+
},
|
|
46943
|
+
leaderColor: o.p.fill,
|
|
46944
|
+
poiId: o.p.id,
|
|
46945
|
+
lineNumber: o.p.lineNumber
|
|
46302
46946
|
});
|
|
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;
|
|
46947
|
+
});
|
|
46948
|
+
};
|
|
46949
|
+
for (const g of groups) {
|
|
46950
|
+
if (g.length === 1) {
|
|
46951
|
+
const p = g[0];
|
|
46952
|
+
const { text, w } = labelInfo(p);
|
|
46953
|
+
if (inlineFits(p, w, "right")) {
|
|
46954
|
+
pushInline(p, text, w, "right");
|
|
46955
|
+
continue;
|
|
46956
|
+
}
|
|
46957
|
+
if (inlineFits(p, w, "left")) {
|
|
46958
|
+
pushInline(p, text, w, "left");
|
|
46959
|
+
continue;
|
|
46333
46960
|
}
|
|
46334
46961
|
}
|
|
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
|
-
});
|
|
46962
|
+
placeColumn(g);
|
|
46348
46963
|
}
|
|
46349
46964
|
}
|
|
46350
46965
|
let legend = null;
|
|
@@ -46353,8 +46968,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46353
46968
|
name: g.name,
|
|
46354
46969
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
46355
46970
|
}));
|
|
46356
|
-
|
|
46357
|
-
if (hasAnything) {
|
|
46971
|
+
if (tagGroups.length > 0 || hasRamp) {
|
|
46358
46972
|
legend = {
|
|
46359
46973
|
tagGroups,
|
|
46360
46974
|
activeGroup,
|
|
@@ -46365,20 +46979,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46365
46979
|
},
|
|
46366
46980
|
min: rampMin,
|
|
46367
46981
|
max: rampMax,
|
|
46368
|
-
hue: rampHue
|
|
46982
|
+
hue: rampHue,
|
|
46983
|
+
base: rampBase
|
|
46369
46984
|
}
|
|
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
|
|
46378
|
-
}
|
|
46379
|
-
},
|
|
46380
|
-
...weightVals.length > 0 && {
|
|
46381
|
-
weight: { min: wMin, max: wMax }
|
|
46382
46985
|
}
|
|
46383
46986
|
};
|
|
46384
46987
|
}
|
|
@@ -46386,28 +46989,30 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46386
46989
|
return {
|
|
46387
46990
|
width,
|
|
46388
46991
|
height,
|
|
46389
|
-
background:
|
|
46992
|
+
background: water,
|
|
46390
46993
|
title: resolved.title,
|
|
46391
46994
|
...resolved.subtitle !== void 0 && { subtitle: resolved.subtitle },
|
|
46392
46995
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
46393
46996
|
regions,
|
|
46997
|
+
rivers,
|
|
46394
46998
|
legs,
|
|
46395
46999
|
pois,
|
|
46396
47000
|
labels,
|
|
46397
|
-
|
|
46398
|
-
|
|
47001
|
+
legend,
|
|
47002
|
+
insets,
|
|
47003
|
+
insetRegions
|
|
46399
47004
|
};
|
|
46400
47005
|
}
|
|
46401
|
-
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT,
|
|
47006
|
+
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
47007
|
var init_layout15 = __esm({
|
|
46403
47008
|
"src/map/layout.ts"() {
|
|
46404
47009
|
"use strict";
|
|
46405
47010
|
import_d3_geo2 = require("d3-geo");
|
|
46406
47011
|
import_topojson_client2 = require("topojson-client");
|
|
46407
47012
|
init_color_utils();
|
|
46408
|
-
init_tag_groups();
|
|
46409
47013
|
init_label_layout();
|
|
46410
47014
|
init_legend_constants();
|
|
47015
|
+
init_title_constants();
|
|
46411
47016
|
FIT_PAD = 24;
|
|
46412
47017
|
RAMP_FLOOR = 15;
|
|
46413
47018
|
R_DEFAULT = 6;
|
|
@@ -46416,23 +47021,32 @@ var init_layout15 = __esm({
|
|
|
46416
47021
|
W_MIN = 1.25;
|
|
46417
47022
|
W_MAX = 8;
|
|
46418
47023
|
FONT = 11;
|
|
46419
|
-
LEADER_STEP = 14;
|
|
46420
47024
|
COLO_EPS = 1.5;
|
|
47025
|
+
LAND_TINT_LIGHT = 58;
|
|
47026
|
+
LAND_TINT_DARK = 75;
|
|
47027
|
+
TAG_TINT_LIGHT = 60;
|
|
47028
|
+
TAG_TINT_DARK = 68;
|
|
47029
|
+
WATER_TINT = 55;
|
|
47030
|
+
RIVER_WIDTH = 1.3;
|
|
47031
|
+
FOREIGN_TINT_LIGHT = 30;
|
|
47032
|
+
FOREIGN_TINT_DARK = 62;
|
|
46421
47033
|
COLO_R = 9;
|
|
46422
47034
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
46423
47035
|
FAN_STEP = 16;
|
|
46424
|
-
TINY_REGION_AREA = 600;
|
|
46425
47036
|
ARC_CURVE_FRAC = 0.18;
|
|
46426
|
-
|
|
46427
|
-
|
|
46428
|
-
|
|
46429
|
-
|
|
46430
|
-
|
|
46431
|
-
|
|
46432
|
-
|
|
46433
|
-
|
|
46434
|
-
|
|
46435
|
-
|
|
47037
|
+
usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47038
|
+
alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47039
|
+
hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
|
|
47040
|
+
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
47041
|
+
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47042
|
+
"US-AK",
|
|
47043
|
+
"US-HI",
|
|
47044
|
+
"US-AS",
|
|
47045
|
+
"US-GU",
|
|
47046
|
+
"US-MP",
|
|
47047
|
+
"US-PR",
|
|
47048
|
+
"US-VI"
|
|
47049
|
+
]);
|
|
46436
47050
|
}
|
|
46437
47051
|
});
|
|
46438
47052
|
|
|
@@ -46442,7 +47056,7 @@ __export(renderer_exports16, {
|
|
|
46442
47056
|
renderMap: () => renderMap,
|
|
46443
47057
|
renderMapForExport: () => renderMapForExport
|
|
46444
47058
|
});
|
|
46445
|
-
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims) {
|
|
47059
|
+
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
46446
47060
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
46447
47061
|
const width = exportDims?.width ?? container.clientWidth;
|
|
46448
47062
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -46453,27 +47067,29 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46453
47067
|
{ width, height },
|
|
46454
47068
|
{
|
|
46455
47069
|
palette,
|
|
46456
|
-
isDark
|
|
47070
|
+
isDark,
|
|
47071
|
+
...activeGroupOverride !== void 0 && {
|
|
47072
|
+
activeGroup: activeGroupOverride
|
|
47073
|
+
}
|
|
46457
47074
|
}
|
|
46458
47075
|
);
|
|
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);
|
|
47076
|
+
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
47077
|
svg.append("rect").attr("width", width).attr("height", height).attr("fill", layout.background);
|
|
46461
|
-
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
46462
47078
|
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
|
-
}
|
|
47079
|
+
const arrowSize = (w) => Math.min(15, 7 + w * 0.95);
|
|
47080
|
+
const haloColor = palette.bg;
|
|
46474
47081
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
46475
|
-
|
|
46476
|
-
const p =
|
|
47082
|
+
const drawRegion = (g, r, strokeWidth) => {
|
|
47083
|
+
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
47084
|
+
if (r.layer !== "base") {
|
|
47085
|
+
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47086
|
+
if (r.score !== void 0) p.attr("data-score", r.score);
|
|
47087
|
+
if (r.tags) {
|
|
47088
|
+
for (const [group, value] of Object.entries(r.tags)) {
|
|
47089
|
+
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
47090
|
+
}
|
|
47091
|
+
}
|
|
47092
|
+
}
|
|
46477
47093
|
if (r.lineNumber >= 0) {
|
|
46478
47094
|
p.attr("data-line-number", r.lineNumber);
|
|
46479
47095
|
if (onClickItem) {
|
|
@@ -46483,11 +47099,31 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46483
47099
|
);
|
|
46484
47100
|
}
|
|
46485
47101
|
}
|
|
47102
|
+
};
|
|
47103
|
+
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
47104
|
+
if (layout.rivers.length) {
|
|
47105
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47106
|
+
for (const r of layout.rivers) {
|
|
47107
|
+
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
47108
|
+
}
|
|
47109
|
+
}
|
|
47110
|
+
if (layout.insets.length) {
|
|
47111
|
+
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47112
|
+
for (const box of layout.insets) {
|
|
47113
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47114
|
+
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");
|
|
47115
|
+
}
|
|
47116
|
+
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
46486
47117
|
}
|
|
46487
47118
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
46488
|
-
|
|
47119
|
+
layout.legs.forEach((leg, i) => {
|
|
46489
47120
|
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)
|
|
47121
|
+
if (leg.arrow) {
|
|
47122
|
+
const id = `dgmo-map-arrow-${i}`;
|
|
47123
|
+
const s = arrowSize(leg.width);
|
|
47124
|
+
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);
|
|
47125
|
+
p.attr("marker-end", `url(#${id})`);
|
|
47126
|
+
}
|
|
46491
47127
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
46492
47128
|
emitText(
|
|
46493
47129
|
gLegs,
|
|
@@ -46501,13 +47137,13 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46501
47137
|
LABEL_FONT - 1
|
|
46502
47138
|
);
|
|
46503
47139
|
}
|
|
46504
|
-
}
|
|
47140
|
+
});
|
|
46505
47141
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
46506
47142
|
for (const poi of layout.pois) {
|
|
46507
47143
|
if (poi.isOrigin) {
|
|
46508
47144
|
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
47145
|
}
|
|
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);
|
|
47146
|
+
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
47147
|
if (onClickItem) {
|
|
46512
47148
|
c.style("cursor", "pointer").on(
|
|
46513
47149
|
"click",
|
|
@@ -46531,48 +47167,66 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46531
47167
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
46532
47168
|
for (const lab of layout.labels) {
|
|
46533
47169
|
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(
|
|
46535
|
-
|
|
46536
|
-
|
|
46537
|
-
|
|
47170
|
+
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(
|
|
47171
|
+
"stroke",
|
|
47172
|
+
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47173
|
+
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47174
|
+
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
46538
47175
|
}
|
|
46539
|
-
emitText(
|
|
47176
|
+
const t = emitText(
|
|
46540
47177
|
gLabels,
|
|
46541
47178
|
lab.x,
|
|
46542
47179
|
lab.y,
|
|
46543
47180
|
lab.text,
|
|
46544
47181
|
lab.anchor,
|
|
46545
47182
|
lab.color,
|
|
46546
|
-
haloColor,
|
|
47183
|
+
lab.haloColor,
|
|
46547
47184
|
lab.halo,
|
|
46548
47185
|
LABEL_FONT
|
|
46549
47186
|
);
|
|
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
|
-
});
|
|
47187
|
+
if (lab.poiId !== void 0) {
|
|
47188
|
+
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47189
|
+
}
|
|
46559
47190
|
}
|
|
46560
47191
|
if (layout.legend) {
|
|
46561
47192
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
46562
47193
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
46563
|
-
const
|
|
47194
|
+
const ramp = layout.legend.ramp;
|
|
47195
|
+
const scoreGroup = ramp ? {
|
|
47196
|
+
name: ramp.metric?.trim() || "Score",
|
|
47197
|
+
entries: [],
|
|
47198
|
+
gradient: {
|
|
47199
|
+
min: ramp.min,
|
|
47200
|
+
max: ramp.max,
|
|
47201
|
+
hue: ramp.hue,
|
|
47202
|
+
base: ramp.base
|
|
47203
|
+
}
|
|
47204
|
+
} : null;
|
|
47205
|
+
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47206
|
+
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
46564
47207
|
if (groups.length > 0) {
|
|
46565
47208
|
const config = {
|
|
46566
|
-
groups
|
|
47209
|
+
groups,
|
|
46567
47210
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
46568
47211
|
mode: exportDims ? "export" : "preview",
|
|
46569
|
-
showEmptyGroups: false
|
|
47212
|
+
showEmptyGroups: false,
|
|
47213
|
+
// Keep inactive siblings visible as pills so the user can click to flip
|
|
47214
|
+
// the active colouring dimension (preview only — export shows just the
|
|
47215
|
+
// active group).
|
|
47216
|
+
showInactivePills: true
|
|
46570
47217
|
};
|
|
46571
47218
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
46572
47219
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
46573
47220
|
}
|
|
46574
|
-
|
|
46575
|
-
|
|
47221
|
+
}
|
|
47222
|
+
if (layout.title) {
|
|
47223
|
+
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);
|
|
47224
|
+
}
|
|
47225
|
+
if (layout.subtitle) {
|
|
47226
|
+
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);
|
|
47227
|
+
}
|
|
47228
|
+
if (layout.caption) {
|
|
47229
|
+
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
47230
|
}
|
|
46577
47231
|
}
|
|
46578
47232
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
@@ -46583,54 +47237,7 @@ function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
|
46583
47237
|
if (withHalo) {
|
|
46584
47238
|
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7);
|
|
46585
47239
|
}
|
|
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();
|
|
47240
|
+
return t;
|
|
46634
47241
|
}
|
|
46635
47242
|
var d3Selection18, LABEL_FONT;
|
|
46636
47243
|
var init_renderer16 = __esm({
|