@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/advanced.js
CHANGED
|
@@ -331,6 +331,33 @@ function rectCircleOverlap(rect, circle) {
|
|
|
331
331
|
const dy = nearestY - circle.cy;
|
|
332
332
|
return dx * dx + dy * dy < circle.r * circle.r;
|
|
333
333
|
}
|
|
334
|
+
function segmentRectOverlap(x0, y0, x1, y1, rect) {
|
|
335
|
+
const dx = x1 - x0;
|
|
336
|
+
const dy = y1 - y0;
|
|
337
|
+
let t0 = 0;
|
|
338
|
+
let t1 = 1;
|
|
339
|
+
const edges = [
|
|
340
|
+
[-dx, x0 - rect.x],
|
|
341
|
+
[dx, rect.x + rect.w - x0],
|
|
342
|
+
[-dy, y0 - rect.y],
|
|
343
|
+
[dy, rect.y + rect.h - y0]
|
|
344
|
+
];
|
|
345
|
+
for (const [p, q] of edges) {
|
|
346
|
+
if (p === 0) {
|
|
347
|
+
if (q < 0) return false;
|
|
348
|
+
} else {
|
|
349
|
+
const t = q / p;
|
|
350
|
+
if (p < 0) {
|
|
351
|
+
if (t > t1) return false;
|
|
352
|
+
if (t > t0) t0 = t;
|
|
353
|
+
} else {
|
|
354
|
+
if (t < t0) return false;
|
|
355
|
+
if (t < t1) t1 = t;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
334
361
|
function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius, fontSize) {
|
|
335
362
|
const labelHeight = fontSize + 4;
|
|
336
363
|
const stepSize = labelHeight + 2;
|
|
@@ -3276,6 +3303,57 @@ var init_legend_constants = __esm({
|
|
|
3276
3303
|
});
|
|
3277
3304
|
|
|
3278
3305
|
// src/utils/legend-layout.ts
|
|
3306
|
+
function fmtRamp(n) {
|
|
3307
|
+
return Number.isInteger(n) ? String(n) : String(Math.round(n * 10) / 10);
|
|
3308
|
+
}
|
|
3309
|
+
function gradientCapsuleWidth(name, gradient) {
|
|
3310
|
+
const pw = pillWidth(name);
|
|
3311
|
+
const minW = measureLegendText(fmtRamp(gradient.min), LEGEND_ENTRY_FONT_SIZE);
|
|
3312
|
+
const maxW = measureLegendText(fmtRamp(gradient.max), LEGEND_ENTRY_FONT_SIZE);
|
|
3313
|
+
return LEGEND_CAPSULE_PAD + pw + 4 + minW + RAMP_LABEL_GAP + RAMP_LEGEND_W + RAMP_LABEL_GAP + maxW + LEGEND_CAPSULE_PAD;
|
|
3314
|
+
}
|
|
3315
|
+
function buildGradientCapsuleLayout(group, gradient) {
|
|
3316
|
+
const pw = pillWidth(group.name);
|
|
3317
|
+
const minText = fmtRamp(gradient.min);
|
|
3318
|
+
const maxText = fmtRamp(gradient.max);
|
|
3319
|
+
const minW = measureLegendText(minText, LEGEND_ENTRY_FONT_SIZE);
|
|
3320
|
+
const gx = LEGEND_CAPSULE_PAD + pw + 4;
|
|
3321
|
+
const minX = gx;
|
|
3322
|
+
const rampX = gx + minW + RAMP_LABEL_GAP;
|
|
3323
|
+
const maxX = rampX + RAMP_LEGEND_W + RAMP_LABEL_GAP;
|
|
3324
|
+
const width = gradientCapsuleWidth(group.name, gradient);
|
|
3325
|
+
return {
|
|
3326
|
+
groupName: group.name,
|
|
3327
|
+
x: 0,
|
|
3328
|
+
y: 0,
|
|
3329
|
+
width,
|
|
3330
|
+
height: LEGEND_HEIGHT,
|
|
3331
|
+
pill: {
|
|
3332
|
+
groupName: group.name,
|
|
3333
|
+
x: LEGEND_CAPSULE_PAD,
|
|
3334
|
+
y: LEGEND_CAPSULE_PAD,
|
|
3335
|
+
width: pw,
|
|
3336
|
+
height: LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2,
|
|
3337
|
+
isActive: true
|
|
3338
|
+
},
|
|
3339
|
+
entries: [],
|
|
3340
|
+
gradient: {
|
|
3341
|
+
rampX,
|
|
3342
|
+
rampY: (LEGEND_HEIGHT - RAMP_LEGEND_H) / 2,
|
|
3343
|
+
rampW: RAMP_LEGEND_W,
|
|
3344
|
+
rampH: RAMP_LEGEND_H,
|
|
3345
|
+
min: gradient.min,
|
|
3346
|
+
max: gradient.max,
|
|
3347
|
+
minText,
|
|
3348
|
+
minX,
|
|
3349
|
+
maxText,
|
|
3350
|
+
maxX,
|
|
3351
|
+
textY: LEGEND_HEIGHT / 2,
|
|
3352
|
+
hue: gradient.hue,
|
|
3353
|
+
base: gradient.base
|
|
3354
|
+
}
|
|
3355
|
+
};
|
|
3356
|
+
}
|
|
3279
3357
|
function pillWidth(name) {
|
|
3280
3358
|
return measureLegendText(name, LEGEND_PILL_FONT_SIZE) + LEGEND_PILL_PAD;
|
|
3281
3359
|
}
|
|
@@ -3418,7 +3496,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3418
3496
|
};
|
|
3419
3497
|
}
|
|
3420
3498
|
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3421
|
-
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0);
|
|
3499
|
+
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3422
3500
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3423
3501
|
return {
|
|
3424
3502
|
height: 0,
|
|
@@ -3497,7 +3575,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3497
3575
|
groupAvailW,
|
|
3498
3576
|
config.capsulePillAddonWidth ?? 0
|
|
3499
3577
|
);
|
|
3500
|
-
} else if (!activeGroupName) {
|
|
3578
|
+
} else if (!activeGroupName || config.showInactivePills) {
|
|
3501
3579
|
const pw = pillWidth(g.name);
|
|
3502
3580
|
pills.push({
|
|
3503
3581
|
groupName: g.name,
|
|
@@ -3535,6 +3613,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3535
3613
|
};
|
|
3536
3614
|
}
|
|
3537
3615
|
function buildCapsuleLayout(group, containerWidth, addonWidth = 0) {
|
|
3616
|
+
if (group.gradient) return buildGradientCapsuleLayout(group, group.gradient);
|
|
3538
3617
|
const pw = pillWidth(group.name);
|
|
3539
3618
|
const info = capsuleWidth(
|
|
3540
3619
|
group.name,
|
|
@@ -3709,7 +3788,7 @@ function getMaxLegendReservedHeight(config, containerWidth) {
|
|
|
3709
3788
|
}
|
|
3710
3789
|
return max;
|
|
3711
3790
|
}
|
|
3712
|
-
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
|
|
3791
|
+
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP, RAMP_LEGEND_W, RAMP_LEGEND_H, RAMP_LABEL_GAP;
|
|
3713
3792
|
var init_legend_layout = __esm({
|
|
3714
3793
|
"src/utils/legend-layout.ts"() {
|
|
3715
3794
|
"use strict";
|
|
@@ -3718,6 +3797,9 @@ var init_legend_layout = __esm({
|
|
|
3718
3797
|
CONTROL_FONT_SIZE = 11;
|
|
3719
3798
|
CONTROL_ICON_GAP = 4;
|
|
3720
3799
|
CONTROL_GAP = 8;
|
|
3800
|
+
RAMP_LEGEND_W = 80;
|
|
3801
|
+
RAMP_LEGEND_H = 8;
|
|
3802
|
+
RAMP_LABEL_GAP = 6;
|
|
3721
3803
|
}
|
|
3722
3804
|
});
|
|
3723
3805
|
|
|
@@ -3805,6 +3887,16 @@ function renderCapsule(parent, capsule, palette, groupBg, pillBorder, _isDark, c
|
|
|
3805
3887
|
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);
|
|
3806
3888
|
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);
|
|
3807
3889
|
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);
|
|
3890
|
+
if (capsule.gradient) {
|
|
3891
|
+
const gr = capsule.gradient;
|
|
3892
|
+
const gradId = `dgmo-legend-ramp-${capsule.groupName.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
3893
|
+
const def = g.append("defs").append("linearGradient").attr("id", gradId);
|
|
3894
|
+
def.append("stop").attr("offset", "0%").attr("stop-color", mix(gr.hue, gr.base, 15));
|
|
3895
|
+
def.append("stop").attr("offset", "100%").attr("stop-color", gr.hue);
|
|
3896
|
+
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);
|
|
3897
|
+
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})`);
|
|
3898
|
+
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);
|
|
3899
|
+
}
|
|
3808
3900
|
for (const entry of capsule.entries) {
|
|
3809
3901
|
const entryG = g.append("g").attr("data-legend-entry", entry.value.toLowerCase()).attr("data-series-name", entry.value).style("cursor", "pointer");
|
|
3810
3902
|
entryG.append("circle").attr("cx", entry.dotCx).attr("cy", entry.dotCy).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
|
|
@@ -11244,23 +11336,22 @@ function parseC4(content, palette) {
|
|
|
11244
11336
|
}
|
|
11245
11337
|
}
|
|
11246
11338
|
const parent = findParentElement(indent, stack);
|
|
11247
|
-
|
|
11248
|
-
|
|
11339
|
+
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
11340
|
+
if (parent && descResult.isKeyword) {
|
|
11249
11341
|
if (descResult.needsColon) {
|
|
11250
11342
|
pushError(
|
|
11251
11343
|
lineNumber,
|
|
11252
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11344
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`,
|
|
11253
11345
|
"warning"
|
|
11254
11346
|
);
|
|
11255
11347
|
}
|
|
11256
|
-
const descText = descResult.isKeyword ? descResult.text : trimmed;
|
|
11257
11348
|
let desc = elementDescription.get(parent.element);
|
|
11258
11349
|
if (!desc) {
|
|
11259
11350
|
desc = [];
|
|
11260
11351
|
elementDescription.set(parent.element, desc);
|
|
11261
11352
|
parent.element.description = desc;
|
|
11262
11353
|
}
|
|
11263
|
-
desc.push(
|
|
11354
|
+
desc.push(descResult.text);
|
|
11264
11355
|
} else {
|
|
11265
11356
|
pushError(lineNumber, `Unexpected content: "${trimmed}"`);
|
|
11266
11357
|
}
|
|
@@ -11727,7 +11818,7 @@ function parseSitemap(content, palette) {
|
|
|
11727
11818
|
if (descResult.needsColon) {
|
|
11728
11819
|
pushWarning(
|
|
11729
11820
|
lineNumber,
|
|
11730
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11821
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
11731
11822
|
);
|
|
11732
11823
|
}
|
|
11733
11824
|
const parent = findParentNode(indent, indentStack);
|
|
@@ -12555,23 +12646,22 @@ function parseInfra(content) {
|
|
|
12555
12646
|
}
|
|
12556
12647
|
}
|
|
12557
12648
|
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
12558
|
-
if (descResult.isKeyword
|
|
12559
|
-
|
|
12560
|
-
|
|
12561
|
-
|
|
12649
|
+
if (descResult.isKeyword) {
|
|
12650
|
+
if (currentNode.isEdge) {
|
|
12651
|
+
continue;
|
|
12652
|
+
}
|
|
12562
12653
|
if (descResult.needsColon) {
|
|
12563
12654
|
warn(
|
|
12564
12655
|
lineNumber,
|
|
12565
|
-
`Use "description: ${descResult.text}" \u2014
|
|
12656
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
12566
12657
|
);
|
|
12567
12658
|
}
|
|
12568
|
-
|
|
12569
|
-
pushDescription(currentNode, descText);
|
|
12659
|
+
pushDescription(currentNode, descResult.text);
|
|
12570
12660
|
continue;
|
|
12571
12661
|
}
|
|
12572
12662
|
warn(
|
|
12573
12663
|
lineNumber,
|
|
12574
|
-
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or description text.`
|
|
12664
|
+
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or a description (description: text).`
|
|
12575
12665
|
);
|
|
12576
12666
|
continue;
|
|
12577
12667
|
}
|
|
@@ -15708,9 +15798,6 @@ function parseMap(content) {
|
|
|
15708
15798
|
const pushWarning = (line12, message) => {
|
|
15709
15799
|
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15710
15800
|
};
|
|
15711
|
-
const pushInfo = (line12, message) => {
|
|
15712
|
-
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15713
|
-
};
|
|
15714
15801
|
const lines = content.split("\n");
|
|
15715
15802
|
let firstIdx = 0;
|
|
15716
15803
|
while (firstIdx < lines.length) {
|
|
@@ -15840,10 +15927,15 @@ function parseMap(content) {
|
|
|
15840
15927
|
break;
|
|
15841
15928
|
case "projection":
|
|
15842
15929
|
dup(d.projection);
|
|
15843
|
-
if (value && ![
|
|
15930
|
+
if (value && ![
|
|
15931
|
+
"equirectangular",
|
|
15932
|
+
"natural-earth",
|
|
15933
|
+
"albers-usa",
|
|
15934
|
+
"mercator"
|
|
15935
|
+
].includes(value))
|
|
15844
15936
|
pushWarning(
|
|
15845
15937
|
line12,
|
|
15846
|
-
`Unknown projection "${value}" (expected natural-earth | albers-usa | mercator).`
|
|
15938
|
+
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15847
15939
|
);
|
|
15848
15940
|
d.projection = value;
|
|
15849
15941
|
break;
|
|
@@ -15982,17 +16074,21 @@ function parseMap(content) {
|
|
|
15982
16074
|
scoreNum = void 0;
|
|
15983
16075
|
}
|
|
15984
16076
|
}
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
|
|
15989
|
-
|
|
16077
|
+
let regionName = split.name;
|
|
16078
|
+
let regionScope;
|
|
16079
|
+
const rToks = regionName.split(/\s+/);
|
|
16080
|
+
const rLast = rToks[rToks.length - 1];
|
|
16081
|
+
if (rToks.length > 1 && SCOPE_RE.test(rLast)) {
|
|
16082
|
+
regionName = rToks.slice(0, -1).join(" ");
|
|
16083
|
+
regionScope = rLast;
|
|
16084
|
+
}
|
|
15990
16085
|
const region = {
|
|
15991
|
-
name:
|
|
16086
|
+
name: regionName,
|
|
15992
16087
|
tags,
|
|
15993
16088
|
meta,
|
|
15994
16089
|
lineNumber: line12
|
|
15995
16090
|
};
|
|
16091
|
+
if (regionScope !== void 0) region.scope = regionScope;
|
|
15996
16092
|
if (scoreNum !== void 0) region.score = scoreNum;
|
|
15997
16093
|
regions.push(region);
|
|
15998
16094
|
}
|
|
@@ -17116,7 +17212,7 @@ function parseMindmap(content, palette) {
|
|
|
17116
17212
|
if (descResult.needsColon) {
|
|
17117
17213
|
pushWarning(
|
|
17118
17214
|
lineNumber,
|
|
17119
|
-
`Use "description: ${descResult.text}" \u2014
|
|
17215
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
17120
17216
|
);
|
|
17121
17217
|
}
|
|
17122
17218
|
const parent = findMetadataParent2(indent, indentStack);
|
|
@@ -18904,7 +19000,7 @@ function parseJourneyMap(content, palette) {
|
|
|
18904
19000
|
if (descResult.needsColon) {
|
|
18905
19001
|
warn(
|
|
18906
19002
|
lineNumber,
|
|
18907
|
-
`Use "description: ${descResult.text}" \u2014
|
|
19003
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
18908
19004
|
);
|
|
18909
19005
|
}
|
|
18910
19006
|
currentStep.description = descResult.text;
|
|
@@ -45806,7 +45902,9 @@ function resolveMap(parsed, data) {
|
|
|
45806
45902
|
const usScoped = parsed.directives.region === "us-states" || parsed.directives.defaultCountry?.toUpperCase() === "US" || parsed.regions.some((r) => {
|
|
45807
45903
|
const f = fold(r.name);
|
|
45808
45904
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45809
|
-
}) || parsed.
|
|
45905
|
+
}) || parsed.regions.some(
|
|
45906
|
+
(r) => r.scope === "US" || r.scope?.startsWith("US-")
|
|
45907
|
+
) || parsed.pois.some(
|
|
45810
45908
|
(p) => p.pos.kind === "name" && p.pos.scope?.startsWith("US-")
|
|
45811
45909
|
);
|
|
45812
45910
|
const regions = [];
|
|
@@ -45818,7 +45916,30 @@ function resolveMap(parsed, data) {
|
|
|
45818
45916
|
const inCountry = countryIndex.get(f) ?? (REGION_ALIASES[f] ? countryIndex.get(REGION_ALIASES[f]) : void 0);
|
|
45819
45917
|
const inState = usStateIndex.get(f);
|
|
45820
45918
|
let chosen = null;
|
|
45821
|
-
|
|
45919
|
+
const scope = r.scope;
|
|
45920
|
+
if (scope) {
|
|
45921
|
+
const wantsState = scope === "US" || scope.startsWith("US-");
|
|
45922
|
+
if (wantsState && inState) {
|
|
45923
|
+
if (scope.startsWith("US-") && inState.id !== scope) {
|
|
45924
|
+
err(
|
|
45925
|
+
r.lineNumber,
|
|
45926
|
+
`No subdivision "${r.name}" in scope ${scope} (it is ${inState.id}).`,
|
|
45927
|
+
"E_MAP_SCOPE_MISS"
|
|
45928
|
+
);
|
|
45929
|
+
continue;
|
|
45930
|
+
}
|
|
45931
|
+
chosen = { ...inState, layer: "us-state" };
|
|
45932
|
+
} else if (!wantsState && inCountry) {
|
|
45933
|
+
chosen = { ...inCountry, layer: "country" };
|
|
45934
|
+
} else {
|
|
45935
|
+
err(
|
|
45936
|
+
r.lineNumber,
|
|
45937
|
+
`No region "${r.name}" found in scope ${scope}.`,
|
|
45938
|
+
"E_MAP_SCOPE_MISS"
|
|
45939
|
+
);
|
|
45940
|
+
continue;
|
|
45941
|
+
}
|
|
45942
|
+
} else if (inCountry && inState) {
|
|
45822
45943
|
if (usScoped) {
|
|
45823
45944
|
chosen = { ...inState, layer: "us-state" };
|
|
45824
45945
|
} else {
|
|
@@ -45826,7 +45947,7 @@ function resolveMap(parsed, data) {
|
|
|
45826
45947
|
}
|
|
45827
45948
|
warn(
|
|
45828
45949
|
r.lineNumber,
|
|
45829
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}).`,
|
|
45950
|
+
`"${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}").`,
|
|
45830
45951
|
"W_MAP_REGION_AMBIGUOUS"
|
|
45831
45952
|
);
|
|
45832
45953
|
} else if (inState) {
|
|
@@ -45998,9 +46119,17 @@ function resolveMap(parsed, data) {
|
|
|
45998
46119
|
};
|
|
45999
46120
|
registerPoi(id, poi, p.lineNumber);
|
|
46000
46121
|
}
|
|
46122
|
+
const declaredByName = /* @__PURE__ */ new Map();
|
|
46123
|
+
for (const p of pois) {
|
|
46124
|
+
const fn = p.name ? fold(p.name) : void 0;
|
|
46125
|
+
if (fn && fn !== p.id && !declaredByName.has(fn))
|
|
46126
|
+
declaredByName.set(fn, p.id);
|
|
46127
|
+
}
|
|
46001
46128
|
const resolveEndpoint2 = (ref, line12) => {
|
|
46002
46129
|
const f = fold(ref);
|
|
46003
46130
|
if (registry.has(f)) return f;
|
|
46131
|
+
const aliased = declaredByName.get(f);
|
|
46132
|
+
if (aliased) return aliased;
|
|
46004
46133
|
const got = lookupName(ref, void 0, line12, inferredCountry, true);
|
|
46005
46134
|
if (got.kind !== "ok") return null;
|
|
46006
46135
|
noteCountry(got.iso);
|
|
@@ -46080,23 +46209,29 @@ function resolveMap(parsed, data) {
|
|
|
46080
46209
|
[-180, -85],
|
|
46081
46210
|
[180, 85]
|
|
46082
46211
|
];
|
|
46083
|
-
|
|
46212
|
+
let extent2 = unioned ? pad(unioned, PAD_FRACTION) : DEFAULT_EXTENT;
|
|
46084
46213
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46085
46214
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46086
46215
|
const span = Math.max(lonSpan, latSpan);
|
|
46087
46216
|
const usDominant = (inferredCountry === "US" || subdivisions.includes("us-states")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
46088
46217
|
let projection;
|
|
46089
46218
|
const override = parsed.directives.projection;
|
|
46090
|
-
if (override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
46219
|
+
if (override === "equirectangular" || override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
46091
46220
|
projection = override;
|
|
46092
46221
|
} else if (usDominant) {
|
|
46093
46222
|
projection = "albers-usa";
|
|
46094
46223
|
} else if (span > WORLD_SPAN) {
|
|
46095
|
-
projection = "
|
|
46224
|
+
projection = "equirectangular";
|
|
46096
46225
|
} else if (span < MERCATOR_MAX_SPAN) {
|
|
46097
46226
|
projection = "mercator";
|
|
46098
46227
|
} else {
|
|
46099
|
-
projection = "
|
|
46228
|
+
projection = "equirectangular";
|
|
46229
|
+
}
|
|
46230
|
+
if (lonSpan >= 180) {
|
|
46231
|
+
extent2 = [
|
|
46232
|
+
[-180, Math.min(extent2[0][1], WORLD_LAT_SOUTH)],
|
|
46233
|
+
[180, Math.max(extent2[1][1], WORLD_LAT_NORTH)]
|
|
46234
|
+
];
|
|
46100
46235
|
}
|
|
46101
46236
|
result.regions = regions;
|
|
46102
46237
|
result.pois = pois;
|
|
@@ -46144,7 +46279,7 @@ function firstError(diags) {
|
|
|
46144
46279
|
const e = diags.find((d) => d.severity === "error");
|
|
46145
46280
|
return e ? formatDgmoError(e) : null;
|
|
46146
46281
|
}
|
|
46147
|
-
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, REGION_ALIASES;
|
|
46282
|
+
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES;
|
|
46148
46283
|
var init_resolver2 = __esm({
|
|
46149
46284
|
"src/map/resolver.ts"() {
|
|
46150
46285
|
"use strict";
|
|
@@ -46153,6 +46288,8 @@ var init_resolver2 = __esm({
|
|
|
46153
46288
|
WORLD_SPAN = 90;
|
|
46154
46289
|
MERCATOR_MAX_SPAN = 25;
|
|
46155
46290
|
PAD_FRACTION = 0.05;
|
|
46291
|
+
WORLD_LAT_SOUTH = -58;
|
|
46292
|
+
WORLD_LAT_NORTH = 78;
|
|
46156
46293
|
REGION_ALIASES = {
|
|
46157
46294
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46158
46295
|
"united states": "united states of america",
|
|
@@ -46220,13 +46357,36 @@ function moduleBaseDir() {
|
|
|
46220
46357
|
function loadMapData() {
|
|
46221
46358
|
cache ??= (async () => {
|
|
46222
46359
|
const dir = await firstExistingDir(moduleBaseDir());
|
|
46223
|
-
const [
|
|
46360
|
+
const [
|
|
46361
|
+
worldCoarse,
|
|
46362
|
+
worldDetail,
|
|
46363
|
+
usStates,
|
|
46364
|
+
lakes,
|
|
46365
|
+
rivers,
|
|
46366
|
+
naLand,
|
|
46367
|
+
naLakes,
|
|
46368
|
+
gazetteer
|
|
46369
|
+
] = await Promise.all([
|
|
46224
46370
|
readJson(dir, FILES.worldCoarse),
|
|
46225
46371
|
readJson(dir, FILES.worldDetail),
|
|
46226
46372
|
readJson(dir, FILES.usStates),
|
|
46373
|
+
// Lakes/rivers/NA assets are optional — older bundles may predate them.
|
|
46374
|
+
readJson(dir, FILES.lakes).catch(() => void 0),
|
|
46375
|
+
readJson(dir, FILES.rivers).catch(() => void 0),
|
|
46376
|
+
readJson(dir, FILES.naLand).catch(() => void 0),
|
|
46377
|
+
readJson(dir, FILES.naLakes).catch(() => void 0),
|
|
46227
46378
|
readJson(dir, FILES.gazetteer)
|
|
46228
46379
|
]);
|
|
46229
|
-
return validate({
|
|
46380
|
+
return validate({
|
|
46381
|
+
worldCoarse,
|
|
46382
|
+
worldDetail,
|
|
46383
|
+
usStates,
|
|
46384
|
+
gazetteer,
|
|
46385
|
+
...lakes && { lakes },
|
|
46386
|
+
...rivers && { rivers },
|
|
46387
|
+
...naLand && { naLand },
|
|
46388
|
+
...naLakes && { naLakes }
|
|
46389
|
+
});
|
|
46230
46390
|
})().catch((e) => {
|
|
46231
46391
|
cache = void 0;
|
|
46232
46392
|
throw e;
|
|
@@ -46241,6 +46401,10 @@ var init_load_data = __esm({
|
|
|
46241
46401
|
worldCoarse: "world-coarse.json",
|
|
46242
46402
|
worldDetail: "world-detail.json",
|
|
46243
46403
|
usStates: "us-states.json",
|
|
46404
|
+
lakes: "lakes.json",
|
|
46405
|
+
rivers: "rivers.json",
|
|
46406
|
+
naLand: "na-land.json",
|
|
46407
|
+
naLakes: "na-lakes.json",
|
|
46244
46408
|
gazetteer: "gazetteer.json"
|
|
46245
46409
|
};
|
|
46246
46410
|
CANDIDATE_DIRS = [
|
|
@@ -46256,8 +46420,11 @@ var init_load_data = __esm({
|
|
|
46256
46420
|
import {
|
|
46257
46421
|
geoPath,
|
|
46258
46422
|
geoNaturalEarth1,
|
|
46259
|
-
|
|
46260
|
-
|
|
46423
|
+
geoEquirectangular,
|
|
46424
|
+
geoConicEqualArea,
|
|
46425
|
+
geoMercator,
|
|
46426
|
+
geoBounds as geoBounds2,
|
|
46427
|
+
geoTransform
|
|
46261
46428
|
} from "d3-geo";
|
|
46262
46429
|
import { feature as feature2 } from "topojson-client";
|
|
46263
46430
|
function geomObject2(topo) {
|
|
@@ -46275,36 +46442,74 @@ function decodeLayer(topo) {
|
|
|
46275
46442
|
function projectionFor(family) {
|
|
46276
46443
|
switch (family) {
|
|
46277
46444
|
case "albers-usa":
|
|
46278
|
-
return
|
|
46445
|
+
return usConusProjection();
|
|
46279
46446
|
case "mercator":
|
|
46280
46447
|
return geoMercator();
|
|
46281
46448
|
case "natural-earth":
|
|
46282
|
-
default:
|
|
46283
46449
|
return geoNaturalEarth1();
|
|
46450
|
+
case "equirectangular":
|
|
46451
|
+
default:
|
|
46452
|
+
return geoEquirectangular();
|
|
46284
46453
|
}
|
|
46285
46454
|
}
|
|
46455
|
+
function mapBackgroundColor(palette) {
|
|
46456
|
+
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
46457
|
+
}
|
|
46458
|
+
function mapNeutralLandColor(palette, isDark) {
|
|
46459
|
+
return mix(
|
|
46460
|
+
palette.colors.green,
|
|
46461
|
+
palette.bg,
|
|
46462
|
+
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46463
|
+
);
|
|
46464
|
+
}
|
|
46286
46465
|
function layoutMap(resolved, data, size, opts) {
|
|
46287
46466
|
const { palette, isDark } = opts;
|
|
46288
46467
|
const { width, height } = size;
|
|
46289
|
-
const
|
|
46468
|
+
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46469
|
+
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
46470
|
+
const worldTopo = usCrisp ? data.naLand : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46290
46471
|
const worldLayer = decodeLayer(worldTopo);
|
|
46291
|
-
const usLayer =
|
|
46292
|
-
const
|
|
46293
|
-
const
|
|
46472
|
+
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
46473
|
+
const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
|
|
46474
|
+
const neutralFill = mix(palette.colors.green, palette.bg, landTint);
|
|
46475
|
+
const water = mapBackgroundColor(palette);
|
|
46476
|
+
const usContext = usLayer !== null;
|
|
46477
|
+
const foreignFill = mix(
|
|
46478
|
+
palette.colors.gray,
|
|
46479
|
+
palette.bg,
|
|
46480
|
+
isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46481
|
+
);
|
|
46482
|
+
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46294
46483
|
const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
|
|
46295
46484
|
const scaleOverride = resolved.directives.scale;
|
|
46296
46485
|
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
|
|
46297
46486
|
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
|
|
46298
|
-
const rampHue = palette.
|
|
46487
|
+
const rampHue = palette.colors.red;
|
|
46299
46488
|
const hasRamp = scores.length > 0;
|
|
46300
|
-
const
|
|
46301
|
-
|
|
46302
|
-
|
|
46303
|
-
|
|
46489
|
+
const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
|
|
46490
|
+
const matchColorGroup = (v) => {
|
|
46491
|
+
const lv = v.trim().toLowerCase();
|
|
46492
|
+
if (lv === "none") return null;
|
|
46493
|
+
if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
|
|
46494
|
+
return SCORE_NAME;
|
|
46495
|
+
const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
46496
|
+
return tg ? tg.name : v;
|
|
46497
|
+
};
|
|
46498
|
+
const override = opts.activeGroup;
|
|
46499
|
+
let activeGroup;
|
|
46500
|
+
if (override !== void 0) {
|
|
46501
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
46502
|
+
} else if (resolved.directives.activeTag !== void 0) {
|
|
46503
|
+
activeGroup = matchColorGroup(resolved.directives.activeTag);
|
|
46504
|
+
} else {
|
|
46505
|
+
activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46506
|
+
}
|
|
46507
|
+
const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
|
|
46508
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46304
46509
|
const fillForScore = (s) => {
|
|
46305
46510
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
46306
46511
|
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
46307
|
-
return mix(rampHue,
|
|
46512
|
+
return mix(rampHue, rampBase, pct);
|
|
46308
46513
|
};
|
|
46309
46514
|
const tagFill = (tags, groupName) => {
|
|
46310
46515
|
if (!groupName) return null;
|
|
@@ -46318,40 +46523,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46318
46523
|
(e) => e.value.toLowerCase() === val.toLowerCase()
|
|
46319
46524
|
);
|
|
46320
46525
|
if (!entry?.color) return null;
|
|
46321
|
-
return
|
|
46526
|
+
return mix(
|
|
46527
|
+
entry.color,
|
|
46528
|
+
palette.bg,
|
|
46529
|
+
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46530
|
+
);
|
|
46531
|
+
};
|
|
46532
|
+
const regionFill = (r) => {
|
|
46533
|
+
if (activeIsScore) {
|
|
46534
|
+
return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
|
|
46535
|
+
}
|
|
46536
|
+
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46322
46537
|
};
|
|
46323
46538
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46324
|
-
const
|
|
46325
|
-
for (const r of resolved.regions) {
|
|
46326
|
-
const f = r.layer === "us-state" ? usLayer?.get(r.iso) : worldLayer.get(r.iso);
|
|
46327
|
-
if (f) regionFeatures.push(f);
|
|
46328
|
-
}
|
|
46329
|
-
const extentCorners = () => {
|
|
46539
|
+
const extentOutline = () => {
|
|
46330
46540
|
const [[w, s], [e, n]] = resolved.extent;
|
|
46541
|
+
const N = 16;
|
|
46542
|
+
const coords = [];
|
|
46543
|
+
for (let i = 0; i <= N; i++) {
|
|
46544
|
+
const t = i / N;
|
|
46545
|
+
const lon = w + (e - w) * t;
|
|
46546
|
+
const lat = s + (n - s) * t;
|
|
46547
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46548
|
+
}
|
|
46331
46549
|
return {
|
|
46332
46550
|
type: "Feature",
|
|
46333
46551
|
properties: {},
|
|
46334
|
-
geometry: {
|
|
46335
|
-
type: "MultiPoint",
|
|
46336
|
-
coordinates: [
|
|
46337
|
-
[w, s],
|
|
46338
|
-
[e, s],
|
|
46339
|
-
[e, n],
|
|
46340
|
-
[w, n]
|
|
46341
|
-
]
|
|
46342
|
-
}
|
|
46552
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46343
46553
|
};
|
|
46344
46554
|
};
|
|
46345
46555
|
let fitFeatures;
|
|
46346
|
-
if (resolved.projection === "albers-usa") {
|
|
46347
|
-
|
|
46348
|
-
else if (usLayer) fitFeatures = [...usLayer.values()];
|
|
46349
|
-
else {
|
|
46350
|
-
const us = worldLayer.get("US");
|
|
46351
|
-
fitFeatures = us ? [us] : [...worldLayer.values()];
|
|
46352
|
-
}
|
|
46556
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46557
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46353
46558
|
} else {
|
|
46354
|
-
fitFeatures = [
|
|
46559
|
+
fitFeatures = [extentOutline()];
|
|
46355
46560
|
}
|
|
46356
46561
|
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46357
46562
|
const projection = projectionFor(resolved.projection);
|
|
@@ -46360,32 +46565,311 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46360
46565
|
if (centerLon > 180) centerLon -= 360;
|
|
46361
46566
|
projection.rotate([-centerLon, 0]);
|
|
46362
46567
|
}
|
|
46363
|
-
|
|
46568
|
+
const TITLE_GAP = 16;
|
|
46569
|
+
let topPad = FIT_PAD;
|
|
46570
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
46571
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46572
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP);
|
|
46573
|
+
}
|
|
46574
|
+
const fitBox = [
|
|
46575
|
+
[FIT_PAD, topPad],
|
|
46364
46576
|
[
|
|
46365
|
-
|
|
46366
|
-
|
|
46367
|
-
|
|
46368
|
-
|
|
46369
|
-
|
|
46370
|
-
|
|
46371
|
-
|
|
46372
|
-
|
|
46373
|
-
|
|
46374
|
-
|
|
46577
|
+
Math.max(FIT_PAD + 1, width - FIT_PAD),
|
|
46578
|
+
Math.max(topPad + 1, height - FIT_PAD)
|
|
46579
|
+
]
|
|
46580
|
+
];
|
|
46581
|
+
projection.fitExtent(fitBox, fitTarget);
|
|
46582
|
+
const fitGB = geoBounds2(fitTarget);
|
|
46583
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46584
|
+
let path;
|
|
46585
|
+
let project;
|
|
46586
|
+
if (fitIsGlobal) {
|
|
46587
|
+
const cb = geoPath(projection).bounds(fitTarget);
|
|
46588
|
+
const bx0 = cb[0][0];
|
|
46589
|
+
const by0 = cb[0][1];
|
|
46590
|
+
const cw = cb[1][0] - bx0;
|
|
46591
|
+
const ch = cb[1][1] - by0;
|
|
46592
|
+
const ox = fitBox[0][0];
|
|
46593
|
+
const oy = fitBox[0][1];
|
|
46594
|
+
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46595
|
+
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
46596
|
+
const stretch = (x, y) => [
|
|
46597
|
+
ox + (x - bx0) * sx,
|
|
46598
|
+
oy + (y - by0) * sy
|
|
46599
|
+
];
|
|
46600
|
+
const baseProjection = projection;
|
|
46601
|
+
const tx = geoTransform({
|
|
46602
|
+
point(x, y) {
|
|
46603
|
+
const [px, py] = stretch(x, y);
|
|
46604
|
+
this.stream.point(px, py);
|
|
46605
|
+
}
|
|
46606
|
+
});
|
|
46607
|
+
path = geoPath({
|
|
46608
|
+
stream: (s) => baseProjection.stream(
|
|
46609
|
+
tx.stream(s)
|
|
46610
|
+
)
|
|
46611
|
+
});
|
|
46612
|
+
project = (lon, lat) => {
|
|
46613
|
+
const p = baseProjection([lon, lat]);
|
|
46614
|
+
return p ? stretch(p[0], p[1]) : null;
|
|
46615
|
+
};
|
|
46616
|
+
} else {
|
|
46617
|
+
path = geoPath(projection);
|
|
46618
|
+
project = (lon, lat) => projection([lon, lat]) ?? null;
|
|
46619
|
+
}
|
|
46620
|
+
const insets = [];
|
|
46621
|
+
const insetRegions = [];
|
|
46622
|
+
const insetLabelSeeds = [];
|
|
46623
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46624
|
+
const PAD = 8;
|
|
46625
|
+
const GAP = 12;
|
|
46626
|
+
const yB = height - FIT_PAD;
|
|
46627
|
+
const BW = 8;
|
|
46628
|
+
const coast = /* @__PURE__ */ new Map();
|
|
46629
|
+
const addPt = (lon, lat) => {
|
|
46630
|
+
const p = projection([lon, lat]);
|
|
46631
|
+
if (!p) return;
|
|
46632
|
+
const bi = Math.floor(p[0] / BW);
|
|
46633
|
+
const cur = coast.get(bi);
|
|
46634
|
+
if (cur === void 0 || p[1] > cur) coast.set(bi, p[1]);
|
|
46635
|
+
};
|
|
46636
|
+
const walk = (co) => {
|
|
46637
|
+
if (Array.isArray(co) && typeof co[0] === "number")
|
|
46638
|
+
addPt(co[0], co[1]);
|
|
46639
|
+
else if (Array.isArray(co)) for (const c of co) walk(c);
|
|
46640
|
+
};
|
|
46641
|
+
for (const [iso, f] of usLayer) {
|
|
46642
|
+
if (US_NON_CONUS.has(iso)) continue;
|
|
46643
|
+
walk(f.geometry.coordinates);
|
|
46644
|
+
}
|
|
46645
|
+
const at = (x) => {
|
|
46646
|
+
const bi = Math.floor(x / BW);
|
|
46647
|
+
let y = -Infinity;
|
|
46648
|
+
for (let k = bi - 1; k <= bi + 1; k++) {
|
|
46649
|
+
const v = coast.get(k);
|
|
46650
|
+
if (v !== void 0 && v > y) y = v;
|
|
46651
|
+
}
|
|
46652
|
+
return y;
|
|
46653
|
+
};
|
|
46654
|
+
const coastTop = (x0, xr) => {
|
|
46655
|
+
const n = 24;
|
|
46656
|
+
const pts = [];
|
|
46657
|
+
let maxY = -Infinity;
|
|
46658
|
+
for (let i = 0; i <= n; i++) {
|
|
46659
|
+
const x = x0 + (xr - x0) * i / n;
|
|
46660
|
+
const y = at(x);
|
|
46661
|
+
if (y > -Infinity) {
|
|
46662
|
+
pts.push([x, y]);
|
|
46663
|
+
if (y > maxY) maxY = y;
|
|
46664
|
+
}
|
|
46665
|
+
}
|
|
46666
|
+
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46667
|
+
let m = 0;
|
|
46668
|
+
if (pts.length >= 2) {
|
|
46669
|
+
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46670
|
+
for (const [x, y] of pts) {
|
|
46671
|
+
sx += x;
|
|
46672
|
+
sy += y;
|
|
46673
|
+
sxx += x * x;
|
|
46674
|
+
sxy += x * y;
|
|
46675
|
+
}
|
|
46676
|
+
const den = pts.length * sxx - sx * sx;
|
|
46677
|
+
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46678
|
+
}
|
|
46679
|
+
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46680
|
+
let c = -Infinity;
|
|
46681
|
+
for (const [x, y] of pts) {
|
|
46682
|
+
const need = y - m * x + GAP;
|
|
46683
|
+
if (need > c) c = need;
|
|
46684
|
+
}
|
|
46685
|
+
return (x) => m * x + c;
|
|
46686
|
+
};
|
|
46687
|
+
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46688
|
+
const f = usLayer.get(iso);
|
|
46689
|
+
if (!f) return boxX;
|
|
46690
|
+
const x0 = boxX;
|
|
46691
|
+
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46692
|
+
if (iw < 24) return boxX;
|
|
46693
|
+
const xr = x0 + iw + 2 * PAD;
|
|
46694
|
+
const top = coastTop(x0, xr);
|
|
46695
|
+
const yL = top(x0);
|
|
46696
|
+
const yR = top(xr);
|
|
46697
|
+
proj.fitWidth(iw, f);
|
|
46698
|
+
const bb = geoPath(proj).bounds(f);
|
|
46699
|
+
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46700
|
+
const needH = sh + 2 * PAD;
|
|
46701
|
+
let topFit = Math.max(yL, yR);
|
|
46702
|
+
const bottom = Math.min(topFit + needH, yB);
|
|
46703
|
+
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46704
|
+
const lift = topFit - Math.max(yL, yR);
|
|
46705
|
+
const topL = yL + lift;
|
|
46706
|
+
const topR = yR + lift;
|
|
46707
|
+
proj.fitExtent(
|
|
46708
|
+
[
|
|
46709
|
+
[x0 + PAD, topFit + PAD],
|
|
46710
|
+
[xr - PAD, bottom - PAD]
|
|
46711
|
+
],
|
|
46712
|
+
f
|
|
46713
|
+
);
|
|
46714
|
+
const d = geoPath(proj)(f) ?? "";
|
|
46715
|
+
if (!d) return xr;
|
|
46716
|
+
const r = regionById.get(iso);
|
|
46717
|
+
let fill2 = neutralFill;
|
|
46718
|
+
let lineNumber = -1;
|
|
46719
|
+
if (r?.layer === "us-state") {
|
|
46720
|
+
fill2 = regionFill(r);
|
|
46721
|
+
lineNumber = r.lineNumber;
|
|
46722
|
+
}
|
|
46723
|
+
insets.push({
|
|
46724
|
+
x: x0,
|
|
46725
|
+
y: Math.min(topL, topR),
|
|
46726
|
+
w: xr - x0,
|
|
46727
|
+
h: bottom - Math.min(topL, topR),
|
|
46728
|
+
points: [
|
|
46729
|
+
[x0, topL],
|
|
46730
|
+
[xr, topR],
|
|
46731
|
+
[xr, bottom],
|
|
46732
|
+
[x0, bottom]
|
|
46733
|
+
]
|
|
46734
|
+
});
|
|
46735
|
+
insetRegions.push({
|
|
46736
|
+
id: iso,
|
|
46737
|
+
d,
|
|
46738
|
+
fill: fill2,
|
|
46739
|
+
stroke: regionStroke,
|
|
46740
|
+
lineNumber,
|
|
46741
|
+
layer: "us-state",
|
|
46742
|
+
...r?.score !== void 0 && { score: r.score },
|
|
46743
|
+
...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46744
|
+
});
|
|
46745
|
+
const ctr = geoPath(proj).centroid(f);
|
|
46746
|
+
if (Number.isFinite(ctr[0])) {
|
|
46747
|
+
const name = f.properties?.name ?? iso;
|
|
46748
|
+
insetLabelSeeds.push({ x: ctr[0], y: ctr[1], iso, name, lineNumber });
|
|
46749
|
+
}
|
|
46750
|
+
return xr;
|
|
46751
|
+
};
|
|
46752
|
+
const akRight = placeInset(
|
|
46753
|
+
"US-AK",
|
|
46754
|
+
alaskaProjection(),
|
|
46755
|
+
FIT_PAD,
|
|
46756
|
+
width * 0.15
|
|
46757
|
+
);
|
|
46758
|
+
placeInset("US-HI", hawaiiProjection(), akRight + 24, width * 0.1);
|
|
46759
|
+
}
|
|
46760
|
+
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46761
|
+
const cullExtent = conusFit ? geoBounds2(fitTarget) : resolved.extent;
|
|
46762
|
+
const [[exW, exS], [exE, exN]] = cullExtent;
|
|
46763
|
+
const lonSpan = exE - exW;
|
|
46764
|
+
const latSpan = exN - exS;
|
|
46765
|
+
const isGlobalView = lonSpan >= 270 || latSpan >= 130;
|
|
46766
|
+
const padLon = Math.max(8, lonSpan * 0.35);
|
|
46767
|
+
const padLat = Math.max(8, latSpan * 0.35);
|
|
46768
|
+
const vW = exW - padLon;
|
|
46769
|
+
const vE = exE + padLon;
|
|
46770
|
+
const vS = exS - padLat;
|
|
46771
|
+
const vN = exN + padLat;
|
|
46772
|
+
const vLonCenter = (exW + exE) / 2;
|
|
46773
|
+
const normLon = (lon) => {
|
|
46774
|
+
let L = lon;
|
|
46775
|
+
while (L < vLonCenter - 180) L += 360;
|
|
46776
|
+
while (L > vLonCenter + 180) L -= 360;
|
|
46777
|
+
return L;
|
|
46778
|
+
};
|
|
46779
|
+
const ringOverlapsView = (ring) => {
|
|
46780
|
+
let anyIn = false;
|
|
46781
|
+
let loMin = Infinity, loMax = -Infinity, laMin = Infinity, laMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
46782
|
+
for (const [rawLon, lat] of ring) {
|
|
46783
|
+
const lon = normLon(rawLon);
|
|
46784
|
+
if (lon >= vW && lon <= vE && lat >= vS && lat <= vN) anyIn = true;
|
|
46785
|
+
if (lon < loMin) loMin = lon;
|
|
46786
|
+
if (lon > loMax) loMax = lon;
|
|
46787
|
+
if (rawLon < rawMin) rawMin = rawLon;
|
|
46788
|
+
if (rawLon > rawMax) rawMax = rawLon;
|
|
46789
|
+
if (lat < laMin) laMin = lat;
|
|
46790
|
+
if (lat > laMax) laMax = lat;
|
|
46791
|
+
}
|
|
46792
|
+
if (loMax - loMin > 270) return false;
|
|
46793
|
+
if (rawMax - rawMin > 180 && loMax - loMin < 90) return false;
|
|
46794
|
+
if (anyIn) return true;
|
|
46795
|
+
if (loMax - loMin > 180) return false;
|
|
46796
|
+
return !(loMax < vW || loMin > vE || laMax < vS || laMin > vN);
|
|
46797
|
+
};
|
|
46798
|
+
const cullFeatureToView = (f) => {
|
|
46799
|
+
if (isGlobalView) return f;
|
|
46800
|
+
const g = f.geometry;
|
|
46801
|
+
if (!g) return f;
|
|
46802
|
+
if (g.type === "Polygon") {
|
|
46803
|
+
const ring = g.coordinates[0];
|
|
46804
|
+
return ringOverlapsView(ring) ? f : null;
|
|
46805
|
+
}
|
|
46806
|
+
if (g.type === "MultiPolygon") {
|
|
46807
|
+
const polys = g.coordinates;
|
|
46808
|
+
const keep = polys.filter(
|
|
46809
|
+
(p) => ringOverlapsView(p[0])
|
|
46810
|
+
);
|
|
46811
|
+
if (!keep.length) return null;
|
|
46812
|
+
if (keep.length === polys.length) return f;
|
|
46813
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46814
|
+
}
|
|
46815
|
+
return f;
|
|
46816
|
+
};
|
|
46817
|
+
const SEAM_SLIVER_MAX_SPAN = 100;
|
|
46818
|
+
const ringIsFrameFiller = (ring) => {
|
|
46819
|
+
const lons = ring.map(([lon]) => lon).sort((a, b) => a - b);
|
|
46820
|
+
if (lons.length < 2) return false;
|
|
46821
|
+
let maxGap = -1;
|
|
46822
|
+
let gapIdx = 0;
|
|
46823
|
+
for (let i = 1; i < lons.length; i++) {
|
|
46824
|
+
const g = lons[i] - lons[i - 1];
|
|
46825
|
+
if (g > maxGap) {
|
|
46826
|
+
maxGap = g;
|
|
46827
|
+
gapIdx = i;
|
|
46828
|
+
}
|
|
46829
|
+
}
|
|
46830
|
+
const wrapGap = lons[0] + 360 - lons[lons.length - 1];
|
|
46831
|
+
if (wrapGap >= maxGap) return false;
|
|
46832
|
+
const span = 360 - maxGap;
|
|
46833
|
+
const east = lons[gapIdx - 1] + 360;
|
|
46834
|
+
return east > 180 && span < SEAM_SLIVER_MAX_SPAN;
|
|
46835
|
+
};
|
|
46836
|
+
const dropFrameFillers = (f) => {
|
|
46837
|
+
const g = f.geometry;
|
|
46838
|
+
if (!g) return f;
|
|
46839
|
+
if (g.type === "Polygon") {
|
|
46840
|
+
const ring = g.coordinates[0];
|
|
46841
|
+
return ringIsFrameFiller(ring) ? null : f;
|
|
46842
|
+
}
|
|
46843
|
+
if (g.type === "MultiPolygon") {
|
|
46844
|
+
const polys = g.coordinates;
|
|
46845
|
+
const keep = polys.filter(
|
|
46846
|
+
(p) => !ringIsFrameFiller(p[0])
|
|
46847
|
+
);
|
|
46848
|
+
if (!keep.length) return null;
|
|
46849
|
+
if (keep.length === polys.length) return f;
|
|
46850
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46851
|
+
}
|
|
46852
|
+
return f;
|
|
46853
|
+
};
|
|
46375
46854
|
const regions = [];
|
|
46376
|
-
const pushRegionLayer = (layerFeatures, layerKind) => {
|
|
46855
|
+
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46377
46856
|
for (const [iso, f] of layerFeatures) {
|
|
46378
|
-
|
|
46379
|
-
|
|
46857
|
+
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
46858
|
+
continue;
|
|
46859
|
+
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46380
46860
|
const r = regionById.get(iso);
|
|
46861
|
+
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
46862
|
+
if (!viewF) continue;
|
|
46863
|
+
const d = path(viewF) ?? "";
|
|
46864
|
+
if (!d) continue;
|
|
46381
46865
|
const isThisLayer = r?.layer === layerKind;
|
|
46382
|
-
|
|
46866
|
+
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46867
|
+
let fill2 = isForeign ? foreignFill : neutralFill;
|
|
46383
46868
|
let label;
|
|
46384
46869
|
let lineNumber = -1;
|
|
46385
46870
|
let layer = "base";
|
|
46386
46871
|
if (isThisLayer) {
|
|
46387
|
-
|
|
46388
|
-
else fill2 = tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46872
|
+
fill2 = regionFill(r);
|
|
46389
46873
|
lineNumber = r.lineNumber;
|
|
46390
46874
|
layer = layerKind;
|
|
46391
46875
|
label = r.name;
|
|
@@ -46397,12 +46881,42 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46397
46881
|
stroke: regionStroke,
|
|
46398
46882
|
lineNumber,
|
|
46399
46883
|
layer,
|
|
46400
|
-
...label !== void 0 && { label }
|
|
46884
|
+
...label !== void 0 && { label },
|
|
46885
|
+
...isThisLayer && r.score !== void 0 && { score: r.score },
|
|
46886
|
+
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46401
46887
|
});
|
|
46402
46888
|
}
|
|
46403
46889
|
};
|
|
46404
|
-
pushRegionLayer(worldLayer, "country");
|
|
46405
|
-
if (usLayer) pushRegionLayer(usLayer, "us-state");
|
|
46890
|
+
pushRegionLayer(worldLayer, "country", !isGlobalView);
|
|
46891
|
+
if (usLayer) pushRegionLayer(usLayer, "us-state", !conusFit && !isGlobalView);
|
|
46892
|
+
const lakesTopo = usCrisp && data.naLakes ? data.naLakes : data.lakes;
|
|
46893
|
+
if (lakesTopo) {
|
|
46894
|
+
for (const [, f] of decodeLayer(lakesTopo)) {
|
|
46895
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46896
|
+
if (!viewF) continue;
|
|
46897
|
+
const d = path(viewF) ?? "";
|
|
46898
|
+
if (!d) continue;
|
|
46899
|
+
regions.push({
|
|
46900
|
+
id: "lake",
|
|
46901
|
+
d,
|
|
46902
|
+
fill: water,
|
|
46903
|
+
stroke: "none",
|
|
46904
|
+
lineNumber: -1,
|
|
46905
|
+
layer: "base"
|
|
46906
|
+
});
|
|
46907
|
+
}
|
|
46908
|
+
}
|
|
46909
|
+
const riverColor = water;
|
|
46910
|
+
const rivers = [];
|
|
46911
|
+
if (data.rivers) {
|
|
46912
|
+
for (const [, f] of decodeLayer(data.rivers)) {
|
|
46913
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46914
|
+
if (!viewF) continue;
|
|
46915
|
+
const d = path(viewF) ?? "";
|
|
46916
|
+
if (!d) continue;
|
|
46917
|
+
rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
|
|
46918
|
+
}
|
|
46919
|
+
}
|
|
46406
46920
|
const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
46407
46921
|
const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
|
|
46408
46922
|
const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
|
|
@@ -46423,8 +46937,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46423
46937
|
if (hex) return { fill: hex, stroke: mix(hex, palette.text, 18) };
|
|
46424
46938
|
}
|
|
46425
46939
|
return {
|
|
46426
|
-
fill: palette.
|
|
46427
|
-
stroke: mix(palette.
|
|
46940
|
+
fill: palette.colors.orange,
|
|
46941
|
+
stroke: mix(palette.colors.orange, palette.text, 18)
|
|
46428
46942
|
};
|
|
46429
46943
|
};
|
|
46430
46944
|
const routeNumberById = /* @__PURE__ */ new Map();
|
|
@@ -46462,7 +46976,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46462
46976
|
cy += Math.sin(ang) * COLO_R;
|
|
46463
46977
|
}
|
|
46464
46978
|
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
46465
|
-
poiScreen.set(e.p.id, { cx, cy });
|
|
46979
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
46466
46980
|
const num = routeNumberById.get(e.p.id);
|
|
46467
46981
|
pois.push({
|
|
46468
46982
|
id: e.p.id,
|
|
@@ -46479,17 +46993,36 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46479
46993
|
});
|
|
46480
46994
|
}
|
|
46481
46995
|
const legs = [];
|
|
46996
|
+
const RIM_GAP = 1.5;
|
|
46482
46997
|
const legPath = (a, b, curved, offset) => {
|
|
46483
|
-
if (!curved && offset === 0) return `M${a.cx},${a.cy}L${b.cx},${b.cy}`;
|
|
46484
46998
|
const mx = (a.cx + b.cx) / 2;
|
|
46485
46999
|
const my = (a.cy + b.cy) / 2;
|
|
46486
47000
|
const dx = b.cx - a.cx;
|
|
46487
47001
|
const dy = b.cy - a.cy;
|
|
46488
47002
|
const len = Math.hypot(dx, dy) || 1;
|
|
47003
|
+
const trimA = Math.min(a.r + RIM_GAP, len * 0.45);
|
|
47004
|
+
const trimB = Math.min(b.r + RIM_GAP, len * 0.45);
|
|
47005
|
+
if (!curved && offset === 0) {
|
|
47006
|
+
const ux = dx / len;
|
|
47007
|
+
const uy = dy / len;
|
|
47008
|
+
const ax2 = a.cx + ux * trimA;
|
|
47009
|
+
const ay2 = a.cy + uy * trimA;
|
|
47010
|
+
const bx2 = b.cx - ux * trimB;
|
|
47011
|
+
const by2 = b.cy - uy * trimB;
|
|
47012
|
+
return `M${ax2},${ay2}L${bx2},${by2}`;
|
|
47013
|
+
}
|
|
46489
47014
|
const nx = -dy / len;
|
|
46490
47015
|
const ny = dx / len;
|
|
46491
47016
|
const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
|
|
46492
|
-
|
|
47017
|
+
const px = mx + nx * bow;
|
|
47018
|
+
const py = my + ny * bow;
|
|
47019
|
+
const ta = Math.hypot(px - a.cx, py - a.cy) || 1;
|
|
47020
|
+
const tb = Math.hypot(b.cx - px, b.cy - py) || 1;
|
|
47021
|
+
const ax = a.cx + (px - a.cx) / ta * trimA;
|
|
47022
|
+
const ay = a.cy + (py - a.cy) / ta * trimA;
|
|
47023
|
+
const bx = b.cx - (b.cx - px) / tb * trimB;
|
|
47024
|
+
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
47025
|
+
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
46493
47026
|
};
|
|
46494
47027
|
for (const rt of resolved.routes) {
|
|
46495
47028
|
const curved = rt.meta["style"] === "arc";
|
|
@@ -46500,7 +47033,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46500
47033
|
legs.push({
|
|
46501
47034
|
d: legPath(a, b, curved, 0),
|
|
46502
47035
|
width: W_MIN,
|
|
46503
|
-
color: mix(palette.text, palette.bg,
|
|
47036
|
+
color: mix(palette.text, palette.bg, 72),
|
|
46504
47037
|
arrow: true,
|
|
46505
47038
|
lineNumber: rt.lineNumber
|
|
46506
47039
|
});
|
|
@@ -46536,7 +47069,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46536
47069
|
legs.push({
|
|
46537
47070
|
d: legPath(a, b, curved, offset),
|
|
46538
47071
|
width: widthFor(e),
|
|
46539
|
-
color: mix(palette.text, palette.bg,
|
|
47072
|
+
color: mix(palette.text, palette.bg, 66),
|
|
46540
47073
|
arrow: e.directed,
|
|
46541
47074
|
lineNumber: e.lineNumber,
|
|
46542
47075
|
...e.label !== void 0 && {
|
|
@@ -46548,38 +47081,92 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46548
47081
|
});
|
|
46549
47082
|
}
|
|
46550
47083
|
const labels = [];
|
|
46551
|
-
const pinList = [];
|
|
46552
47084
|
const obstacles = [];
|
|
46553
47085
|
const markers = pois.map((p) => ({
|
|
46554
47086
|
cx: p.cx,
|
|
46555
47087
|
cy: p.cy,
|
|
46556
47088
|
r: p.r
|
|
46557
47089
|
}));
|
|
46558
|
-
const
|
|
47090
|
+
const legSegments = [];
|
|
47091
|
+
for (const leg of legs) {
|
|
47092
|
+
const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
47093
|
+
leg.d
|
|
47094
|
+
);
|
|
47095
|
+
if (!m) continue;
|
|
47096
|
+
const x0 = +m[1];
|
|
47097
|
+
const y0 = +m[2];
|
|
47098
|
+
if (m[3] !== void 0) {
|
|
47099
|
+
legSegments.push([x0, y0, +m[3], +m[4]]);
|
|
47100
|
+
} else {
|
|
47101
|
+
const cx = +m[5];
|
|
47102
|
+
const cy = +m[6];
|
|
47103
|
+
const ex = +m[7];
|
|
47104
|
+
const ey = +m[8];
|
|
47105
|
+
const N = 8;
|
|
47106
|
+
let px = x0;
|
|
47107
|
+
let py = y0;
|
|
47108
|
+
for (let i = 1; i <= N; i++) {
|
|
47109
|
+
const t = i / N;
|
|
47110
|
+
const u = 1 - t;
|
|
47111
|
+
const qx = u * u * x0 + 2 * u * t * cx + t * t * ex;
|
|
47112
|
+
const qy = u * u * y0 + 2 * u * t * cy + t * t * ey;
|
|
47113
|
+
legSegments.push([px, py, qx, qy]);
|
|
47114
|
+
px = qx;
|
|
47115
|
+
py = qy;
|
|
47116
|
+
}
|
|
47117
|
+
}
|
|
47118
|
+
}
|
|
47119
|
+
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));
|
|
46559
47120
|
const regionLabelMode = resolved.directives.regionLabels ?? "off";
|
|
47121
|
+
const LABEL_PADX = 6;
|
|
47122
|
+
const LABEL_PADY = 3;
|
|
47123
|
+
const labelW = (text) => measureLegendText(text, FONT) + 2 * LABEL_PADX;
|
|
47124
|
+
const labelH = FONT + 2 * LABEL_PADY;
|
|
47125
|
+
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
47126
|
+
const color = contrastText(
|
|
47127
|
+
fill2,
|
|
47128
|
+
palette.textOnFillLight,
|
|
47129
|
+
palette.textOnFillDark
|
|
47130
|
+
);
|
|
47131
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47132
|
+
labels.push({
|
|
47133
|
+
x,
|
|
47134
|
+
y,
|
|
47135
|
+
text,
|
|
47136
|
+
anchor: "middle",
|
|
47137
|
+
color,
|
|
47138
|
+
halo: true,
|
|
47139
|
+
haloColor,
|
|
47140
|
+
lineNumber
|
|
47141
|
+
});
|
|
47142
|
+
};
|
|
47143
|
+
const WORLD_LABEL_ANCHORS = {
|
|
47144
|
+
US: [-98.5, 39.5]
|
|
47145
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
47146
|
+
};
|
|
46560
47147
|
if (regionLabelMode === "full" || regionLabelMode === "abbrev") {
|
|
46561
47148
|
for (const r of regions) {
|
|
46562
47149
|
if (r.layer === "base" || r.label === void 0) continue;
|
|
46563
47150
|
const f = r.layer === "us-state" ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
46564
47151
|
if (!f) continue;
|
|
46565
47152
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
46566
|
-
if ((x1 - x0) * (y1 - y0) < TINY_REGION_AREA) continue;
|
|
46567
|
-
const c = path.centroid(f);
|
|
46568
|
-
if (!Number.isFinite(c[0])) continue;
|
|
46569
47153
|
const text = regionLabelMode === "abbrev" ? r.id.replace(/^US-/, "") : r.label;
|
|
46570
|
-
|
|
46571
|
-
|
|
46572
|
-
|
|
47154
|
+
if (labelW(text) > x1 - x0 || labelH > y1 - y0) continue;
|
|
47155
|
+
const anchor = r.layer !== "us-state" ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
47156
|
+
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47157
|
+
if (!c || !Number.isFinite(c[0])) continue;
|
|
47158
|
+
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47159
|
+
}
|
|
47160
|
+
for (const seed of insetLabelSeeds) {
|
|
47161
|
+
const text = regionLabelMode === "abbrev" ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47162
|
+
const src = regionById.get(seed.iso);
|
|
47163
|
+
pushRegionLabel(
|
|
47164
|
+
seed.x,
|
|
47165
|
+
seed.y,
|
|
46573
47166
|
text,
|
|
46574
|
-
|
|
46575
|
-
|
|
46576
|
-
|
|
46577
|
-
palette.textOnFillLight,
|
|
46578
|
-
palette.textOnFillDark
|
|
46579
|
-
),
|
|
46580
|
-
halo: true,
|
|
46581
|
-
lineNumber: r.lineNumber
|
|
46582
|
-
});
|
|
47167
|
+
src ? regionFill(src) : neutralFill,
|
|
47168
|
+
seed.lineNumber
|
|
47169
|
+
);
|
|
46583
47170
|
}
|
|
46584
47171
|
}
|
|
46585
47172
|
const poiLabelMode = resolved.directives.poiLabels ?? "auto";
|
|
@@ -46592,68 +47179,106 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46592
47179
|
const src = poiById.get(p.id);
|
|
46593
47180
|
return src?.label ?? src?.name ?? p.id;
|
|
46594
47181
|
};
|
|
46595
|
-
|
|
46596
|
-
|
|
47182
|
+
const poiLabH = FONT * 1.25;
|
|
47183
|
+
const labelInfo = (p) => {
|
|
46597
47184
|
const text = labelText(p);
|
|
46598
|
-
|
|
46599
|
-
|
|
46600
|
-
|
|
46601
|
-
|
|
46602
|
-
|
|
47185
|
+
return { text, w: measureLegendText(text, FONT) };
|
|
47186
|
+
};
|
|
47187
|
+
const pushInline = (p, text, w, side) => {
|
|
47188
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
47189
|
+
obstacles.push({
|
|
47190
|
+
x: side === "right" ? tx : tx - w,
|
|
47191
|
+
y: p.cy - poiLabH / 2,
|
|
47192
|
+
w,
|
|
47193
|
+
h: poiLabH
|
|
47194
|
+
});
|
|
47195
|
+
labels.push({
|
|
47196
|
+
x: tx,
|
|
47197
|
+
y: p.cy + FONT / 3,
|
|
47198
|
+
text,
|
|
47199
|
+
anchor: side === "right" ? "start" : "end",
|
|
47200
|
+
color: palette.text,
|
|
47201
|
+
halo: true,
|
|
47202
|
+
haloColor: palette.bg,
|
|
47203
|
+
poiId: p.id,
|
|
47204
|
+
lineNumber: p.lineNumber
|
|
47205
|
+
});
|
|
47206
|
+
};
|
|
47207
|
+
const inlineFits = (p, w, side) => {
|
|
47208
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
47209
|
+
const rect = {
|
|
47210
|
+
x: side === "right" ? tx : tx - w,
|
|
47211
|
+
y: p.cy - poiLabH / 2,
|
|
47212
|
+
w,
|
|
47213
|
+
h: poiLabH
|
|
47214
|
+
};
|
|
47215
|
+
return rect.x >= 0 && rect.x + rect.w <= width && !collides(rect);
|
|
47216
|
+
};
|
|
47217
|
+
const GROUP_R = 30;
|
|
47218
|
+
const groups = [];
|
|
47219
|
+
for (const p of ordered) {
|
|
47220
|
+
const near = groups.find(
|
|
47221
|
+
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47222
|
+
);
|
|
47223
|
+
if (near) near.push(p);
|
|
47224
|
+
else groups.push([p]);
|
|
47225
|
+
}
|
|
47226
|
+
const ROW_GAP2 = 3;
|
|
47227
|
+
const step = poiLabH + ROW_GAP2;
|
|
47228
|
+
const COL_GAP = 16;
|
|
47229
|
+
const placeColumn = (group) => {
|
|
47230
|
+
const items = group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
47231
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47232
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47233
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47234
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
47235
|
+
const side = right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
47236
|
+
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
47237
|
+
const totalH = items.length * step;
|
|
47238
|
+
let startY = cyMid - totalH / 2;
|
|
47239
|
+
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47240
|
+
items.forEach((o, i) => {
|
|
47241
|
+
const rowCy = startY + i * step + step / 2;
|
|
47242
|
+
obstacles.push({
|
|
47243
|
+
x: side === "right" ? colX : colX - o.w,
|
|
47244
|
+
y: rowCy - poiLabH / 2,
|
|
47245
|
+
w: o.w,
|
|
47246
|
+
h: poiLabH
|
|
47247
|
+
});
|
|
46603
47248
|
labels.push({
|
|
46604
|
-
x:
|
|
46605
|
-
y:
|
|
46606
|
-
text,
|
|
46607
|
-
anchor: "start",
|
|
47249
|
+
x: colX,
|
|
47250
|
+
y: rowCy + FONT / 3,
|
|
47251
|
+
text: o.text,
|
|
47252
|
+
anchor: side === "right" ? "start" : "end",
|
|
46608
47253
|
color: palette.text,
|
|
46609
47254
|
halo: true,
|
|
46610
|
-
|
|
47255
|
+
haloColor: palette.bg,
|
|
47256
|
+
leader: {
|
|
47257
|
+
x1: o.p.cx,
|
|
47258
|
+
y1: o.p.cy,
|
|
47259
|
+
x2: side === "right" ? colX - 2 : colX + 2,
|
|
47260
|
+
y2: rowCy
|
|
47261
|
+
},
|
|
47262
|
+
leaderColor: o.p.fill,
|
|
47263
|
+
poiId: o.p.id,
|
|
47264
|
+
lineNumber: o.p.lineNumber
|
|
46611
47265
|
});
|
|
46612
|
-
|
|
46613
|
-
|
|
46614
|
-
|
|
46615
|
-
|
|
46616
|
-
|
|
46617
|
-
|
|
46618
|
-
|
|
46619
|
-
|
|
46620
|
-
|
|
46621
|
-
|
|
46622
|
-
|
|
46623
|
-
|
|
46624
|
-
|
|
46625
|
-
if (rect.x < 0 || rect.x + rect.w > width || rect.y < 0 || rect.y + rect.h > height) {
|
|
46626
|
-
continue;
|
|
46627
|
-
}
|
|
46628
|
-
if (collides(rect)) continue;
|
|
46629
|
-
obstacles.push(rect);
|
|
46630
|
-
labels.push({
|
|
46631
|
-
x: cx,
|
|
46632
|
-
y: cy + FONT / 3,
|
|
46633
|
-
text,
|
|
46634
|
-
anchor: dx >= 0 ? "start" : "end",
|
|
46635
|
-
color: palette.text,
|
|
46636
|
-
halo: true,
|
|
46637
|
-
leader: { x1: p.cx, y1: p.cy, x2: cx, y2: cy },
|
|
46638
|
-
lineNumber: p.lineNumber
|
|
46639
|
-
});
|
|
46640
|
-
placed = true;
|
|
46641
|
-
break;
|
|
47266
|
+
});
|
|
47267
|
+
};
|
|
47268
|
+
for (const g of groups) {
|
|
47269
|
+
if (g.length === 1) {
|
|
47270
|
+
const p = g[0];
|
|
47271
|
+
const { text, w } = labelInfo(p);
|
|
47272
|
+
if (inlineFits(p, w, "right")) {
|
|
47273
|
+
pushInline(p, text, w, "right");
|
|
47274
|
+
continue;
|
|
47275
|
+
}
|
|
47276
|
+
if (inlineFits(p, w, "left")) {
|
|
47277
|
+
pushInline(p, text, w, "left");
|
|
47278
|
+
continue;
|
|
46642
47279
|
}
|
|
46643
47280
|
}
|
|
46644
|
-
|
|
46645
|
-
pinCounter += 1;
|
|
46646
|
-
pinList.push({ pin: pinCounter, label: text });
|
|
46647
|
-
labels.push({
|
|
46648
|
-
x: p.cx + p.r + 2,
|
|
46649
|
-
y: p.cy - p.r,
|
|
46650
|
-
text: String(pinCounter),
|
|
46651
|
-
anchor: "start",
|
|
46652
|
-
color: palette.text,
|
|
46653
|
-
halo: true,
|
|
46654
|
-
pin: pinCounter,
|
|
46655
|
-
lineNumber: p.lineNumber
|
|
46656
|
-
});
|
|
47281
|
+
placeColumn(g);
|
|
46657
47282
|
}
|
|
46658
47283
|
}
|
|
46659
47284
|
let legend = null;
|
|
@@ -46662,8 +47287,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46662
47287
|
name: g.name,
|
|
46663
47288
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
46664
47289
|
}));
|
|
46665
|
-
|
|
46666
|
-
if (hasAnything) {
|
|
47290
|
+
if (tagGroups.length > 0 || hasRamp) {
|
|
46667
47291
|
legend = {
|
|
46668
47292
|
tagGroups,
|
|
46669
47293
|
activeGroup,
|
|
@@ -46674,20 +47298,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46674
47298
|
},
|
|
46675
47299
|
min: rampMin,
|
|
46676
47300
|
max: rampMax,
|
|
46677
|
-
hue: rampHue
|
|
47301
|
+
hue: rampHue,
|
|
47302
|
+
base: rampBase
|
|
46678
47303
|
}
|
|
46679
|
-
},
|
|
46680
|
-
...sizeVals.length > 0 && {
|
|
46681
|
-
size: {
|
|
46682
|
-
...resolved.directives.sizeMetric !== void 0 && {
|
|
46683
|
-
metric: resolved.directives.sizeMetric
|
|
46684
|
-
},
|
|
46685
|
-
min: sizeMin,
|
|
46686
|
-
max: sizeMax
|
|
46687
|
-
}
|
|
46688
|
-
},
|
|
46689
|
-
...weightVals.length > 0 && {
|
|
46690
|
-
weight: { min: wMin, max: wMax }
|
|
46691
47304
|
}
|
|
46692
47305
|
};
|
|
46693
47306
|
}
|
|
@@ -46695,26 +47308,28 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46695
47308
|
return {
|
|
46696
47309
|
width,
|
|
46697
47310
|
height,
|
|
46698
|
-
background:
|
|
47311
|
+
background: water,
|
|
46699
47312
|
title: resolved.title,
|
|
46700
47313
|
...resolved.subtitle !== void 0 && { subtitle: resolved.subtitle },
|
|
46701
47314
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
46702
47315
|
regions,
|
|
47316
|
+
rivers,
|
|
46703
47317
|
legs,
|
|
46704
47318
|
pois,
|
|
46705
47319
|
labels,
|
|
46706
|
-
|
|
46707
|
-
|
|
47320
|
+
legend,
|
|
47321
|
+
insets,
|
|
47322
|
+
insetRegions
|
|
46708
47323
|
};
|
|
46709
47324
|
}
|
|
46710
|
-
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT,
|
|
47325
|
+
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT, COLO_EPS, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT, RIVER_WIDTH, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, COLO_R, GOLDEN_ANGLE, FAN_STEP, ARC_CURVE_FRAC, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, US_NON_CONUS;
|
|
46711
47326
|
var init_layout15 = __esm({
|
|
46712
47327
|
"src/map/layout.ts"() {
|
|
46713
47328
|
"use strict";
|
|
46714
47329
|
init_color_utils();
|
|
46715
|
-
init_tag_groups();
|
|
46716
47330
|
init_label_layout();
|
|
46717
47331
|
init_legend_constants();
|
|
47332
|
+
init_title_constants();
|
|
46718
47333
|
FIT_PAD = 24;
|
|
46719
47334
|
RAMP_FLOOR = 15;
|
|
46720
47335
|
R_DEFAULT = 6;
|
|
@@ -46723,23 +47338,32 @@ var init_layout15 = __esm({
|
|
|
46723
47338
|
W_MIN = 1.25;
|
|
46724
47339
|
W_MAX = 8;
|
|
46725
47340
|
FONT = 11;
|
|
46726
|
-
LEADER_STEP = 14;
|
|
46727
47341
|
COLO_EPS = 1.5;
|
|
47342
|
+
LAND_TINT_LIGHT = 58;
|
|
47343
|
+
LAND_TINT_DARK = 75;
|
|
47344
|
+
TAG_TINT_LIGHT = 60;
|
|
47345
|
+
TAG_TINT_DARK = 68;
|
|
47346
|
+
WATER_TINT = 55;
|
|
47347
|
+
RIVER_WIDTH = 1.3;
|
|
47348
|
+
FOREIGN_TINT_LIGHT = 30;
|
|
47349
|
+
FOREIGN_TINT_DARK = 62;
|
|
46728
47350
|
COLO_R = 9;
|
|
46729
47351
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
46730
47352
|
FAN_STEP = 16;
|
|
46731
|
-
TINY_REGION_AREA = 600;
|
|
46732
47353
|
ARC_CURVE_FRAC = 0.18;
|
|
46733
|
-
|
|
46734
|
-
|
|
46735
|
-
|
|
46736
|
-
|
|
46737
|
-
|
|
46738
|
-
|
|
46739
|
-
|
|
46740
|
-
|
|
46741
|
-
|
|
46742
|
-
|
|
47354
|
+
usConusProjection = () => geoConicEqualArea().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47355
|
+
alaskaProjection = () => geoConicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47356
|
+
hawaiiProjection = () => geoMercator();
|
|
47357
|
+
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
47358
|
+
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47359
|
+
"US-AK",
|
|
47360
|
+
"US-HI",
|
|
47361
|
+
"US-AS",
|
|
47362
|
+
"US-GU",
|
|
47363
|
+
"US-MP",
|
|
47364
|
+
"US-PR",
|
|
47365
|
+
"US-VI"
|
|
47366
|
+
]);
|
|
46743
47367
|
}
|
|
46744
47368
|
});
|
|
46745
47369
|
|
|
@@ -46750,7 +47374,7 @@ __export(renderer_exports16, {
|
|
|
46750
47374
|
renderMapForExport: () => renderMapForExport
|
|
46751
47375
|
});
|
|
46752
47376
|
import * as d3Selection18 from "d3-selection";
|
|
46753
|
-
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims) {
|
|
47377
|
+
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
46754
47378
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
46755
47379
|
const width = exportDims?.width ?? container.clientWidth;
|
|
46756
47380
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -46761,27 +47385,29 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46761
47385
|
{ width, height },
|
|
46762
47386
|
{
|
|
46763
47387
|
palette,
|
|
46764
|
-
isDark
|
|
47388
|
+
isDark,
|
|
47389
|
+
...activeGroupOverride !== void 0 && {
|
|
47390
|
+
activeGroup: activeGroupOverride
|
|
47391
|
+
}
|
|
46765
47392
|
}
|
|
46766
47393
|
);
|
|
46767
|
-
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);
|
|
47394
|
+
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);
|
|
46768
47395
|
svg.append("rect").attr("width", width).attr("height", height).attr("fill", layout.background);
|
|
46769
|
-
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
46770
47396
|
const defs = svg.append("defs");
|
|
46771
|
-
|
|
46772
|
-
const haloColor =
|
|
46773
|
-
if (layout.title) {
|
|
46774
|
-
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);
|
|
46775
|
-
}
|
|
46776
|
-
if (layout.subtitle) {
|
|
46777
|
-
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);
|
|
46778
|
-
}
|
|
46779
|
-
if (layout.caption) {
|
|
46780
|
-
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);
|
|
46781
|
-
}
|
|
47397
|
+
const arrowSize = (w) => Math.min(15, 7 + w * 0.95);
|
|
47398
|
+
const haloColor = palette.bg;
|
|
46782
47399
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
46783
|
-
|
|
46784
|
-
const p =
|
|
47400
|
+
const drawRegion = (g, r, strokeWidth) => {
|
|
47401
|
+
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
47402
|
+
if (r.layer !== "base") {
|
|
47403
|
+
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47404
|
+
if (r.score !== void 0) p.attr("data-score", r.score);
|
|
47405
|
+
if (r.tags) {
|
|
47406
|
+
for (const [group, value] of Object.entries(r.tags)) {
|
|
47407
|
+
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
47408
|
+
}
|
|
47409
|
+
}
|
|
47410
|
+
}
|
|
46785
47411
|
if (r.lineNumber >= 0) {
|
|
46786
47412
|
p.attr("data-line-number", r.lineNumber);
|
|
46787
47413
|
if (onClickItem) {
|
|
@@ -46791,11 +47417,31 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46791
47417
|
);
|
|
46792
47418
|
}
|
|
46793
47419
|
}
|
|
47420
|
+
};
|
|
47421
|
+
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
47422
|
+
if (layout.rivers.length) {
|
|
47423
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47424
|
+
for (const r of layout.rivers) {
|
|
47425
|
+
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
47426
|
+
}
|
|
47427
|
+
}
|
|
47428
|
+
if (layout.insets.length) {
|
|
47429
|
+
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47430
|
+
for (const box of layout.insets) {
|
|
47431
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47432
|
+
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");
|
|
47433
|
+
}
|
|
47434
|
+
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
46794
47435
|
}
|
|
46795
47436
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
46796
|
-
|
|
47437
|
+
layout.legs.forEach((leg, i) => {
|
|
46797
47438
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
46798
|
-
if (leg.arrow)
|
|
47439
|
+
if (leg.arrow) {
|
|
47440
|
+
const id = `dgmo-map-arrow-${i}`;
|
|
47441
|
+
const s = arrowSize(leg.width);
|
|
47442
|
+
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);
|
|
47443
|
+
p.attr("marker-end", `url(#${id})`);
|
|
47444
|
+
}
|
|
46799
47445
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
46800
47446
|
emitText(
|
|
46801
47447
|
gLegs,
|
|
@@ -46809,13 +47455,13 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46809
47455
|
LABEL_FONT - 1
|
|
46810
47456
|
);
|
|
46811
47457
|
}
|
|
46812
|
-
}
|
|
47458
|
+
});
|
|
46813
47459
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
46814
47460
|
for (const poi of layout.pois) {
|
|
46815
47461
|
if (poi.isOrigin) {
|
|
46816
47462
|
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);
|
|
46817
47463
|
}
|
|
46818
|
-
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);
|
|
47464
|
+
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);
|
|
46819
47465
|
if (onClickItem) {
|
|
46820
47466
|
c.style("cursor", "pointer").on(
|
|
46821
47467
|
"click",
|
|
@@ -46839,48 +47485,66 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46839
47485
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
46840
47486
|
for (const lab of layout.labels) {
|
|
46841
47487
|
if (lab.leader) {
|
|
46842
|
-
gLabels.append("line").attr("x1", lab.leader.x1).attr("y1", lab.leader.y1).attr("x2", lab.leader.x2).attr("y2", lab.leader.y2).attr(
|
|
47488
|
+
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(
|
|
47489
|
+
"stroke",
|
|
47490
|
+
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47491
|
+
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47492
|
+
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
46843
47493
|
}
|
|
46844
|
-
|
|
46845
|
-
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);
|
|
46846
|
-
}
|
|
46847
|
-
emitText(
|
|
47494
|
+
const t = emitText(
|
|
46848
47495
|
gLabels,
|
|
46849
47496
|
lab.x,
|
|
46850
47497
|
lab.y,
|
|
46851
47498
|
lab.text,
|
|
46852
47499
|
lab.anchor,
|
|
46853
47500
|
lab.color,
|
|
46854
|
-
haloColor,
|
|
47501
|
+
lab.haloColor,
|
|
46855
47502
|
lab.halo,
|
|
46856
47503
|
LABEL_FONT
|
|
46857
47504
|
);
|
|
46858
|
-
|
|
46859
|
-
|
|
46860
|
-
|
|
46861
|
-
"transform",
|
|
46862
|
-
`translate(12, ${height - layout.pinList.length * 14 - 8})`
|
|
46863
|
-
);
|
|
46864
|
-
layout.pinList.forEach((entry, i) => {
|
|
46865
|
-
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}`);
|
|
46866
|
-
});
|
|
47505
|
+
if (lab.poiId !== void 0) {
|
|
47506
|
+
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47507
|
+
}
|
|
46867
47508
|
}
|
|
46868
47509
|
if (layout.legend) {
|
|
46869
47510
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
46870
47511
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
46871
|
-
const
|
|
47512
|
+
const ramp = layout.legend.ramp;
|
|
47513
|
+
const scoreGroup = ramp ? {
|
|
47514
|
+
name: ramp.metric?.trim() || "Score",
|
|
47515
|
+
entries: [],
|
|
47516
|
+
gradient: {
|
|
47517
|
+
min: ramp.min,
|
|
47518
|
+
max: ramp.max,
|
|
47519
|
+
hue: ramp.hue,
|
|
47520
|
+
base: ramp.base
|
|
47521
|
+
}
|
|
47522
|
+
} : null;
|
|
47523
|
+
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47524
|
+
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
46872
47525
|
if (groups.length > 0) {
|
|
46873
47526
|
const config = {
|
|
46874
|
-
groups
|
|
47527
|
+
groups,
|
|
46875
47528
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
46876
47529
|
mode: exportDims ? "export" : "preview",
|
|
46877
|
-
showEmptyGroups: false
|
|
47530
|
+
showEmptyGroups: false,
|
|
47531
|
+
// Keep inactive siblings visible as pills so the user can click to flip
|
|
47532
|
+
// the active colouring dimension (preview only — export shows just the
|
|
47533
|
+
// active group).
|
|
47534
|
+
showInactivePills: true
|
|
46878
47535
|
};
|
|
46879
47536
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
46880
47537
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
46881
47538
|
}
|
|
46882
|
-
|
|
46883
|
-
|
|
47539
|
+
}
|
|
47540
|
+
if (layout.title) {
|
|
47541
|
+
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);
|
|
47542
|
+
}
|
|
47543
|
+
if (layout.subtitle) {
|
|
47544
|
+
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);
|
|
47545
|
+
}
|
|
47546
|
+
if (layout.caption) {
|
|
47547
|
+
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);
|
|
46884
47548
|
}
|
|
46885
47549
|
}
|
|
46886
47550
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
@@ -46891,54 +47555,7 @@ function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
|
46891
47555
|
if (withHalo) {
|
|
46892
47556
|
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7);
|
|
46893
47557
|
}
|
|
46894
|
-
|
|
46895
|
-
function emitExtraLegend(svg, layout, palette, height, bottomGap) {
|
|
46896
|
-
const { legend } = layout;
|
|
46897
|
-
if (!legend) return;
|
|
46898
|
-
if (!legend.ramp && !legend.size && !legend.weight) return;
|
|
46899
|
-
const blocks = [];
|
|
46900
|
-
const g = svg.append("g").attr("class", "dgmo-map-legend-keys").attr("transform", `translate(12, ${height - 56 - bottomGap})`);
|
|
46901
|
-
let xCursor = 0;
|
|
46902
|
-
if (legend.ramp) {
|
|
46903
|
-
const ramp = legend.ramp;
|
|
46904
|
-
blocks.push(() => {
|
|
46905
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46906
|
-
const gradId = "dgmo-map-ramp";
|
|
46907
|
-
const grad = block.append("defs").append("linearGradient").attr("id", gradId).attr("x1", "0%").attr("x2", "100%");
|
|
46908
|
-
grad.append("stop").attr("offset", "0%").attr("stop-color", mix(ramp.hue, palette.bg, 15));
|
|
46909
|
-
grad.append("stop").attr("offset", "100%").attr("stop-color", ramp.hue);
|
|
46910
|
-
block.append("rect").attr("width", 80).attr("height", 8).attr("fill", `url(#${gradId})`);
|
|
46911
|
-
block.append("text").attr("x", 0).attr("y", 22).attr("font-size", 9).attr("fill", palette.textMuted).text(String(ramp.min));
|
|
46912
|
-
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));
|
|
46913
|
-
if (ramp.metric) {
|
|
46914
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(ramp.metric);
|
|
46915
|
-
}
|
|
46916
|
-
xCursor += 110;
|
|
46917
|
-
});
|
|
46918
|
-
}
|
|
46919
|
-
if (legend.size) {
|
|
46920
|
-
const sz = legend.size;
|
|
46921
|
-
blocks.push(() => {
|
|
46922
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46923
|
-
[3, 6, 10].forEach((r, i) => {
|
|
46924
|
-
block.append("circle").attr("cx", i * 26 + r).attr("cy", 8).attr("r", r).attr("fill", "none").attr("stroke", palette.textMuted);
|
|
46925
|
-
});
|
|
46926
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(sz.metric ?? "size");
|
|
46927
|
-
xCursor += 110;
|
|
46928
|
-
});
|
|
46929
|
-
}
|
|
46930
|
-
if (legend.weight) {
|
|
46931
|
-
const wt = legend.weight;
|
|
46932
|
-
blocks.push(() => {
|
|
46933
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46934
|
-
[1, 3, 6].forEach((w, i) => {
|
|
46935
|
-
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);
|
|
46936
|
-
});
|
|
46937
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(wt.metric ?? "weight");
|
|
46938
|
-
xCursor += 110;
|
|
46939
|
-
});
|
|
46940
|
-
}
|
|
46941
|
-
for (const draw of blocks) draw();
|
|
47558
|
+
return t;
|
|
46942
47559
|
}
|
|
46943
47560
|
var LABEL_FONT;
|
|
46944
47561
|
var init_renderer16 = __esm({
|
|
@@ -57564,10 +58181,13 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
57564
58181
|
// keywords, not directives; metadata keys (score/size/label) live in the
|
|
57565
58182
|
// reserved-key registry.
|
|
57566
58183
|
withGlobals({
|
|
57567
|
-
region: {
|
|
58184
|
+
region: {
|
|
58185
|
+
description: "Basemap: us-states (force US state mesh + scoping) | world (inert \u2014 already the default)",
|
|
58186
|
+
values: ["us-states", "world"]
|
|
58187
|
+
},
|
|
57568
58188
|
projection: {
|
|
57569
58189
|
description: "Override the auto projection",
|
|
57570
|
-
values: ["natural-earth", "albers-usa", "mercator"]
|
|
58190
|
+
values: ["equirectangular", "natural-earth", "albers-usa", "mercator"]
|
|
57571
58191
|
},
|
|
57572
58192
|
metric: { description: "Label for the region score ramp" },
|
|
57573
58193
|
"size-metric": { description: "Label for the POI size channel" },
|
|
@@ -59160,6 +59780,8 @@ export {
|
|
|
59160
59780
|
looksLikeSitemap,
|
|
59161
59781
|
looksLikeState,
|
|
59162
59782
|
makeDgmoError,
|
|
59783
|
+
mapBackgroundColor,
|
|
59784
|
+
mapNeutralLandColor,
|
|
59163
59785
|
matchesContiguously,
|
|
59164
59786
|
measurePertAnalysisBlock,
|
|
59165
59787
|
migrateContent,
|