@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/internal.cjs
CHANGED
|
@@ -333,6 +333,33 @@ function rectCircleOverlap(rect, circle) {
|
|
|
333
333
|
const dy = nearestY - circle.cy;
|
|
334
334
|
return dx * dx + dy * dy < circle.r * circle.r;
|
|
335
335
|
}
|
|
336
|
+
function segmentRectOverlap(x0, y0, x1, y1, rect) {
|
|
337
|
+
const dx = x1 - x0;
|
|
338
|
+
const dy = y1 - y0;
|
|
339
|
+
let t0 = 0;
|
|
340
|
+
let t1 = 1;
|
|
341
|
+
const edges = [
|
|
342
|
+
[-dx, x0 - rect.x],
|
|
343
|
+
[dx, rect.x + rect.w - x0],
|
|
344
|
+
[-dy, y0 - rect.y],
|
|
345
|
+
[dy, rect.y + rect.h - y0]
|
|
346
|
+
];
|
|
347
|
+
for (const [p, q] of edges) {
|
|
348
|
+
if (p === 0) {
|
|
349
|
+
if (q < 0) return false;
|
|
350
|
+
} else {
|
|
351
|
+
const t = q / p;
|
|
352
|
+
if (p < 0) {
|
|
353
|
+
if (t > t1) return false;
|
|
354
|
+
if (t > t0) t0 = t;
|
|
355
|
+
} else {
|
|
356
|
+
if (t < t0) return false;
|
|
357
|
+
if (t < t1) t1 = t;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
336
363
|
function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius, fontSize) {
|
|
337
364
|
const labelHeight = fontSize + 4;
|
|
338
365
|
const stepSize = labelHeight + 2;
|
|
@@ -3278,6 +3305,57 @@ var init_legend_constants = __esm({
|
|
|
3278
3305
|
});
|
|
3279
3306
|
|
|
3280
3307
|
// src/utils/legend-layout.ts
|
|
3308
|
+
function fmtRamp(n) {
|
|
3309
|
+
return Number.isInteger(n) ? String(n) : String(Math.round(n * 10) / 10);
|
|
3310
|
+
}
|
|
3311
|
+
function gradientCapsuleWidth(name, gradient) {
|
|
3312
|
+
const pw = pillWidth(name);
|
|
3313
|
+
const minW = measureLegendText(fmtRamp(gradient.min), LEGEND_ENTRY_FONT_SIZE);
|
|
3314
|
+
const maxW = measureLegendText(fmtRamp(gradient.max), LEGEND_ENTRY_FONT_SIZE);
|
|
3315
|
+
return LEGEND_CAPSULE_PAD + pw + 4 + minW + RAMP_LABEL_GAP + RAMP_LEGEND_W + RAMP_LABEL_GAP + maxW + LEGEND_CAPSULE_PAD;
|
|
3316
|
+
}
|
|
3317
|
+
function buildGradientCapsuleLayout(group, gradient) {
|
|
3318
|
+
const pw = pillWidth(group.name);
|
|
3319
|
+
const minText = fmtRamp(gradient.min);
|
|
3320
|
+
const maxText = fmtRamp(gradient.max);
|
|
3321
|
+
const minW = measureLegendText(minText, LEGEND_ENTRY_FONT_SIZE);
|
|
3322
|
+
const gx = LEGEND_CAPSULE_PAD + pw + 4;
|
|
3323
|
+
const minX = gx;
|
|
3324
|
+
const rampX = gx + minW + RAMP_LABEL_GAP;
|
|
3325
|
+
const maxX = rampX + RAMP_LEGEND_W + RAMP_LABEL_GAP;
|
|
3326
|
+
const width = gradientCapsuleWidth(group.name, gradient);
|
|
3327
|
+
return {
|
|
3328
|
+
groupName: group.name,
|
|
3329
|
+
x: 0,
|
|
3330
|
+
y: 0,
|
|
3331
|
+
width,
|
|
3332
|
+
height: LEGEND_HEIGHT,
|
|
3333
|
+
pill: {
|
|
3334
|
+
groupName: group.name,
|
|
3335
|
+
x: LEGEND_CAPSULE_PAD,
|
|
3336
|
+
y: LEGEND_CAPSULE_PAD,
|
|
3337
|
+
width: pw,
|
|
3338
|
+
height: LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2,
|
|
3339
|
+
isActive: true
|
|
3340
|
+
},
|
|
3341
|
+
entries: [],
|
|
3342
|
+
gradient: {
|
|
3343
|
+
rampX,
|
|
3344
|
+
rampY: (LEGEND_HEIGHT - RAMP_LEGEND_H) / 2,
|
|
3345
|
+
rampW: RAMP_LEGEND_W,
|
|
3346
|
+
rampH: RAMP_LEGEND_H,
|
|
3347
|
+
min: gradient.min,
|
|
3348
|
+
max: gradient.max,
|
|
3349
|
+
minText,
|
|
3350
|
+
minX,
|
|
3351
|
+
maxText,
|
|
3352
|
+
maxX,
|
|
3353
|
+
textY: LEGEND_HEIGHT / 2,
|
|
3354
|
+
hue: gradient.hue,
|
|
3355
|
+
base: gradient.base
|
|
3356
|
+
}
|
|
3357
|
+
};
|
|
3358
|
+
}
|
|
3281
3359
|
function pillWidth(name) {
|
|
3282
3360
|
return measureLegendText(name, LEGEND_PILL_FONT_SIZE) + LEGEND_PILL_PAD;
|
|
3283
3361
|
}
|
|
@@ -3420,7 +3498,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3420
3498
|
};
|
|
3421
3499
|
}
|
|
3422
3500
|
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3423
|
-
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0);
|
|
3501
|
+
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3424
3502
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3425
3503
|
return {
|
|
3426
3504
|
height: 0,
|
|
@@ -3499,7 +3577,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3499
3577
|
groupAvailW,
|
|
3500
3578
|
config.capsulePillAddonWidth ?? 0
|
|
3501
3579
|
);
|
|
3502
|
-
} else if (!activeGroupName) {
|
|
3580
|
+
} else if (!activeGroupName || config.showInactivePills) {
|
|
3503
3581
|
const pw = pillWidth(g.name);
|
|
3504
3582
|
pills.push({
|
|
3505
3583
|
groupName: g.name,
|
|
@@ -3537,6 +3615,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3537
3615
|
};
|
|
3538
3616
|
}
|
|
3539
3617
|
function buildCapsuleLayout(group, containerWidth, addonWidth = 0) {
|
|
3618
|
+
if (group.gradient) return buildGradientCapsuleLayout(group, group.gradient);
|
|
3540
3619
|
const pw = pillWidth(group.name);
|
|
3541
3620
|
const info = capsuleWidth(
|
|
3542
3621
|
group.name,
|
|
@@ -3711,7 +3790,7 @@ function getMaxLegendReservedHeight(config, containerWidth) {
|
|
|
3711
3790
|
}
|
|
3712
3791
|
return max;
|
|
3713
3792
|
}
|
|
3714
|
-
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
|
|
3793
|
+
var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP, RAMP_LEGEND_W, RAMP_LEGEND_H, RAMP_LABEL_GAP;
|
|
3715
3794
|
var init_legend_layout = __esm({
|
|
3716
3795
|
"src/utils/legend-layout.ts"() {
|
|
3717
3796
|
"use strict";
|
|
@@ -3720,6 +3799,9 @@ var init_legend_layout = __esm({
|
|
|
3720
3799
|
CONTROL_FONT_SIZE = 11;
|
|
3721
3800
|
CONTROL_ICON_GAP = 4;
|
|
3722
3801
|
CONTROL_GAP = 8;
|
|
3802
|
+
RAMP_LEGEND_W = 80;
|
|
3803
|
+
RAMP_LEGEND_H = 8;
|
|
3804
|
+
RAMP_LABEL_GAP = 6;
|
|
3723
3805
|
}
|
|
3724
3806
|
});
|
|
3725
3807
|
|
|
@@ -3807,6 +3889,16 @@ function renderCapsule(parent, capsule, palette, groupBg, pillBorder, _isDark, c
|
|
|
3807
3889
|
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);
|
|
3808
3890
|
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);
|
|
3809
3891
|
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);
|
|
3892
|
+
if (capsule.gradient) {
|
|
3893
|
+
const gr = capsule.gradient;
|
|
3894
|
+
const gradId = `dgmo-legend-ramp-${capsule.groupName.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
3895
|
+
const def = g.append("defs").append("linearGradient").attr("id", gradId);
|
|
3896
|
+
def.append("stop").attr("offset", "0%").attr("stop-color", mix(gr.hue, gr.base, 15));
|
|
3897
|
+
def.append("stop").attr("offset", "100%").attr("stop-color", gr.hue);
|
|
3898
|
+
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);
|
|
3899
|
+
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})`);
|
|
3900
|
+
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);
|
|
3901
|
+
}
|
|
3810
3902
|
for (const entry of capsule.entries) {
|
|
3811
3903
|
const entryG = g.append("g").attr("data-legend-entry", entry.value.toLowerCase()).attr("data-series-name", entry.value).style("cursor", "pointer");
|
|
3812
3904
|
entryG.append("circle").attr("cx", entry.dotCx).attr("cy", entry.dotCy).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
|
|
@@ -11228,23 +11320,22 @@ function parseC4(content, palette) {
|
|
|
11228
11320
|
}
|
|
11229
11321
|
}
|
|
11230
11322
|
const parent = findParentElement(indent, stack);
|
|
11231
|
-
|
|
11232
|
-
|
|
11323
|
+
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
11324
|
+
if (parent && descResult.isKeyword) {
|
|
11233
11325
|
if (descResult.needsColon) {
|
|
11234
11326
|
pushError(
|
|
11235
11327
|
lineNumber,
|
|
11236
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11328
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`,
|
|
11237
11329
|
"warning"
|
|
11238
11330
|
);
|
|
11239
11331
|
}
|
|
11240
|
-
const descText = descResult.isKeyword ? descResult.text : trimmed;
|
|
11241
11332
|
let desc = elementDescription.get(parent.element);
|
|
11242
11333
|
if (!desc) {
|
|
11243
11334
|
desc = [];
|
|
11244
11335
|
elementDescription.set(parent.element, desc);
|
|
11245
11336
|
parent.element.description = desc;
|
|
11246
11337
|
}
|
|
11247
|
-
desc.push(
|
|
11338
|
+
desc.push(descResult.text);
|
|
11248
11339
|
} else {
|
|
11249
11340
|
pushError(lineNumber, `Unexpected content: "${trimmed}"`);
|
|
11250
11341
|
}
|
|
@@ -11711,7 +11802,7 @@ function parseSitemap(content, palette) {
|
|
|
11711
11802
|
if (descResult.needsColon) {
|
|
11712
11803
|
pushWarning(
|
|
11713
11804
|
lineNumber,
|
|
11714
|
-
`Use "description: ${descResult.text}" \u2014
|
|
11805
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
11715
11806
|
);
|
|
11716
11807
|
}
|
|
11717
11808
|
const parent = findParentNode(indent, indentStack);
|
|
@@ -12539,23 +12630,22 @@ function parseInfra(content) {
|
|
|
12539
12630
|
}
|
|
12540
12631
|
}
|
|
12541
12632
|
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
12542
|
-
if (descResult.isKeyword
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
|
|
12633
|
+
if (descResult.isKeyword) {
|
|
12634
|
+
if (currentNode.isEdge) {
|
|
12635
|
+
continue;
|
|
12636
|
+
}
|
|
12546
12637
|
if (descResult.needsColon) {
|
|
12547
12638
|
warn(
|
|
12548
12639
|
lineNumber,
|
|
12549
|
-
`Use "description: ${descResult.text}" \u2014
|
|
12640
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
12550
12641
|
);
|
|
12551
12642
|
}
|
|
12552
|
-
|
|
12553
|
-
pushDescription(currentNode, descText);
|
|
12643
|
+
pushDescription(currentNode, descResult.text);
|
|
12554
12644
|
continue;
|
|
12555
12645
|
}
|
|
12556
12646
|
warn(
|
|
12557
12647
|
lineNumber,
|
|
12558
|
-
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or description text.`
|
|
12648
|
+
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or a description (description: text).`
|
|
12559
12649
|
);
|
|
12560
12650
|
continue;
|
|
12561
12651
|
}
|
|
@@ -15692,9 +15782,6 @@ function parseMap(content) {
|
|
|
15692
15782
|
const pushWarning = (line12, message) => {
|
|
15693
15783
|
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15694
15784
|
};
|
|
15695
|
-
const pushInfo = (line12, message) => {
|
|
15696
|
-
diagnostics.push(makeDgmoError(line12, message, "warning"));
|
|
15697
|
-
};
|
|
15698
15785
|
const lines = content.split("\n");
|
|
15699
15786
|
let firstIdx = 0;
|
|
15700
15787
|
while (firstIdx < lines.length) {
|
|
@@ -15824,10 +15911,15 @@ function parseMap(content) {
|
|
|
15824
15911
|
break;
|
|
15825
15912
|
case "projection":
|
|
15826
15913
|
dup(d.projection);
|
|
15827
|
-
if (value && ![
|
|
15914
|
+
if (value && ![
|
|
15915
|
+
"equirectangular",
|
|
15916
|
+
"natural-earth",
|
|
15917
|
+
"albers-usa",
|
|
15918
|
+
"mercator"
|
|
15919
|
+
].includes(value))
|
|
15828
15920
|
pushWarning(
|
|
15829
15921
|
line12,
|
|
15830
|
-
`Unknown projection "${value}" (expected natural-earth | albers-usa | mercator).`
|
|
15922
|
+
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15831
15923
|
);
|
|
15832
15924
|
d.projection = value;
|
|
15833
15925
|
break;
|
|
@@ -15966,17 +16058,21 @@ function parseMap(content) {
|
|
|
15966
16058
|
scoreNum = void 0;
|
|
15967
16059
|
}
|
|
15968
16060
|
}
|
|
15969
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
|
|
16061
|
+
let regionName = split.name;
|
|
16062
|
+
let regionScope;
|
|
16063
|
+
const rToks = regionName.split(/\s+/);
|
|
16064
|
+
const rLast = rToks[rToks.length - 1];
|
|
16065
|
+
if (rToks.length > 1 && SCOPE_RE.test(rLast)) {
|
|
16066
|
+
regionName = rToks.slice(0, -1).join(" ");
|
|
16067
|
+
regionScope = rLast;
|
|
16068
|
+
}
|
|
15974
16069
|
const region = {
|
|
15975
|
-
name:
|
|
16070
|
+
name: regionName,
|
|
15976
16071
|
tags,
|
|
15977
16072
|
meta,
|
|
15978
16073
|
lineNumber: line12
|
|
15979
16074
|
};
|
|
16075
|
+
if (regionScope !== void 0) region.scope = regionScope;
|
|
15980
16076
|
if (scoreNum !== void 0) region.score = scoreNum;
|
|
15981
16077
|
regions.push(region);
|
|
15982
16078
|
}
|
|
@@ -17100,7 +17196,7 @@ function parseMindmap(content, palette) {
|
|
|
17100
17196
|
if (descResult.needsColon) {
|
|
17101
17197
|
pushWarning(
|
|
17102
17198
|
lineNumber,
|
|
17103
|
-
`Use "description: ${descResult.text}" \u2014
|
|
17199
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
17104
17200
|
);
|
|
17105
17201
|
}
|
|
17106
17202
|
const parent = findMetadataParent2(indent, indentStack);
|
|
@@ -18888,7 +18984,7 @@ function parseJourneyMap(content, palette) {
|
|
|
18888
18984
|
if (descResult.needsColon) {
|
|
18889
18985
|
warn(
|
|
18890
18986
|
lineNumber,
|
|
18891
|
-
`Use "description: ${descResult.text}" \u2014
|
|
18987
|
+
`Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
|
|
18892
18988
|
);
|
|
18893
18989
|
}
|
|
18894
18990
|
currentStep.description = descResult.text;
|
|
@@ -45790,7 +45886,9 @@ function resolveMap(parsed, data) {
|
|
|
45790
45886
|
const usScoped = parsed.directives.region === "us-states" || parsed.directives.defaultCountry?.toUpperCase() === "US" || parsed.regions.some((r) => {
|
|
45791
45887
|
const f = fold(r.name);
|
|
45792
45888
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45793
|
-
}) || parsed.
|
|
45889
|
+
}) || parsed.regions.some(
|
|
45890
|
+
(r) => r.scope === "US" || r.scope?.startsWith("US-")
|
|
45891
|
+
) || parsed.pois.some(
|
|
45794
45892
|
(p) => p.pos.kind === "name" && p.pos.scope?.startsWith("US-")
|
|
45795
45893
|
);
|
|
45796
45894
|
const regions = [];
|
|
@@ -45802,7 +45900,30 @@ function resolveMap(parsed, data) {
|
|
|
45802
45900
|
const inCountry = countryIndex.get(f) ?? (REGION_ALIASES[f] ? countryIndex.get(REGION_ALIASES[f]) : void 0);
|
|
45803
45901
|
const inState = usStateIndex.get(f);
|
|
45804
45902
|
let chosen = null;
|
|
45805
|
-
|
|
45903
|
+
const scope = r.scope;
|
|
45904
|
+
if (scope) {
|
|
45905
|
+
const wantsState = scope === "US" || scope.startsWith("US-");
|
|
45906
|
+
if (wantsState && inState) {
|
|
45907
|
+
if (scope.startsWith("US-") && inState.id !== scope) {
|
|
45908
|
+
err(
|
|
45909
|
+
r.lineNumber,
|
|
45910
|
+
`No subdivision "${r.name}" in scope ${scope} (it is ${inState.id}).`,
|
|
45911
|
+
"E_MAP_SCOPE_MISS"
|
|
45912
|
+
);
|
|
45913
|
+
continue;
|
|
45914
|
+
}
|
|
45915
|
+
chosen = { ...inState, layer: "us-state" };
|
|
45916
|
+
} else if (!wantsState && inCountry) {
|
|
45917
|
+
chosen = { ...inCountry, layer: "country" };
|
|
45918
|
+
} else {
|
|
45919
|
+
err(
|
|
45920
|
+
r.lineNumber,
|
|
45921
|
+
`No region "${r.name}" found in scope ${scope}.`,
|
|
45922
|
+
"E_MAP_SCOPE_MISS"
|
|
45923
|
+
);
|
|
45924
|
+
continue;
|
|
45925
|
+
}
|
|
45926
|
+
} else if (inCountry && inState) {
|
|
45806
45927
|
if (usScoped) {
|
|
45807
45928
|
chosen = { ...inState, layer: "us-state" };
|
|
45808
45929
|
} else {
|
|
@@ -45810,7 +45931,7 @@ function resolveMap(parsed, data) {
|
|
|
45810
45931
|
}
|
|
45811
45932
|
warn(
|
|
45812
45933
|
r.lineNumber,
|
|
45813
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}).`,
|
|
45934
|
+
`"${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}").`,
|
|
45814
45935
|
"W_MAP_REGION_AMBIGUOUS"
|
|
45815
45936
|
);
|
|
45816
45937
|
} else if (inState) {
|
|
@@ -45982,9 +46103,17 @@ function resolveMap(parsed, data) {
|
|
|
45982
46103
|
};
|
|
45983
46104
|
registerPoi(id, poi, p.lineNumber);
|
|
45984
46105
|
}
|
|
46106
|
+
const declaredByName = /* @__PURE__ */ new Map();
|
|
46107
|
+
for (const p of pois) {
|
|
46108
|
+
const fn = p.name ? fold(p.name) : void 0;
|
|
46109
|
+
if (fn && fn !== p.id && !declaredByName.has(fn))
|
|
46110
|
+
declaredByName.set(fn, p.id);
|
|
46111
|
+
}
|
|
45985
46112
|
const resolveEndpoint2 = (ref, line12) => {
|
|
45986
46113
|
const f = fold(ref);
|
|
45987
46114
|
if (registry.has(f)) return f;
|
|
46115
|
+
const aliased = declaredByName.get(f);
|
|
46116
|
+
if (aliased) return aliased;
|
|
45988
46117
|
const got = lookupName(ref, void 0, line12, inferredCountry, true);
|
|
45989
46118
|
if (got.kind !== "ok") return null;
|
|
45990
46119
|
noteCountry(got.iso);
|
|
@@ -46064,23 +46193,29 @@ function resolveMap(parsed, data) {
|
|
|
46064
46193
|
[-180, -85],
|
|
46065
46194
|
[180, 85]
|
|
46066
46195
|
];
|
|
46067
|
-
|
|
46196
|
+
let extent2 = unioned ? pad(unioned, PAD_FRACTION) : DEFAULT_EXTENT;
|
|
46068
46197
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46069
46198
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46070
46199
|
const span = Math.max(lonSpan, latSpan);
|
|
46071
46200
|
const usDominant = (inferredCountry === "US" || subdivisions.includes("us-states")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
46072
46201
|
let projection;
|
|
46073
46202
|
const override = parsed.directives.projection;
|
|
46074
|
-
if (override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
46203
|
+
if (override === "equirectangular" || override === "natural-earth" || override === "albers-usa" || override === "mercator") {
|
|
46075
46204
|
projection = override;
|
|
46076
46205
|
} else if (usDominant) {
|
|
46077
46206
|
projection = "albers-usa";
|
|
46078
46207
|
} else if (span > WORLD_SPAN) {
|
|
46079
|
-
projection = "
|
|
46208
|
+
projection = "equirectangular";
|
|
46080
46209
|
} else if (span < MERCATOR_MAX_SPAN) {
|
|
46081
46210
|
projection = "mercator";
|
|
46082
46211
|
} else {
|
|
46083
|
-
projection = "
|
|
46212
|
+
projection = "equirectangular";
|
|
46213
|
+
}
|
|
46214
|
+
if (lonSpan >= 180) {
|
|
46215
|
+
extent2 = [
|
|
46216
|
+
[-180, Math.min(extent2[0][1], WORLD_LAT_SOUTH)],
|
|
46217
|
+
[180, Math.max(extent2[1][1], WORLD_LAT_NORTH)]
|
|
46218
|
+
];
|
|
46084
46219
|
}
|
|
46085
46220
|
result.regions = regions;
|
|
46086
46221
|
result.pois = pois;
|
|
@@ -46128,7 +46263,7 @@ function firstError(diags) {
|
|
|
46128
46263
|
const e = diags.find((d) => d.severity === "error");
|
|
46129
46264
|
return e ? formatDgmoError(e) : null;
|
|
46130
46265
|
}
|
|
46131
|
-
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, REGION_ALIASES;
|
|
46266
|
+
var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES;
|
|
46132
46267
|
var init_resolver2 = __esm({
|
|
46133
46268
|
"src/map/resolver.ts"() {
|
|
46134
46269
|
"use strict";
|
|
@@ -46137,6 +46272,8 @@ var init_resolver2 = __esm({
|
|
|
46137
46272
|
WORLD_SPAN = 90;
|
|
46138
46273
|
MERCATOR_MAX_SPAN = 25;
|
|
46139
46274
|
PAD_FRACTION = 0.05;
|
|
46275
|
+
WORLD_LAT_SOUTH = -58;
|
|
46276
|
+
WORLD_LAT_NORTH = 78;
|
|
46140
46277
|
REGION_ALIASES = {
|
|
46141
46278
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46142
46279
|
"united states": "united states of america",
|
|
@@ -46201,13 +46338,36 @@ function moduleBaseDir() {
|
|
|
46201
46338
|
function loadMapData() {
|
|
46202
46339
|
cache ??= (async () => {
|
|
46203
46340
|
const dir = await firstExistingDir(moduleBaseDir());
|
|
46204
|
-
const [
|
|
46341
|
+
const [
|
|
46342
|
+
worldCoarse,
|
|
46343
|
+
worldDetail,
|
|
46344
|
+
usStates,
|
|
46345
|
+
lakes,
|
|
46346
|
+
rivers,
|
|
46347
|
+
naLand,
|
|
46348
|
+
naLakes,
|
|
46349
|
+
gazetteer
|
|
46350
|
+
] = await Promise.all([
|
|
46205
46351
|
readJson(dir, FILES.worldCoarse),
|
|
46206
46352
|
readJson(dir, FILES.worldDetail),
|
|
46207
46353
|
readJson(dir, FILES.usStates),
|
|
46354
|
+
// Lakes/rivers/NA assets are optional — older bundles may predate them.
|
|
46355
|
+
readJson(dir, FILES.lakes).catch(() => void 0),
|
|
46356
|
+
readJson(dir, FILES.rivers).catch(() => void 0),
|
|
46357
|
+
readJson(dir, FILES.naLand).catch(() => void 0),
|
|
46358
|
+
readJson(dir, FILES.naLakes).catch(() => void 0),
|
|
46208
46359
|
readJson(dir, FILES.gazetteer)
|
|
46209
46360
|
]);
|
|
46210
|
-
return validate({
|
|
46361
|
+
return validate({
|
|
46362
|
+
worldCoarse,
|
|
46363
|
+
worldDetail,
|
|
46364
|
+
usStates,
|
|
46365
|
+
gazetteer,
|
|
46366
|
+
...lakes && { lakes },
|
|
46367
|
+
...rivers && { rivers },
|
|
46368
|
+
...naLand && { naLand },
|
|
46369
|
+
...naLakes && { naLakes }
|
|
46370
|
+
});
|
|
46211
46371
|
})().catch((e) => {
|
|
46212
46372
|
cache = void 0;
|
|
46213
46373
|
throw e;
|
|
@@ -46226,6 +46386,10 @@ var init_load_data = __esm({
|
|
|
46226
46386
|
worldCoarse: "world-coarse.json",
|
|
46227
46387
|
worldDetail: "world-detail.json",
|
|
46228
46388
|
usStates: "us-states.json",
|
|
46389
|
+
lakes: "lakes.json",
|
|
46390
|
+
rivers: "rivers.json",
|
|
46391
|
+
naLand: "na-land.json",
|
|
46392
|
+
naLakes: "na-lakes.json",
|
|
46229
46393
|
gazetteer: "gazetteer.json"
|
|
46230
46394
|
};
|
|
46231
46395
|
CANDIDATE_DIRS = [
|
|
@@ -46253,36 +46417,74 @@ function decodeLayer(topo) {
|
|
|
46253
46417
|
function projectionFor(family) {
|
|
46254
46418
|
switch (family) {
|
|
46255
46419
|
case "albers-usa":
|
|
46256
|
-
return (
|
|
46420
|
+
return usConusProjection();
|
|
46257
46421
|
case "mercator":
|
|
46258
46422
|
return (0, import_d3_geo2.geoMercator)();
|
|
46259
46423
|
case "natural-earth":
|
|
46260
|
-
default:
|
|
46261
46424
|
return (0, import_d3_geo2.geoNaturalEarth1)();
|
|
46425
|
+
case "equirectangular":
|
|
46426
|
+
default:
|
|
46427
|
+
return (0, import_d3_geo2.geoEquirectangular)();
|
|
46262
46428
|
}
|
|
46263
46429
|
}
|
|
46430
|
+
function mapBackgroundColor(palette) {
|
|
46431
|
+
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
46432
|
+
}
|
|
46433
|
+
function mapNeutralLandColor(palette, isDark) {
|
|
46434
|
+
return mix(
|
|
46435
|
+
palette.colors.green,
|
|
46436
|
+
palette.bg,
|
|
46437
|
+
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46438
|
+
);
|
|
46439
|
+
}
|
|
46264
46440
|
function layoutMap(resolved, data, size, opts) {
|
|
46265
46441
|
const { palette, isDark } = opts;
|
|
46266
46442
|
const { width, height } = size;
|
|
46267
|
-
const
|
|
46443
|
+
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46444
|
+
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
46445
|
+
const worldTopo = usCrisp ? data.naLand : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46268
46446
|
const worldLayer = decodeLayer(worldTopo);
|
|
46269
|
-
const usLayer =
|
|
46270
|
-
const
|
|
46271
|
-
const
|
|
46447
|
+
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
46448
|
+
const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
|
|
46449
|
+
const neutralFill = mix(palette.colors.green, palette.bg, landTint);
|
|
46450
|
+
const water = mapBackgroundColor(palette);
|
|
46451
|
+
const usContext = usLayer !== null;
|
|
46452
|
+
const foreignFill = mix(
|
|
46453
|
+
palette.colors.gray,
|
|
46454
|
+
palette.bg,
|
|
46455
|
+
isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46456
|
+
);
|
|
46457
|
+
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46272
46458
|
const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
|
|
46273
46459
|
const scaleOverride = resolved.directives.scale;
|
|
46274
46460
|
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
|
|
46275
46461
|
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
|
|
46276
|
-
const rampHue = palette.
|
|
46462
|
+
const rampHue = palette.colors.red;
|
|
46277
46463
|
const hasRamp = scores.length > 0;
|
|
46278
|
-
const
|
|
46279
|
-
|
|
46280
|
-
|
|
46281
|
-
|
|
46464
|
+
const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
|
|
46465
|
+
const matchColorGroup = (v) => {
|
|
46466
|
+
const lv = v.trim().toLowerCase();
|
|
46467
|
+
if (lv === "none") return null;
|
|
46468
|
+
if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
|
|
46469
|
+
return SCORE_NAME;
|
|
46470
|
+
const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
46471
|
+
return tg ? tg.name : v;
|
|
46472
|
+
};
|
|
46473
|
+
const override = opts.activeGroup;
|
|
46474
|
+
let activeGroup;
|
|
46475
|
+
if (override !== void 0) {
|
|
46476
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
46477
|
+
} else if (resolved.directives.activeTag !== void 0) {
|
|
46478
|
+
activeGroup = matchColorGroup(resolved.directives.activeTag);
|
|
46479
|
+
} else {
|
|
46480
|
+
activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46481
|
+
}
|
|
46482
|
+
const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
|
|
46483
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46282
46484
|
const fillForScore = (s) => {
|
|
46283
46485
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
46284
46486
|
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
46285
|
-
return mix(rampHue,
|
|
46487
|
+
return mix(rampHue, rampBase, pct);
|
|
46286
46488
|
};
|
|
46287
46489
|
const tagFill = (tags, groupName) => {
|
|
46288
46490
|
if (!groupName) return null;
|
|
@@ -46296,40 +46498,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46296
46498
|
(e) => e.value.toLowerCase() === val.toLowerCase()
|
|
46297
46499
|
);
|
|
46298
46500
|
if (!entry?.color) return null;
|
|
46299
|
-
return
|
|
46501
|
+
return mix(
|
|
46502
|
+
entry.color,
|
|
46503
|
+
palette.bg,
|
|
46504
|
+
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46505
|
+
);
|
|
46506
|
+
};
|
|
46507
|
+
const regionFill = (r) => {
|
|
46508
|
+
if (activeIsScore) {
|
|
46509
|
+
return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
|
|
46510
|
+
}
|
|
46511
|
+
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46300
46512
|
};
|
|
46301
46513
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46302
|
-
const
|
|
46303
|
-
for (const r of resolved.regions) {
|
|
46304
|
-
const f = r.layer === "us-state" ? usLayer?.get(r.iso) : worldLayer.get(r.iso);
|
|
46305
|
-
if (f) regionFeatures.push(f);
|
|
46306
|
-
}
|
|
46307
|
-
const extentCorners = () => {
|
|
46514
|
+
const extentOutline = () => {
|
|
46308
46515
|
const [[w, s], [e, n]] = resolved.extent;
|
|
46516
|
+
const N = 16;
|
|
46517
|
+
const coords = [];
|
|
46518
|
+
for (let i = 0; i <= N; i++) {
|
|
46519
|
+
const t = i / N;
|
|
46520
|
+
const lon = w + (e - w) * t;
|
|
46521
|
+
const lat = s + (n - s) * t;
|
|
46522
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46523
|
+
}
|
|
46309
46524
|
return {
|
|
46310
46525
|
type: "Feature",
|
|
46311
46526
|
properties: {},
|
|
46312
|
-
geometry: {
|
|
46313
|
-
type: "MultiPoint",
|
|
46314
|
-
coordinates: [
|
|
46315
|
-
[w, s],
|
|
46316
|
-
[e, s],
|
|
46317
|
-
[e, n],
|
|
46318
|
-
[w, n]
|
|
46319
|
-
]
|
|
46320
|
-
}
|
|
46527
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46321
46528
|
};
|
|
46322
46529
|
};
|
|
46323
46530
|
let fitFeatures;
|
|
46324
|
-
if (resolved.projection === "albers-usa") {
|
|
46325
|
-
|
|
46326
|
-
else if (usLayer) fitFeatures = [...usLayer.values()];
|
|
46327
|
-
else {
|
|
46328
|
-
const us = worldLayer.get("US");
|
|
46329
|
-
fitFeatures = us ? [us] : [...worldLayer.values()];
|
|
46330
|
-
}
|
|
46531
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46532
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46331
46533
|
} else {
|
|
46332
|
-
fitFeatures = [
|
|
46534
|
+
fitFeatures = [extentOutline()];
|
|
46333
46535
|
}
|
|
46334
46536
|
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46335
46537
|
const projection = projectionFor(resolved.projection);
|
|
@@ -46338,32 +46540,311 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46338
46540
|
if (centerLon > 180) centerLon -= 360;
|
|
46339
46541
|
projection.rotate([-centerLon, 0]);
|
|
46340
46542
|
}
|
|
46341
|
-
|
|
46543
|
+
const TITLE_GAP = 16;
|
|
46544
|
+
let topPad = FIT_PAD;
|
|
46545
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
46546
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46547
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP);
|
|
46548
|
+
}
|
|
46549
|
+
const fitBox = [
|
|
46550
|
+
[FIT_PAD, topPad],
|
|
46342
46551
|
[
|
|
46343
|
-
|
|
46344
|
-
|
|
46345
|
-
|
|
46346
|
-
|
|
46347
|
-
|
|
46348
|
-
|
|
46349
|
-
|
|
46350
|
-
|
|
46351
|
-
|
|
46352
|
-
|
|
46552
|
+
Math.max(FIT_PAD + 1, width - FIT_PAD),
|
|
46553
|
+
Math.max(topPad + 1, height - FIT_PAD)
|
|
46554
|
+
]
|
|
46555
|
+
];
|
|
46556
|
+
projection.fitExtent(fitBox, fitTarget);
|
|
46557
|
+
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
46558
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46559
|
+
let path;
|
|
46560
|
+
let project;
|
|
46561
|
+
if (fitIsGlobal) {
|
|
46562
|
+
const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
|
|
46563
|
+
const bx0 = cb[0][0];
|
|
46564
|
+
const by0 = cb[0][1];
|
|
46565
|
+
const cw = cb[1][0] - bx0;
|
|
46566
|
+
const ch = cb[1][1] - by0;
|
|
46567
|
+
const ox = fitBox[0][0];
|
|
46568
|
+
const oy = fitBox[0][1];
|
|
46569
|
+
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46570
|
+
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
46571
|
+
const stretch = (x, y) => [
|
|
46572
|
+
ox + (x - bx0) * sx,
|
|
46573
|
+
oy + (y - by0) * sy
|
|
46574
|
+
];
|
|
46575
|
+
const baseProjection = projection;
|
|
46576
|
+
const tx = (0, import_d3_geo2.geoTransform)({
|
|
46577
|
+
point(x, y) {
|
|
46578
|
+
const [px, py] = stretch(x, y);
|
|
46579
|
+
this.stream.point(px, py);
|
|
46580
|
+
}
|
|
46581
|
+
});
|
|
46582
|
+
path = (0, import_d3_geo2.geoPath)({
|
|
46583
|
+
stream: (s) => baseProjection.stream(
|
|
46584
|
+
tx.stream(s)
|
|
46585
|
+
)
|
|
46586
|
+
});
|
|
46587
|
+
project = (lon, lat) => {
|
|
46588
|
+
const p = baseProjection([lon, lat]);
|
|
46589
|
+
return p ? stretch(p[0], p[1]) : null;
|
|
46590
|
+
};
|
|
46591
|
+
} else {
|
|
46592
|
+
path = (0, import_d3_geo2.geoPath)(projection);
|
|
46593
|
+
project = (lon, lat) => projection([lon, lat]) ?? null;
|
|
46594
|
+
}
|
|
46595
|
+
const insets = [];
|
|
46596
|
+
const insetRegions = [];
|
|
46597
|
+
const insetLabelSeeds = [];
|
|
46598
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46599
|
+
const PAD = 8;
|
|
46600
|
+
const GAP = 12;
|
|
46601
|
+
const yB = height - FIT_PAD;
|
|
46602
|
+
const BW = 8;
|
|
46603
|
+
const coast = /* @__PURE__ */ new Map();
|
|
46604
|
+
const addPt = (lon, lat) => {
|
|
46605
|
+
const p = projection([lon, lat]);
|
|
46606
|
+
if (!p) return;
|
|
46607
|
+
const bi = Math.floor(p[0] / BW);
|
|
46608
|
+
const cur = coast.get(bi);
|
|
46609
|
+
if (cur === void 0 || p[1] > cur) coast.set(bi, p[1]);
|
|
46610
|
+
};
|
|
46611
|
+
const walk = (co) => {
|
|
46612
|
+
if (Array.isArray(co) && typeof co[0] === "number")
|
|
46613
|
+
addPt(co[0], co[1]);
|
|
46614
|
+
else if (Array.isArray(co)) for (const c of co) walk(c);
|
|
46615
|
+
};
|
|
46616
|
+
for (const [iso, f] of usLayer) {
|
|
46617
|
+
if (US_NON_CONUS.has(iso)) continue;
|
|
46618
|
+
walk(f.geometry.coordinates);
|
|
46619
|
+
}
|
|
46620
|
+
const at = (x) => {
|
|
46621
|
+
const bi = Math.floor(x / BW);
|
|
46622
|
+
let y = -Infinity;
|
|
46623
|
+
for (let k = bi - 1; k <= bi + 1; k++) {
|
|
46624
|
+
const v = coast.get(k);
|
|
46625
|
+
if (v !== void 0 && v > y) y = v;
|
|
46626
|
+
}
|
|
46627
|
+
return y;
|
|
46628
|
+
};
|
|
46629
|
+
const coastTop = (x0, xr) => {
|
|
46630
|
+
const n = 24;
|
|
46631
|
+
const pts = [];
|
|
46632
|
+
let maxY = -Infinity;
|
|
46633
|
+
for (let i = 0; i <= n; i++) {
|
|
46634
|
+
const x = x0 + (xr - x0) * i / n;
|
|
46635
|
+
const y = at(x);
|
|
46636
|
+
if (y > -Infinity) {
|
|
46637
|
+
pts.push([x, y]);
|
|
46638
|
+
if (y > maxY) maxY = y;
|
|
46639
|
+
}
|
|
46640
|
+
}
|
|
46641
|
+
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46642
|
+
let m = 0;
|
|
46643
|
+
if (pts.length >= 2) {
|
|
46644
|
+
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46645
|
+
for (const [x, y] of pts) {
|
|
46646
|
+
sx += x;
|
|
46647
|
+
sy += y;
|
|
46648
|
+
sxx += x * x;
|
|
46649
|
+
sxy += x * y;
|
|
46650
|
+
}
|
|
46651
|
+
const den = pts.length * sxx - sx * sx;
|
|
46652
|
+
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46653
|
+
}
|
|
46654
|
+
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46655
|
+
let c = -Infinity;
|
|
46656
|
+
for (const [x, y] of pts) {
|
|
46657
|
+
const need = y - m * x + GAP;
|
|
46658
|
+
if (need > c) c = need;
|
|
46659
|
+
}
|
|
46660
|
+
return (x) => m * x + c;
|
|
46661
|
+
};
|
|
46662
|
+
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46663
|
+
const f = usLayer.get(iso);
|
|
46664
|
+
if (!f) return boxX;
|
|
46665
|
+
const x0 = boxX;
|
|
46666
|
+
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46667
|
+
if (iw < 24) return boxX;
|
|
46668
|
+
const xr = x0 + iw + 2 * PAD;
|
|
46669
|
+
const top = coastTop(x0, xr);
|
|
46670
|
+
const yL = top(x0);
|
|
46671
|
+
const yR = top(xr);
|
|
46672
|
+
proj.fitWidth(iw, f);
|
|
46673
|
+
const bb = (0, import_d3_geo2.geoPath)(proj).bounds(f);
|
|
46674
|
+
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46675
|
+
const needH = sh + 2 * PAD;
|
|
46676
|
+
let topFit = Math.max(yL, yR);
|
|
46677
|
+
const bottom = Math.min(topFit + needH, yB);
|
|
46678
|
+
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46679
|
+
const lift = topFit - Math.max(yL, yR);
|
|
46680
|
+
const topL = yL + lift;
|
|
46681
|
+
const topR = yR + lift;
|
|
46682
|
+
proj.fitExtent(
|
|
46683
|
+
[
|
|
46684
|
+
[x0 + PAD, topFit + PAD],
|
|
46685
|
+
[xr - PAD, bottom - PAD]
|
|
46686
|
+
],
|
|
46687
|
+
f
|
|
46688
|
+
);
|
|
46689
|
+
const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
|
|
46690
|
+
if (!d) return xr;
|
|
46691
|
+
const r = regionById.get(iso);
|
|
46692
|
+
let fill2 = neutralFill;
|
|
46693
|
+
let lineNumber = -1;
|
|
46694
|
+
if (r?.layer === "us-state") {
|
|
46695
|
+
fill2 = regionFill(r);
|
|
46696
|
+
lineNumber = r.lineNumber;
|
|
46697
|
+
}
|
|
46698
|
+
insets.push({
|
|
46699
|
+
x: x0,
|
|
46700
|
+
y: Math.min(topL, topR),
|
|
46701
|
+
w: xr - x0,
|
|
46702
|
+
h: bottom - Math.min(topL, topR),
|
|
46703
|
+
points: [
|
|
46704
|
+
[x0, topL],
|
|
46705
|
+
[xr, topR],
|
|
46706
|
+
[xr, bottom],
|
|
46707
|
+
[x0, bottom]
|
|
46708
|
+
]
|
|
46709
|
+
});
|
|
46710
|
+
insetRegions.push({
|
|
46711
|
+
id: iso,
|
|
46712
|
+
d,
|
|
46713
|
+
fill: fill2,
|
|
46714
|
+
stroke: regionStroke,
|
|
46715
|
+
lineNumber,
|
|
46716
|
+
layer: "us-state",
|
|
46717
|
+
...r?.score !== void 0 && { score: r.score },
|
|
46718
|
+
...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46719
|
+
});
|
|
46720
|
+
const ctr = (0, import_d3_geo2.geoPath)(proj).centroid(f);
|
|
46721
|
+
if (Number.isFinite(ctr[0])) {
|
|
46722
|
+
const name = f.properties?.name ?? iso;
|
|
46723
|
+
insetLabelSeeds.push({ x: ctr[0], y: ctr[1], iso, name, lineNumber });
|
|
46724
|
+
}
|
|
46725
|
+
return xr;
|
|
46726
|
+
};
|
|
46727
|
+
const akRight = placeInset(
|
|
46728
|
+
"US-AK",
|
|
46729
|
+
alaskaProjection(),
|
|
46730
|
+
FIT_PAD,
|
|
46731
|
+
width * 0.15
|
|
46732
|
+
);
|
|
46733
|
+
placeInset("US-HI", hawaiiProjection(), akRight + 24, width * 0.1);
|
|
46734
|
+
}
|
|
46735
|
+
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46736
|
+
const cullExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
|
|
46737
|
+
const [[exW, exS], [exE, exN]] = cullExtent;
|
|
46738
|
+
const lonSpan = exE - exW;
|
|
46739
|
+
const latSpan = exN - exS;
|
|
46740
|
+
const isGlobalView = lonSpan >= 270 || latSpan >= 130;
|
|
46741
|
+
const padLon = Math.max(8, lonSpan * 0.35);
|
|
46742
|
+
const padLat = Math.max(8, latSpan * 0.35);
|
|
46743
|
+
const vW = exW - padLon;
|
|
46744
|
+
const vE = exE + padLon;
|
|
46745
|
+
const vS = exS - padLat;
|
|
46746
|
+
const vN = exN + padLat;
|
|
46747
|
+
const vLonCenter = (exW + exE) / 2;
|
|
46748
|
+
const normLon = (lon) => {
|
|
46749
|
+
let L = lon;
|
|
46750
|
+
while (L < vLonCenter - 180) L += 360;
|
|
46751
|
+
while (L > vLonCenter + 180) L -= 360;
|
|
46752
|
+
return L;
|
|
46753
|
+
};
|
|
46754
|
+
const ringOverlapsView = (ring) => {
|
|
46755
|
+
let anyIn = false;
|
|
46756
|
+
let loMin = Infinity, loMax = -Infinity, laMin = Infinity, laMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
46757
|
+
for (const [rawLon, lat] of ring) {
|
|
46758
|
+
const lon = normLon(rawLon);
|
|
46759
|
+
if (lon >= vW && lon <= vE && lat >= vS && lat <= vN) anyIn = true;
|
|
46760
|
+
if (lon < loMin) loMin = lon;
|
|
46761
|
+
if (lon > loMax) loMax = lon;
|
|
46762
|
+
if (rawLon < rawMin) rawMin = rawLon;
|
|
46763
|
+
if (rawLon > rawMax) rawMax = rawLon;
|
|
46764
|
+
if (lat < laMin) laMin = lat;
|
|
46765
|
+
if (lat > laMax) laMax = lat;
|
|
46766
|
+
}
|
|
46767
|
+
if (loMax - loMin > 270) return false;
|
|
46768
|
+
if (rawMax - rawMin > 180 && loMax - loMin < 90) return false;
|
|
46769
|
+
if (anyIn) return true;
|
|
46770
|
+
if (loMax - loMin > 180) return false;
|
|
46771
|
+
return !(loMax < vW || loMin > vE || laMax < vS || laMin > vN);
|
|
46772
|
+
};
|
|
46773
|
+
const cullFeatureToView = (f) => {
|
|
46774
|
+
if (isGlobalView) return f;
|
|
46775
|
+
const g = f.geometry;
|
|
46776
|
+
if (!g) return f;
|
|
46777
|
+
if (g.type === "Polygon") {
|
|
46778
|
+
const ring = g.coordinates[0];
|
|
46779
|
+
return ringOverlapsView(ring) ? f : null;
|
|
46780
|
+
}
|
|
46781
|
+
if (g.type === "MultiPolygon") {
|
|
46782
|
+
const polys = g.coordinates;
|
|
46783
|
+
const keep = polys.filter(
|
|
46784
|
+
(p) => ringOverlapsView(p[0])
|
|
46785
|
+
);
|
|
46786
|
+
if (!keep.length) return null;
|
|
46787
|
+
if (keep.length === polys.length) return f;
|
|
46788
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46789
|
+
}
|
|
46790
|
+
return f;
|
|
46791
|
+
};
|
|
46792
|
+
const SEAM_SLIVER_MAX_SPAN = 100;
|
|
46793
|
+
const ringIsFrameFiller = (ring) => {
|
|
46794
|
+
const lons = ring.map(([lon]) => lon).sort((a, b) => a - b);
|
|
46795
|
+
if (lons.length < 2) return false;
|
|
46796
|
+
let maxGap = -1;
|
|
46797
|
+
let gapIdx = 0;
|
|
46798
|
+
for (let i = 1; i < lons.length; i++) {
|
|
46799
|
+
const g = lons[i] - lons[i - 1];
|
|
46800
|
+
if (g > maxGap) {
|
|
46801
|
+
maxGap = g;
|
|
46802
|
+
gapIdx = i;
|
|
46803
|
+
}
|
|
46804
|
+
}
|
|
46805
|
+
const wrapGap = lons[0] + 360 - lons[lons.length - 1];
|
|
46806
|
+
if (wrapGap >= maxGap) return false;
|
|
46807
|
+
const span = 360 - maxGap;
|
|
46808
|
+
const east = lons[gapIdx - 1] + 360;
|
|
46809
|
+
return east > 180 && span < SEAM_SLIVER_MAX_SPAN;
|
|
46810
|
+
};
|
|
46811
|
+
const dropFrameFillers = (f) => {
|
|
46812
|
+
const g = f.geometry;
|
|
46813
|
+
if (!g) return f;
|
|
46814
|
+
if (g.type === "Polygon") {
|
|
46815
|
+
const ring = g.coordinates[0];
|
|
46816
|
+
return ringIsFrameFiller(ring) ? null : f;
|
|
46817
|
+
}
|
|
46818
|
+
if (g.type === "MultiPolygon") {
|
|
46819
|
+
const polys = g.coordinates;
|
|
46820
|
+
const keep = polys.filter(
|
|
46821
|
+
(p) => !ringIsFrameFiller(p[0])
|
|
46822
|
+
);
|
|
46823
|
+
if (!keep.length) return null;
|
|
46824
|
+
if (keep.length === polys.length) return f;
|
|
46825
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46826
|
+
}
|
|
46827
|
+
return f;
|
|
46828
|
+
};
|
|
46353
46829
|
const regions = [];
|
|
46354
|
-
const pushRegionLayer = (layerFeatures, layerKind) => {
|
|
46830
|
+
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46355
46831
|
for (const [iso, f] of layerFeatures) {
|
|
46356
|
-
|
|
46357
|
-
|
|
46832
|
+
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
46833
|
+
continue;
|
|
46834
|
+
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46358
46835
|
const r = regionById.get(iso);
|
|
46836
|
+
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
46837
|
+
if (!viewF) continue;
|
|
46838
|
+
const d = path(viewF) ?? "";
|
|
46839
|
+
if (!d) continue;
|
|
46359
46840
|
const isThisLayer = r?.layer === layerKind;
|
|
46360
|
-
|
|
46841
|
+
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46842
|
+
let fill2 = isForeign ? foreignFill : neutralFill;
|
|
46361
46843
|
let label;
|
|
46362
46844
|
let lineNumber = -1;
|
|
46363
46845
|
let layer = "base";
|
|
46364
46846
|
if (isThisLayer) {
|
|
46365
|
-
|
|
46366
|
-
else fill2 = tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46847
|
+
fill2 = regionFill(r);
|
|
46367
46848
|
lineNumber = r.lineNumber;
|
|
46368
46849
|
layer = layerKind;
|
|
46369
46850
|
label = r.name;
|
|
@@ -46375,12 +46856,42 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46375
46856
|
stroke: regionStroke,
|
|
46376
46857
|
lineNumber,
|
|
46377
46858
|
layer,
|
|
46378
|
-
...label !== void 0 && { label }
|
|
46859
|
+
...label !== void 0 && { label },
|
|
46860
|
+
...isThisLayer && r.score !== void 0 && { score: r.score },
|
|
46861
|
+
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46379
46862
|
});
|
|
46380
46863
|
}
|
|
46381
46864
|
};
|
|
46382
|
-
pushRegionLayer(worldLayer, "country");
|
|
46383
|
-
if (usLayer) pushRegionLayer(usLayer, "us-state");
|
|
46865
|
+
pushRegionLayer(worldLayer, "country", !isGlobalView);
|
|
46866
|
+
if (usLayer) pushRegionLayer(usLayer, "us-state", !conusFit && !isGlobalView);
|
|
46867
|
+
const lakesTopo = usCrisp && data.naLakes ? data.naLakes : data.lakes;
|
|
46868
|
+
if (lakesTopo) {
|
|
46869
|
+
for (const [, f] of decodeLayer(lakesTopo)) {
|
|
46870
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46871
|
+
if (!viewF) continue;
|
|
46872
|
+
const d = path(viewF) ?? "";
|
|
46873
|
+
if (!d) continue;
|
|
46874
|
+
regions.push({
|
|
46875
|
+
id: "lake",
|
|
46876
|
+
d,
|
|
46877
|
+
fill: water,
|
|
46878
|
+
stroke: "none",
|
|
46879
|
+
lineNumber: -1,
|
|
46880
|
+
layer: "base"
|
|
46881
|
+
});
|
|
46882
|
+
}
|
|
46883
|
+
}
|
|
46884
|
+
const riverColor = water;
|
|
46885
|
+
const rivers = [];
|
|
46886
|
+
if (data.rivers) {
|
|
46887
|
+
for (const [, f] of decodeLayer(data.rivers)) {
|
|
46888
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46889
|
+
if (!viewF) continue;
|
|
46890
|
+
const d = path(viewF) ?? "";
|
|
46891
|
+
if (!d) continue;
|
|
46892
|
+
rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
|
|
46893
|
+
}
|
|
46894
|
+
}
|
|
46384
46895
|
const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
46385
46896
|
const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
|
|
46386
46897
|
const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
|
|
@@ -46401,8 +46912,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46401
46912
|
if (hex) return { fill: hex, stroke: mix(hex, palette.text, 18) };
|
|
46402
46913
|
}
|
|
46403
46914
|
return {
|
|
46404
|
-
fill: palette.
|
|
46405
|
-
stroke: mix(palette.
|
|
46915
|
+
fill: palette.colors.orange,
|
|
46916
|
+
stroke: mix(palette.colors.orange, palette.text, 18)
|
|
46406
46917
|
};
|
|
46407
46918
|
};
|
|
46408
46919
|
const routeNumberById = /* @__PURE__ */ new Map();
|
|
@@ -46440,7 +46951,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46440
46951
|
cy += Math.sin(ang) * COLO_R;
|
|
46441
46952
|
}
|
|
46442
46953
|
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
46443
|
-
poiScreen.set(e.p.id, { cx, cy });
|
|
46954
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
46444
46955
|
const num = routeNumberById.get(e.p.id);
|
|
46445
46956
|
pois.push({
|
|
46446
46957
|
id: e.p.id,
|
|
@@ -46457,17 +46968,36 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46457
46968
|
});
|
|
46458
46969
|
}
|
|
46459
46970
|
const legs = [];
|
|
46971
|
+
const RIM_GAP = 1.5;
|
|
46460
46972
|
const legPath = (a, b, curved, offset) => {
|
|
46461
|
-
if (!curved && offset === 0) return `M${a.cx},${a.cy}L${b.cx},${b.cy}`;
|
|
46462
46973
|
const mx = (a.cx + b.cx) / 2;
|
|
46463
46974
|
const my = (a.cy + b.cy) / 2;
|
|
46464
46975
|
const dx = b.cx - a.cx;
|
|
46465
46976
|
const dy = b.cy - a.cy;
|
|
46466
46977
|
const len = Math.hypot(dx, dy) || 1;
|
|
46978
|
+
const trimA = Math.min(a.r + RIM_GAP, len * 0.45);
|
|
46979
|
+
const trimB = Math.min(b.r + RIM_GAP, len * 0.45);
|
|
46980
|
+
if (!curved && offset === 0) {
|
|
46981
|
+
const ux = dx / len;
|
|
46982
|
+
const uy = dy / len;
|
|
46983
|
+
const ax2 = a.cx + ux * trimA;
|
|
46984
|
+
const ay2 = a.cy + uy * trimA;
|
|
46985
|
+
const bx2 = b.cx - ux * trimB;
|
|
46986
|
+
const by2 = b.cy - uy * trimB;
|
|
46987
|
+
return `M${ax2},${ay2}L${bx2},${by2}`;
|
|
46988
|
+
}
|
|
46467
46989
|
const nx = -dy / len;
|
|
46468
46990
|
const ny = dx / len;
|
|
46469
46991
|
const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
|
|
46470
|
-
|
|
46992
|
+
const px = mx + nx * bow;
|
|
46993
|
+
const py = my + ny * bow;
|
|
46994
|
+
const ta = Math.hypot(px - a.cx, py - a.cy) || 1;
|
|
46995
|
+
const tb = Math.hypot(b.cx - px, b.cy - py) || 1;
|
|
46996
|
+
const ax = a.cx + (px - a.cx) / ta * trimA;
|
|
46997
|
+
const ay = a.cy + (py - a.cy) / ta * trimA;
|
|
46998
|
+
const bx = b.cx - (b.cx - px) / tb * trimB;
|
|
46999
|
+
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
47000
|
+
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
46471
47001
|
};
|
|
46472
47002
|
for (const rt of resolved.routes) {
|
|
46473
47003
|
const curved = rt.meta["style"] === "arc";
|
|
@@ -46478,7 +47008,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46478
47008
|
legs.push({
|
|
46479
47009
|
d: legPath(a, b, curved, 0),
|
|
46480
47010
|
width: W_MIN,
|
|
46481
|
-
color: mix(palette.text, palette.bg,
|
|
47011
|
+
color: mix(palette.text, palette.bg, 72),
|
|
46482
47012
|
arrow: true,
|
|
46483
47013
|
lineNumber: rt.lineNumber
|
|
46484
47014
|
});
|
|
@@ -46514,7 +47044,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46514
47044
|
legs.push({
|
|
46515
47045
|
d: legPath(a, b, curved, offset),
|
|
46516
47046
|
width: widthFor(e),
|
|
46517
|
-
color: mix(palette.text, palette.bg,
|
|
47047
|
+
color: mix(palette.text, palette.bg, 66),
|
|
46518
47048
|
arrow: e.directed,
|
|
46519
47049
|
lineNumber: e.lineNumber,
|
|
46520
47050
|
...e.label !== void 0 && {
|
|
@@ -46526,38 +47056,92 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46526
47056
|
});
|
|
46527
47057
|
}
|
|
46528
47058
|
const labels = [];
|
|
46529
|
-
const pinList = [];
|
|
46530
47059
|
const obstacles = [];
|
|
46531
47060
|
const markers = pois.map((p) => ({
|
|
46532
47061
|
cx: p.cx,
|
|
46533
47062
|
cy: p.cy,
|
|
46534
47063
|
r: p.r
|
|
46535
47064
|
}));
|
|
46536
|
-
const
|
|
47065
|
+
const legSegments = [];
|
|
47066
|
+
for (const leg of legs) {
|
|
47067
|
+
const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
47068
|
+
leg.d
|
|
47069
|
+
);
|
|
47070
|
+
if (!m) continue;
|
|
47071
|
+
const x0 = +m[1];
|
|
47072
|
+
const y0 = +m[2];
|
|
47073
|
+
if (m[3] !== void 0) {
|
|
47074
|
+
legSegments.push([x0, y0, +m[3], +m[4]]);
|
|
47075
|
+
} else {
|
|
47076
|
+
const cx = +m[5];
|
|
47077
|
+
const cy = +m[6];
|
|
47078
|
+
const ex = +m[7];
|
|
47079
|
+
const ey = +m[8];
|
|
47080
|
+
const N = 8;
|
|
47081
|
+
let px = x0;
|
|
47082
|
+
let py = y0;
|
|
47083
|
+
for (let i = 1; i <= N; i++) {
|
|
47084
|
+
const t = i / N;
|
|
47085
|
+
const u = 1 - t;
|
|
47086
|
+
const qx = u * u * x0 + 2 * u * t * cx + t * t * ex;
|
|
47087
|
+
const qy = u * u * y0 + 2 * u * t * cy + t * t * ey;
|
|
47088
|
+
legSegments.push([px, py, qx, qy]);
|
|
47089
|
+
px = qx;
|
|
47090
|
+
py = qy;
|
|
47091
|
+
}
|
|
47092
|
+
}
|
|
47093
|
+
}
|
|
47094
|
+
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));
|
|
46537
47095
|
const regionLabelMode = resolved.directives.regionLabels ?? "off";
|
|
47096
|
+
const LABEL_PADX = 6;
|
|
47097
|
+
const LABEL_PADY = 3;
|
|
47098
|
+
const labelW = (text) => measureLegendText(text, FONT) + 2 * LABEL_PADX;
|
|
47099
|
+
const labelH = FONT + 2 * LABEL_PADY;
|
|
47100
|
+
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
47101
|
+
const color = contrastText(
|
|
47102
|
+
fill2,
|
|
47103
|
+
palette.textOnFillLight,
|
|
47104
|
+
palette.textOnFillDark
|
|
47105
|
+
);
|
|
47106
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47107
|
+
labels.push({
|
|
47108
|
+
x,
|
|
47109
|
+
y,
|
|
47110
|
+
text,
|
|
47111
|
+
anchor: "middle",
|
|
47112
|
+
color,
|
|
47113
|
+
halo: true,
|
|
47114
|
+
haloColor,
|
|
47115
|
+
lineNumber
|
|
47116
|
+
});
|
|
47117
|
+
};
|
|
47118
|
+
const WORLD_LABEL_ANCHORS = {
|
|
47119
|
+
US: [-98.5, 39.5]
|
|
47120
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
47121
|
+
};
|
|
46538
47122
|
if (regionLabelMode === "full" || regionLabelMode === "abbrev") {
|
|
46539
47123
|
for (const r of regions) {
|
|
46540
47124
|
if (r.layer === "base" || r.label === void 0) continue;
|
|
46541
47125
|
const f = r.layer === "us-state" ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
46542
47126
|
if (!f) continue;
|
|
46543
47127
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
46544
|
-
if ((x1 - x0) * (y1 - y0) < TINY_REGION_AREA) continue;
|
|
46545
|
-
const c = path.centroid(f);
|
|
46546
|
-
if (!Number.isFinite(c[0])) continue;
|
|
46547
47128
|
const text = regionLabelMode === "abbrev" ? r.id.replace(/^US-/, "") : r.label;
|
|
46548
|
-
|
|
46549
|
-
|
|
46550
|
-
|
|
47129
|
+
if (labelW(text) > x1 - x0 || labelH > y1 - y0) continue;
|
|
47130
|
+
const anchor = r.layer !== "us-state" ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
47131
|
+
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47132
|
+
if (!c || !Number.isFinite(c[0])) continue;
|
|
47133
|
+
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47134
|
+
}
|
|
47135
|
+
for (const seed of insetLabelSeeds) {
|
|
47136
|
+
const text = regionLabelMode === "abbrev" ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47137
|
+
const src = regionById.get(seed.iso);
|
|
47138
|
+
pushRegionLabel(
|
|
47139
|
+
seed.x,
|
|
47140
|
+
seed.y,
|
|
46551
47141
|
text,
|
|
46552
|
-
|
|
46553
|
-
|
|
46554
|
-
|
|
46555
|
-
palette.textOnFillLight,
|
|
46556
|
-
palette.textOnFillDark
|
|
46557
|
-
),
|
|
46558
|
-
halo: true,
|
|
46559
|
-
lineNumber: r.lineNumber
|
|
46560
|
-
});
|
|
47142
|
+
src ? regionFill(src) : neutralFill,
|
|
47143
|
+
seed.lineNumber
|
|
47144
|
+
);
|
|
46561
47145
|
}
|
|
46562
47146
|
}
|
|
46563
47147
|
const poiLabelMode = resolved.directives.poiLabels ?? "auto";
|
|
@@ -46570,68 +47154,106 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46570
47154
|
const src = poiById.get(p.id);
|
|
46571
47155
|
return src?.label ?? src?.name ?? p.id;
|
|
46572
47156
|
};
|
|
46573
|
-
|
|
46574
|
-
|
|
47157
|
+
const poiLabH = FONT * 1.25;
|
|
47158
|
+
const labelInfo = (p) => {
|
|
46575
47159
|
const text = labelText(p);
|
|
46576
|
-
|
|
46577
|
-
|
|
46578
|
-
|
|
46579
|
-
|
|
46580
|
-
|
|
47160
|
+
return { text, w: measureLegendText(text, FONT) };
|
|
47161
|
+
};
|
|
47162
|
+
const pushInline = (p, text, w, side) => {
|
|
47163
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
47164
|
+
obstacles.push({
|
|
47165
|
+
x: side === "right" ? tx : tx - w,
|
|
47166
|
+
y: p.cy - poiLabH / 2,
|
|
47167
|
+
w,
|
|
47168
|
+
h: poiLabH
|
|
47169
|
+
});
|
|
47170
|
+
labels.push({
|
|
47171
|
+
x: tx,
|
|
47172
|
+
y: p.cy + FONT / 3,
|
|
47173
|
+
text,
|
|
47174
|
+
anchor: side === "right" ? "start" : "end",
|
|
47175
|
+
color: palette.text,
|
|
47176
|
+
halo: true,
|
|
47177
|
+
haloColor: palette.bg,
|
|
47178
|
+
poiId: p.id,
|
|
47179
|
+
lineNumber: p.lineNumber
|
|
47180
|
+
});
|
|
47181
|
+
};
|
|
47182
|
+
const inlineFits = (p, w, side) => {
|
|
47183
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
47184
|
+
const rect = {
|
|
47185
|
+
x: side === "right" ? tx : tx - w,
|
|
47186
|
+
y: p.cy - poiLabH / 2,
|
|
47187
|
+
w,
|
|
47188
|
+
h: poiLabH
|
|
47189
|
+
};
|
|
47190
|
+
return rect.x >= 0 && rect.x + rect.w <= width && !collides(rect);
|
|
47191
|
+
};
|
|
47192
|
+
const GROUP_R = 30;
|
|
47193
|
+
const groups = [];
|
|
47194
|
+
for (const p of ordered) {
|
|
47195
|
+
const near = groups.find(
|
|
47196
|
+
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47197
|
+
);
|
|
47198
|
+
if (near) near.push(p);
|
|
47199
|
+
else groups.push([p]);
|
|
47200
|
+
}
|
|
47201
|
+
const ROW_GAP2 = 3;
|
|
47202
|
+
const step = poiLabH + ROW_GAP2;
|
|
47203
|
+
const COL_GAP = 16;
|
|
47204
|
+
const placeColumn = (group) => {
|
|
47205
|
+
const items = group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
47206
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47207
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47208
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47209
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
47210
|
+
const side = right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
47211
|
+
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
47212
|
+
const totalH = items.length * step;
|
|
47213
|
+
let startY = cyMid - totalH / 2;
|
|
47214
|
+
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47215
|
+
items.forEach((o, i) => {
|
|
47216
|
+
const rowCy = startY + i * step + step / 2;
|
|
47217
|
+
obstacles.push({
|
|
47218
|
+
x: side === "right" ? colX : colX - o.w,
|
|
47219
|
+
y: rowCy - poiLabH / 2,
|
|
47220
|
+
w: o.w,
|
|
47221
|
+
h: poiLabH
|
|
47222
|
+
});
|
|
46581
47223
|
labels.push({
|
|
46582
|
-
x:
|
|
46583
|
-
y:
|
|
46584
|
-
text,
|
|
46585
|
-
anchor: "start",
|
|
47224
|
+
x: colX,
|
|
47225
|
+
y: rowCy + FONT / 3,
|
|
47226
|
+
text: o.text,
|
|
47227
|
+
anchor: side === "right" ? "start" : "end",
|
|
46586
47228
|
color: palette.text,
|
|
46587
47229
|
halo: true,
|
|
46588
|
-
|
|
47230
|
+
haloColor: palette.bg,
|
|
47231
|
+
leader: {
|
|
47232
|
+
x1: o.p.cx,
|
|
47233
|
+
y1: o.p.cy,
|
|
47234
|
+
x2: side === "right" ? colX - 2 : colX + 2,
|
|
47235
|
+
y2: rowCy
|
|
47236
|
+
},
|
|
47237
|
+
leaderColor: o.p.fill,
|
|
47238
|
+
poiId: o.p.id,
|
|
47239
|
+
lineNumber: o.p.lineNumber
|
|
46589
47240
|
});
|
|
46590
|
-
|
|
46591
|
-
|
|
46592
|
-
|
|
46593
|
-
|
|
46594
|
-
|
|
46595
|
-
|
|
46596
|
-
|
|
46597
|
-
|
|
46598
|
-
|
|
46599
|
-
|
|
46600
|
-
|
|
46601
|
-
|
|
46602
|
-
|
|
46603
|
-
if (rect.x < 0 || rect.x + rect.w > width || rect.y < 0 || rect.y + rect.h > height) {
|
|
46604
|
-
continue;
|
|
46605
|
-
}
|
|
46606
|
-
if (collides(rect)) continue;
|
|
46607
|
-
obstacles.push(rect);
|
|
46608
|
-
labels.push({
|
|
46609
|
-
x: cx,
|
|
46610
|
-
y: cy + FONT / 3,
|
|
46611
|
-
text,
|
|
46612
|
-
anchor: dx >= 0 ? "start" : "end",
|
|
46613
|
-
color: palette.text,
|
|
46614
|
-
halo: true,
|
|
46615
|
-
leader: { x1: p.cx, y1: p.cy, x2: cx, y2: cy },
|
|
46616
|
-
lineNumber: p.lineNumber
|
|
46617
|
-
});
|
|
46618
|
-
placed = true;
|
|
46619
|
-
break;
|
|
47241
|
+
});
|
|
47242
|
+
};
|
|
47243
|
+
for (const g of groups) {
|
|
47244
|
+
if (g.length === 1) {
|
|
47245
|
+
const p = g[0];
|
|
47246
|
+
const { text, w } = labelInfo(p);
|
|
47247
|
+
if (inlineFits(p, w, "right")) {
|
|
47248
|
+
pushInline(p, text, w, "right");
|
|
47249
|
+
continue;
|
|
47250
|
+
}
|
|
47251
|
+
if (inlineFits(p, w, "left")) {
|
|
47252
|
+
pushInline(p, text, w, "left");
|
|
47253
|
+
continue;
|
|
46620
47254
|
}
|
|
46621
47255
|
}
|
|
46622
|
-
|
|
46623
|
-
pinCounter += 1;
|
|
46624
|
-
pinList.push({ pin: pinCounter, label: text });
|
|
46625
|
-
labels.push({
|
|
46626
|
-
x: p.cx + p.r + 2,
|
|
46627
|
-
y: p.cy - p.r,
|
|
46628
|
-
text: String(pinCounter),
|
|
46629
|
-
anchor: "start",
|
|
46630
|
-
color: palette.text,
|
|
46631
|
-
halo: true,
|
|
46632
|
-
pin: pinCounter,
|
|
46633
|
-
lineNumber: p.lineNumber
|
|
46634
|
-
});
|
|
47256
|
+
placeColumn(g);
|
|
46635
47257
|
}
|
|
46636
47258
|
}
|
|
46637
47259
|
let legend = null;
|
|
@@ -46640,8 +47262,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46640
47262
|
name: g.name,
|
|
46641
47263
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
46642
47264
|
}));
|
|
46643
|
-
|
|
46644
|
-
if (hasAnything) {
|
|
47265
|
+
if (tagGroups.length > 0 || hasRamp) {
|
|
46645
47266
|
legend = {
|
|
46646
47267
|
tagGroups,
|
|
46647
47268
|
activeGroup,
|
|
@@ -46652,20 +47273,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46652
47273
|
},
|
|
46653
47274
|
min: rampMin,
|
|
46654
47275
|
max: rampMax,
|
|
46655
|
-
hue: rampHue
|
|
47276
|
+
hue: rampHue,
|
|
47277
|
+
base: rampBase
|
|
46656
47278
|
}
|
|
46657
|
-
},
|
|
46658
|
-
...sizeVals.length > 0 && {
|
|
46659
|
-
size: {
|
|
46660
|
-
...resolved.directives.sizeMetric !== void 0 && {
|
|
46661
|
-
metric: resolved.directives.sizeMetric
|
|
46662
|
-
},
|
|
46663
|
-
min: sizeMin,
|
|
46664
|
-
max: sizeMax
|
|
46665
|
-
}
|
|
46666
|
-
},
|
|
46667
|
-
...weightVals.length > 0 && {
|
|
46668
|
-
weight: { min: wMin, max: wMax }
|
|
46669
47279
|
}
|
|
46670
47280
|
};
|
|
46671
47281
|
}
|
|
@@ -46673,28 +47283,30 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46673
47283
|
return {
|
|
46674
47284
|
width,
|
|
46675
47285
|
height,
|
|
46676
|
-
background:
|
|
47286
|
+
background: water,
|
|
46677
47287
|
title: resolved.title,
|
|
46678
47288
|
...resolved.subtitle !== void 0 && { subtitle: resolved.subtitle },
|
|
46679
47289
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
46680
47290
|
regions,
|
|
47291
|
+
rivers,
|
|
46681
47292
|
legs,
|
|
46682
47293
|
pois,
|
|
46683
47294
|
labels,
|
|
46684
|
-
|
|
46685
|
-
|
|
47295
|
+
legend,
|
|
47296
|
+
insets,
|
|
47297
|
+
insetRegions
|
|
46686
47298
|
};
|
|
46687
47299
|
}
|
|
46688
|
-
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT,
|
|
47300
|
+
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;
|
|
46689
47301
|
var init_layout15 = __esm({
|
|
46690
47302
|
"src/map/layout.ts"() {
|
|
46691
47303
|
"use strict";
|
|
46692
47304
|
import_d3_geo2 = require("d3-geo");
|
|
46693
47305
|
import_topojson_client2 = require("topojson-client");
|
|
46694
47306
|
init_color_utils();
|
|
46695
|
-
init_tag_groups();
|
|
46696
47307
|
init_label_layout();
|
|
46697
47308
|
init_legend_constants();
|
|
47309
|
+
init_title_constants();
|
|
46698
47310
|
FIT_PAD = 24;
|
|
46699
47311
|
RAMP_FLOOR = 15;
|
|
46700
47312
|
R_DEFAULT = 6;
|
|
@@ -46703,23 +47315,32 @@ var init_layout15 = __esm({
|
|
|
46703
47315
|
W_MIN = 1.25;
|
|
46704
47316
|
W_MAX = 8;
|
|
46705
47317
|
FONT = 11;
|
|
46706
|
-
LEADER_STEP = 14;
|
|
46707
47318
|
COLO_EPS = 1.5;
|
|
47319
|
+
LAND_TINT_LIGHT = 58;
|
|
47320
|
+
LAND_TINT_DARK = 75;
|
|
47321
|
+
TAG_TINT_LIGHT = 60;
|
|
47322
|
+
TAG_TINT_DARK = 68;
|
|
47323
|
+
WATER_TINT = 55;
|
|
47324
|
+
RIVER_WIDTH = 1.3;
|
|
47325
|
+
FOREIGN_TINT_LIGHT = 30;
|
|
47326
|
+
FOREIGN_TINT_DARK = 62;
|
|
46708
47327
|
COLO_R = 9;
|
|
46709
47328
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
46710
47329
|
FAN_STEP = 16;
|
|
46711
|
-
TINY_REGION_AREA = 600;
|
|
46712
47330
|
ARC_CURVE_FRAC = 0.18;
|
|
46713
|
-
|
|
46714
|
-
|
|
46715
|
-
|
|
46716
|
-
|
|
46717
|
-
|
|
46718
|
-
|
|
46719
|
-
|
|
46720
|
-
|
|
46721
|
-
|
|
46722
|
-
|
|
47331
|
+
usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47332
|
+
alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47333
|
+
hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
|
|
47334
|
+
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
47335
|
+
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47336
|
+
"US-AK",
|
|
47337
|
+
"US-HI",
|
|
47338
|
+
"US-AS",
|
|
47339
|
+
"US-GU",
|
|
47340
|
+
"US-MP",
|
|
47341
|
+
"US-PR",
|
|
47342
|
+
"US-VI"
|
|
47343
|
+
]);
|
|
46723
47344
|
}
|
|
46724
47345
|
});
|
|
46725
47346
|
|
|
@@ -46729,7 +47350,7 @@ __export(renderer_exports16, {
|
|
|
46729
47350
|
renderMap: () => renderMap,
|
|
46730
47351
|
renderMapForExport: () => renderMapForExport
|
|
46731
47352
|
});
|
|
46732
|
-
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims) {
|
|
47353
|
+
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
46733
47354
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
46734
47355
|
const width = exportDims?.width ?? container.clientWidth;
|
|
46735
47356
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -46740,27 +47361,29 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46740
47361
|
{ width, height },
|
|
46741
47362
|
{
|
|
46742
47363
|
palette,
|
|
46743
|
-
isDark
|
|
47364
|
+
isDark,
|
|
47365
|
+
...activeGroupOverride !== void 0 && {
|
|
47366
|
+
activeGroup: activeGroupOverride
|
|
47367
|
+
}
|
|
46744
47368
|
}
|
|
46745
47369
|
);
|
|
46746
|
-
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);
|
|
47370
|
+
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);
|
|
46747
47371
|
svg.append("rect").attr("width", width).attr("height", height).attr("fill", layout.background);
|
|
46748
|
-
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
46749
47372
|
const defs = svg.append("defs");
|
|
46750
|
-
|
|
46751
|
-
const haloColor =
|
|
46752
|
-
if (layout.title) {
|
|
46753
|
-
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);
|
|
46754
|
-
}
|
|
46755
|
-
if (layout.subtitle) {
|
|
46756
|
-
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);
|
|
46757
|
-
}
|
|
46758
|
-
if (layout.caption) {
|
|
46759
|
-
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);
|
|
46760
|
-
}
|
|
47373
|
+
const arrowSize = (w) => Math.min(15, 7 + w * 0.95);
|
|
47374
|
+
const haloColor = palette.bg;
|
|
46761
47375
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
46762
|
-
|
|
46763
|
-
const p =
|
|
47376
|
+
const drawRegion = (g, r, strokeWidth) => {
|
|
47377
|
+
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
47378
|
+
if (r.layer !== "base") {
|
|
47379
|
+
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47380
|
+
if (r.score !== void 0) p.attr("data-score", r.score);
|
|
47381
|
+
if (r.tags) {
|
|
47382
|
+
for (const [group, value] of Object.entries(r.tags)) {
|
|
47383
|
+
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
47384
|
+
}
|
|
47385
|
+
}
|
|
47386
|
+
}
|
|
46764
47387
|
if (r.lineNumber >= 0) {
|
|
46765
47388
|
p.attr("data-line-number", r.lineNumber);
|
|
46766
47389
|
if (onClickItem) {
|
|
@@ -46770,11 +47393,31 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46770
47393
|
);
|
|
46771
47394
|
}
|
|
46772
47395
|
}
|
|
47396
|
+
};
|
|
47397
|
+
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
47398
|
+
if (layout.rivers.length) {
|
|
47399
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47400
|
+
for (const r of layout.rivers) {
|
|
47401
|
+
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
47402
|
+
}
|
|
47403
|
+
}
|
|
47404
|
+
if (layout.insets.length) {
|
|
47405
|
+
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47406
|
+
for (const box of layout.insets) {
|
|
47407
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47408
|
+
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");
|
|
47409
|
+
}
|
|
47410
|
+
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
46773
47411
|
}
|
|
46774
47412
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
46775
|
-
|
|
47413
|
+
layout.legs.forEach((leg, i) => {
|
|
46776
47414
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
46777
|
-
if (leg.arrow)
|
|
47415
|
+
if (leg.arrow) {
|
|
47416
|
+
const id = `dgmo-map-arrow-${i}`;
|
|
47417
|
+
const s = arrowSize(leg.width);
|
|
47418
|
+
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);
|
|
47419
|
+
p.attr("marker-end", `url(#${id})`);
|
|
47420
|
+
}
|
|
46778
47421
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
46779
47422
|
emitText(
|
|
46780
47423
|
gLegs,
|
|
@@ -46788,13 +47431,13 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46788
47431
|
LABEL_FONT - 1
|
|
46789
47432
|
);
|
|
46790
47433
|
}
|
|
46791
|
-
}
|
|
47434
|
+
});
|
|
46792
47435
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
46793
47436
|
for (const poi of layout.pois) {
|
|
46794
47437
|
if (poi.isOrigin) {
|
|
46795
47438
|
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);
|
|
46796
47439
|
}
|
|
46797
|
-
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);
|
|
47440
|
+
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);
|
|
46798
47441
|
if (onClickItem) {
|
|
46799
47442
|
c.style("cursor", "pointer").on(
|
|
46800
47443
|
"click",
|
|
@@ -46818,48 +47461,66 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46818
47461
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
46819
47462
|
for (const lab of layout.labels) {
|
|
46820
47463
|
if (lab.leader) {
|
|
46821
|
-
gLabels.append("line").attr("x1", lab.leader.x1).attr("y1", lab.leader.y1).attr("x2", lab.leader.x2).attr("y2", lab.leader.y2).attr(
|
|
47464
|
+
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(
|
|
47465
|
+
"stroke",
|
|
47466
|
+
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47467
|
+
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47468
|
+
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
46822
47469
|
}
|
|
46823
|
-
|
|
46824
|
-
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);
|
|
46825
|
-
}
|
|
46826
|
-
emitText(
|
|
47470
|
+
const t = emitText(
|
|
46827
47471
|
gLabels,
|
|
46828
47472
|
lab.x,
|
|
46829
47473
|
lab.y,
|
|
46830
47474
|
lab.text,
|
|
46831
47475
|
lab.anchor,
|
|
46832
47476
|
lab.color,
|
|
46833
|
-
haloColor,
|
|
47477
|
+
lab.haloColor,
|
|
46834
47478
|
lab.halo,
|
|
46835
47479
|
LABEL_FONT
|
|
46836
47480
|
);
|
|
46837
|
-
|
|
46838
|
-
|
|
46839
|
-
|
|
46840
|
-
"transform",
|
|
46841
|
-
`translate(12, ${height - layout.pinList.length * 14 - 8})`
|
|
46842
|
-
);
|
|
46843
|
-
layout.pinList.forEach((entry, i) => {
|
|
46844
|
-
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}`);
|
|
46845
|
-
});
|
|
47481
|
+
if (lab.poiId !== void 0) {
|
|
47482
|
+
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47483
|
+
}
|
|
46846
47484
|
}
|
|
46847
47485
|
if (layout.legend) {
|
|
46848
47486
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
46849
47487
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
46850
|
-
const
|
|
47488
|
+
const ramp = layout.legend.ramp;
|
|
47489
|
+
const scoreGroup = ramp ? {
|
|
47490
|
+
name: ramp.metric?.trim() || "Score",
|
|
47491
|
+
entries: [],
|
|
47492
|
+
gradient: {
|
|
47493
|
+
min: ramp.min,
|
|
47494
|
+
max: ramp.max,
|
|
47495
|
+
hue: ramp.hue,
|
|
47496
|
+
base: ramp.base
|
|
47497
|
+
}
|
|
47498
|
+
} : null;
|
|
47499
|
+
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47500
|
+
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
46851
47501
|
if (groups.length > 0) {
|
|
46852
47502
|
const config = {
|
|
46853
|
-
groups
|
|
47503
|
+
groups,
|
|
46854
47504
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
46855
47505
|
mode: exportDims ? "export" : "preview",
|
|
46856
|
-
showEmptyGroups: false
|
|
47506
|
+
showEmptyGroups: false,
|
|
47507
|
+
// Keep inactive siblings visible as pills so the user can click to flip
|
|
47508
|
+
// the active colouring dimension (preview only — export shows just the
|
|
47509
|
+
// active group).
|
|
47510
|
+
showInactivePills: true
|
|
46857
47511
|
};
|
|
46858
47512
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
46859
47513
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
46860
47514
|
}
|
|
46861
|
-
|
|
46862
|
-
|
|
47515
|
+
}
|
|
47516
|
+
if (layout.title) {
|
|
47517
|
+
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);
|
|
47518
|
+
}
|
|
47519
|
+
if (layout.subtitle) {
|
|
47520
|
+
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);
|
|
47521
|
+
}
|
|
47522
|
+
if (layout.caption) {
|
|
47523
|
+
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);
|
|
46863
47524
|
}
|
|
46864
47525
|
}
|
|
46865
47526
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
@@ -46870,54 +47531,7 @@ function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
|
46870
47531
|
if (withHalo) {
|
|
46871
47532
|
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7);
|
|
46872
47533
|
}
|
|
46873
|
-
|
|
46874
|
-
function emitExtraLegend(svg, layout, palette, height, bottomGap) {
|
|
46875
|
-
const { legend } = layout;
|
|
46876
|
-
if (!legend) return;
|
|
46877
|
-
if (!legend.ramp && !legend.size && !legend.weight) return;
|
|
46878
|
-
const blocks = [];
|
|
46879
|
-
const g = svg.append("g").attr("class", "dgmo-map-legend-keys").attr("transform", `translate(12, ${height - 56 - bottomGap})`);
|
|
46880
|
-
let xCursor = 0;
|
|
46881
|
-
if (legend.ramp) {
|
|
46882
|
-
const ramp = legend.ramp;
|
|
46883
|
-
blocks.push(() => {
|
|
46884
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46885
|
-
const gradId = "dgmo-map-ramp";
|
|
46886
|
-
const grad = block.append("defs").append("linearGradient").attr("id", gradId).attr("x1", "0%").attr("x2", "100%");
|
|
46887
|
-
grad.append("stop").attr("offset", "0%").attr("stop-color", mix(ramp.hue, palette.bg, 15));
|
|
46888
|
-
grad.append("stop").attr("offset", "100%").attr("stop-color", ramp.hue);
|
|
46889
|
-
block.append("rect").attr("width", 80).attr("height", 8).attr("fill", `url(#${gradId})`);
|
|
46890
|
-
block.append("text").attr("x", 0).attr("y", 22).attr("font-size", 9).attr("fill", palette.textMuted).text(String(ramp.min));
|
|
46891
|
-
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));
|
|
46892
|
-
if (ramp.metric) {
|
|
46893
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(ramp.metric);
|
|
46894
|
-
}
|
|
46895
|
-
xCursor += 110;
|
|
46896
|
-
});
|
|
46897
|
-
}
|
|
46898
|
-
if (legend.size) {
|
|
46899
|
-
const sz = legend.size;
|
|
46900
|
-
blocks.push(() => {
|
|
46901
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46902
|
-
[3, 6, 10].forEach((r, i) => {
|
|
46903
|
-
block.append("circle").attr("cx", i * 26 + r).attr("cy", 8).attr("r", r).attr("fill", "none").attr("stroke", palette.textMuted);
|
|
46904
|
-
});
|
|
46905
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(sz.metric ?? "size");
|
|
46906
|
-
xCursor += 110;
|
|
46907
|
-
});
|
|
46908
|
-
}
|
|
46909
|
-
if (legend.weight) {
|
|
46910
|
-
const wt = legend.weight;
|
|
46911
|
-
blocks.push(() => {
|
|
46912
|
-
const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
|
|
46913
|
-
[1, 3, 6].forEach((w, i) => {
|
|
46914
|
-
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);
|
|
46915
|
-
});
|
|
46916
|
-
block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(wt.metric ?? "weight");
|
|
46917
|
-
xCursor += 110;
|
|
46918
|
-
});
|
|
46919
|
-
}
|
|
46920
|
-
for (const draw of blocks) draw();
|
|
47534
|
+
return t;
|
|
46921
47535
|
}
|
|
46922
47536
|
var d3Selection18, LABEL_FONT;
|
|
46923
47537
|
var init_renderer16 = __esm({
|
|
@@ -56038,6 +56652,8 @@ __export(internal_exports, {
|
|
|
56038
56652
|
looksLikeSitemap: () => looksLikeSitemap,
|
|
56039
56653
|
looksLikeState: () => looksLikeState,
|
|
56040
56654
|
makeDgmoError: () => makeDgmoError,
|
|
56655
|
+
mapBackgroundColor: () => mapBackgroundColor,
|
|
56656
|
+
mapNeutralLandColor: () => mapNeutralLandColor,
|
|
56041
56657
|
matchesContiguously: () => matchesContiguously,
|
|
56042
56658
|
measurePertAnalysisBlock: () => measurePertAnalysisBlock,
|
|
56043
56659
|
migrateContent: () => migrateContent,
|
|
@@ -57822,10 +58438,13 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
57822
58438
|
// keywords, not directives; metadata keys (score/size/label) live in the
|
|
57823
58439
|
// reserved-key registry.
|
|
57824
58440
|
withGlobals({
|
|
57825
|
-
region: {
|
|
58441
|
+
region: {
|
|
58442
|
+
description: "Basemap: us-states (force US state mesh + scoping) | world (inert \u2014 already the default)",
|
|
58443
|
+
values: ["us-states", "world"]
|
|
58444
|
+
},
|
|
57826
58445
|
projection: {
|
|
57827
58446
|
description: "Override the auto projection",
|
|
57828
|
-
values: ["natural-earth", "albers-usa", "mercator"]
|
|
58447
|
+
values: ["equirectangular", "natural-earth", "albers-usa", "mercator"]
|
|
57829
58448
|
},
|
|
57830
58449
|
metric: { description: "Label for the region score ramp" },
|
|
57831
58450
|
"size-metric": { description: "Label for the POI size channel" },
|
|
@@ -59413,6 +60032,8 @@ function formatLineDiff(path, original, migrated) {
|
|
|
59413
60032
|
looksLikeSitemap,
|
|
59414
60033
|
looksLikeState,
|
|
59415
60034
|
makeDgmoError,
|
|
60035
|
+
mapBackgroundColor,
|
|
60036
|
+
mapNeutralLandColor,
|
|
59416
60037
|
matchesContiguously,
|
|
59417
60038
|
measurePertAnalysisBlock,
|
|
59418
60039
|
migrateContent,
|