@diagrammo/dgmo 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.cjs +948 -321
- package/dist/advanced.d.cts +148 -54
- package/dist/advanced.d.ts +148 -54
- package/dist/advanced.js +949 -321
- package/dist/auto.cjs +930 -317
- package/dist/auto.js +117 -117
- package/dist/auto.mjs +934 -318
- package/dist/cli.cjs +160 -160
- package/dist/index.cjs +929 -316
- package/dist/index.js +933 -317
- package/dist/internal.cjs +948 -321
- package/dist/internal.d.cts +148 -54
- package/dist/internal.d.ts +148 -54
- package/dist/internal.js +949 -321
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/lakes.json +1 -0
- package/dist/map-data/na-lakes.json +1 -0
- package/dist/map-data/na-land.json +1 -0
- package/dist/map-data/rivers.json +1 -0
- package/docs/language-reference.md +12 -7
- package/gallery/fixtures/map-region-scope.dgmo +15 -0
- package/package.json +4 -4
- package/src/advanced.ts +7 -6
- package/src/c4/parser.ts +6 -6
- package/src/completion.ts +6 -2
- package/src/echarts.ts +1 -1
- package/src/infra/parser.ts +10 -10
- package/src/journey-map/parser.ts +1 -1
- package/src/label-layout.ts +36 -0
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/README.md +2 -0
- package/src/map/data/lakes.json +1 -0
- package/src/map/data/na-lakes.json +1 -0
- package/src/map/data/na-land.json +1 -0
- package/src/map/data/rivers.json +1 -0
- package/src/map/layout.ts +1022 -205
- package/src/map/load-data.ts +73 -17
- package/src/map/parser.ts +22 -13
- package/src/map/renderer.ts +200 -219
- package/src/map/resolved-types.ts +18 -1
- package/src/map/resolver.ts +79 -7
- package/src/map/types.ts +4 -0
- package/src/mindmap/parser.ts +1 -1
- package/src/sitemap/parser.ts +1 -1
- package/src/utils/legend-d3.ts +42 -0
- package/src/utils/legend-layout.ts +83 -3
- package/src/utils/legend-svg.ts +1 -8
- package/src/utils/legend-types.ts +44 -1
package/dist/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",
|
|
@@ -46166,14 +46303,22 @@ var load_data_exports = {};
|
|
|
46166
46303
|
__export(load_data_exports, {
|
|
46167
46304
|
loadMapData: () => loadMapData
|
|
46168
46305
|
});
|
|
46169
|
-
async function
|
|
46170
|
-
|
|
46306
|
+
async function loadNodeBuiltins() {
|
|
46307
|
+
const [{ readFile }, { fileURLToPath }, { dirname: dirname2, resolve }] = await Promise.all([
|
|
46308
|
+
import("fs/promises"),
|
|
46309
|
+
import("url"),
|
|
46310
|
+
import("path")
|
|
46311
|
+
]);
|
|
46312
|
+
return { readFile, fileURLToPath, dirname: dirname2, resolve };
|
|
46171
46313
|
}
|
|
46172
|
-
async function
|
|
46314
|
+
async function readJson(nb, dir, name) {
|
|
46315
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
46316
|
+
}
|
|
46317
|
+
async function firstExistingDir(nb, baseDir) {
|
|
46173
46318
|
for (const rel of CANDIDATE_DIRS) {
|
|
46174
|
-
const dir =
|
|
46319
|
+
const dir = nb.resolve(baseDir, rel);
|
|
46175
46320
|
try {
|
|
46176
|
-
await
|
|
46321
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
46177
46322
|
return dir;
|
|
46178
46323
|
} catch {
|
|
46179
46324
|
}
|
|
@@ -46189,10 +46334,10 @@ function validate(data) {
|
|
|
46189
46334
|
}
|
|
46190
46335
|
return data;
|
|
46191
46336
|
}
|
|
46192
|
-
function moduleBaseDir() {
|
|
46337
|
+
function moduleBaseDir(nb) {
|
|
46193
46338
|
try {
|
|
46194
46339
|
const url = import_meta.url;
|
|
46195
|
-
if (url) return
|
|
46340
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
46196
46341
|
} catch {
|
|
46197
46342
|
}
|
|
46198
46343
|
if (typeof __dirname !== "undefined") return __dirname;
|
|
@@ -46200,32 +46345,57 @@ function moduleBaseDir() {
|
|
|
46200
46345
|
}
|
|
46201
46346
|
function loadMapData() {
|
|
46202
46347
|
cache ??= (async () => {
|
|
46203
|
-
const
|
|
46204
|
-
const
|
|
46205
|
-
|
|
46206
|
-
|
|
46207
|
-
|
|
46208
|
-
|
|
46348
|
+
const nb = await loadNodeBuiltins();
|
|
46349
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
46350
|
+
const [
|
|
46351
|
+
worldCoarse,
|
|
46352
|
+
worldDetail,
|
|
46353
|
+
usStates,
|
|
46354
|
+
lakes,
|
|
46355
|
+
rivers,
|
|
46356
|
+
naLand,
|
|
46357
|
+
naLakes,
|
|
46358
|
+
gazetteer
|
|
46359
|
+
] = await Promise.all([
|
|
46360
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
46361
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
46362
|
+
readJson(nb, dir, FILES.usStates),
|
|
46363
|
+
// Lakes/rivers/NA assets are optional — older bundles may predate them.
|
|
46364
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
46365
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
46366
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
46367
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
46368
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
46209
46369
|
]);
|
|
46210
|
-
return validate({
|
|
46370
|
+
return validate({
|
|
46371
|
+
worldCoarse,
|
|
46372
|
+
worldDetail,
|
|
46373
|
+
usStates,
|
|
46374
|
+
gazetteer,
|
|
46375
|
+
...lakes && { lakes },
|
|
46376
|
+
...rivers && { rivers },
|
|
46377
|
+
...naLand && { naLand },
|
|
46378
|
+
...naLakes && { naLakes }
|
|
46379
|
+
});
|
|
46211
46380
|
})().catch((e) => {
|
|
46212
46381
|
cache = void 0;
|
|
46213
46382
|
throw e;
|
|
46214
46383
|
});
|
|
46215
46384
|
return cache;
|
|
46216
46385
|
}
|
|
46217
|
-
var
|
|
46386
|
+
var import_meta, FILES, CANDIDATE_DIRS, cache;
|
|
46218
46387
|
var init_load_data = __esm({
|
|
46219
46388
|
"src/map/load-data.ts"() {
|
|
46220
46389
|
"use strict";
|
|
46221
|
-
import_promises = require("fs/promises");
|
|
46222
|
-
import_node_url = require("url");
|
|
46223
|
-
import_node_path = require("path");
|
|
46224
46390
|
import_meta = {};
|
|
46225
46391
|
FILES = {
|
|
46226
46392
|
worldCoarse: "world-coarse.json",
|
|
46227
46393
|
worldDetail: "world-detail.json",
|
|
46228
46394
|
usStates: "us-states.json",
|
|
46395
|
+
lakes: "lakes.json",
|
|
46396
|
+
rivers: "rivers.json",
|
|
46397
|
+
naLand: "na-land.json",
|
|
46398
|
+
naLakes: "na-lakes.json",
|
|
46229
46399
|
gazetteer: "gazetteer.json"
|
|
46230
46400
|
};
|
|
46231
46401
|
CANDIDATE_DIRS = [
|
|
@@ -46253,36 +46423,74 @@ function decodeLayer(topo) {
|
|
|
46253
46423
|
function projectionFor(family) {
|
|
46254
46424
|
switch (family) {
|
|
46255
46425
|
case "albers-usa":
|
|
46256
|
-
return (
|
|
46426
|
+
return usConusProjection();
|
|
46257
46427
|
case "mercator":
|
|
46258
46428
|
return (0, import_d3_geo2.geoMercator)();
|
|
46259
46429
|
case "natural-earth":
|
|
46260
|
-
default:
|
|
46261
46430
|
return (0, import_d3_geo2.geoNaturalEarth1)();
|
|
46431
|
+
case "equirectangular":
|
|
46432
|
+
default:
|
|
46433
|
+
return (0, import_d3_geo2.geoEquirectangular)();
|
|
46262
46434
|
}
|
|
46263
46435
|
}
|
|
46436
|
+
function mapBackgroundColor(palette) {
|
|
46437
|
+
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
46438
|
+
}
|
|
46439
|
+
function mapNeutralLandColor(palette, isDark) {
|
|
46440
|
+
return mix(
|
|
46441
|
+
palette.colors.green,
|
|
46442
|
+
palette.bg,
|
|
46443
|
+
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46444
|
+
);
|
|
46445
|
+
}
|
|
46264
46446
|
function layoutMap(resolved, data, size, opts) {
|
|
46265
46447
|
const { palette, isDark } = opts;
|
|
46266
46448
|
const { width, height } = size;
|
|
46267
|
-
const
|
|
46449
|
+
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46450
|
+
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
46451
|
+
const worldTopo = usCrisp ? data.naLand : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46268
46452
|
const worldLayer = decodeLayer(worldTopo);
|
|
46269
|
-
const usLayer =
|
|
46270
|
-
const
|
|
46271
|
-
const
|
|
46453
|
+
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
46454
|
+
const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
|
|
46455
|
+
const neutralFill = mix(palette.colors.green, palette.bg, landTint);
|
|
46456
|
+
const water = mapBackgroundColor(palette);
|
|
46457
|
+
const usContext = usLayer !== null;
|
|
46458
|
+
const foreignFill = mix(
|
|
46459
|
+
palette.colors.gray,
|
|
46460
|
+
palette.bg,
|
|
46461
|
+
isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46462
|
+
);
|
|
46463
|
+
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46272
46464
|
const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
|
|
46273
46465
|
const scaleOverride = resolved.directives.scale;
|
|
46274
46466
|
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
|
|
46275
46467
|
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
|
|
46276
|
-
const rampHue = palette.
|
|
46468
|
+
const rampHue = palette.colors.red;
|
|
46277
46469
|
const hasRamp = scores.length > 0;
|
|
46278
|
-
const
|
|
46279
|
-
|
|
46280
|
-
|
|
46281
|
-
|
|
46470
|
+
const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
|
|
46471
|
+
const matchColorGroup = (v) => {
|
|
46472
|
+
const lv = v.trim().toLowerCase();
|
|
46473
|
+
if (lv === "none") return null;
|
|
46474
|
+
if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
|
|
46475
|
+
return SCORE_NAME;
|
|
46476
|
+
const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
46477
|
+
return tg ? tg.name : v;
|
|
46478
|
+
};
|
|
46479
|
+
const override = opts.activeGroup;
|
|
46480
|
+
let activeGroup;
|
|
46481
|
+
if (override !== void 0) {
|
|
46482
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
46483
|
+
} else if (resolved.directives.activeTag !== void 0) {
|
|
46484
|
+
activeGroup = matchColorGroup(resolved.directives.activeTag);
|
|
46485
|
+
} else {
|
|
46486
|
+
activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46487
|
+
}
|
|
46488
|
+
const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
|
|
46489
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46282
46490
|
const fillForScore = (s) => {
|
|
46283
46491
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
46284
46492
|
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
46285
|
-
return mix(rampHue,
|
|
46493
|
+
return mix(rampHue, rampBase, pct);
|
|
46286
46494
|
};
|
|
46287
46495
|
const tagFill = (tags, groupName) => {
|
|
46288
46496
|
if (!groupName) return null;
|
|
@@ -46296,40 +46504,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46296
46504
|
(e) => e.value.toLowerCase() === val.toLowerCase()
|
|
46297
46505
|
);
|
|
46298
46506
|
if (!entry?.color) return null;
|
|
46299
|
-
return
|
|
46507
|
+
return mix(
|
|
46508
|
+
entry.color,
|
|
46509
|
+
palette.bg,
|
|
46510
|
+
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46511
|
+
);
|
|
46512
|
+
};
|
|
46513
|
+
const regionFill = (r) => {
|
|
46514
|
+
if (activeIsScore) {
|
|
46515
|
+
return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
|
|
46516
|
+
}
|
|
46517
|
+
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46300
46518
|
};
|
|
46301
46519
|
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 = () => {
|
|
46520
|
+
const extentOutline = () => {
|
|
46308
46521
|
const [[w, s], [e, n]] = resolved.extent;
|
|
46522
|
+
const N = 16;
|
|
46523
|
+
const coords = [];
|
|
46524
|
+
for (let i = 0; i <= N; i++) {
|
|
46525
|
+
const t = i / N;
|
|
46526
|
+
const lon = w + (e - w) * t;
|
|
46527
|
+
const lat = s + (n - s) * t;
|
|
46528
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46529
|
+
}
|
|
46309
46530
|
return {
|
|
46310
46531
|
type: "Feature",
|
|
46311
46532
|
properties: {},
|
|
46312
|
-
geometry: {
|
|
46313
|
-
type: "MultiPoint",
|
|
46314
|
-
coordinates: [
|
|
46315
|
-
[w, s],
|
|
46316
|
-
[e, s],
|
|
46317
|
-
[e, n],
|
|
46318
|
-
[w, n]
|
|
46319
|
-
]
|
|
46320
|
-
}
|
|
46533
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46321
46534
|
};
|
|
46322
46535
|
};
|
|
46323
46536
|
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
|
-
}
|
|
46537
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46538
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46331
46539
|
} else {
|
|
46332
|
-
fitFeatures = [
|
|
46540
|
+
fitFeatures = [extentOutline()];
|
|
46333
46541
|
}
|
|
46334
46542
|
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46335
46543
|
const projection = projectionFor(resolved.projection);
|
|
@@ -46338,32 +46546,311 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46338
46546
|
if (centerLon > 180) centerLon -= 360;
|
|
46339
46547
|
projection.rotate([-centerLon, 0]);
|
|
46340
46548
|
}
|
|
46341
|
-
|
|
46549
|
+
const TITLE_GAP = 16;
|
|
46550
|
+
let topPad = FIT_PAD;
|
|
46551
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
46552
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46553
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP);
|
|
46554
|
+
}
|
|
46555
|
+
const fitBox = [
|
|
46556
|
+
[FIT_PAD, topPad],
|
|
46342
46557
|
[
|
|
46343
|
-
|
|
46344
|
-
|
|
46345
|
-
|
|
46346
|
-
|
|
46347
|
-
|
|
46348
|
-
|
|
46349
|
-
|
|
46350
|
-
|
|
46351
|
-
|
|
46352
|
-
|
|
46558
|
+
Math.max(FIT_PAD + 1, width - FIT_PAD),
|
|
46559
|
+
Math.max(topPad + 1, height - FIT_PAD)
|
|
46560
|
+
]
|
|
46561
|
+
];
|
|
46562
|
+
projection.fitExtent(fitBox, fitTarget);
|
|
46563
|
+
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
46564
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46565
|
+
let path;
|
|
46566
|
+
let project;
|
|
46567
|
+
if (fitIsGlobal) {
|
|
46568
|
+
const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
|
|
46569
|
+
const bx0 = cb[0][0];
|
|
46570
|
+
const by0 = cb[0][1];
|
|
46571
|
+
const cw = cb[1][0] - bx0;
|
|
46572
|
+
const ch = cb[1][1] - by0;
|
|
46573
|
+
const ox = fitBox[0][0];
|
|
46574
|
+
const oy = fitBox[0][1];
|
|
46575
|
+
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46576
|
+
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
46577
|
+
const stretch = (x, y) => [
|
|
46578
|
+
ox + (x - bx0) * sx,
|
|
46579
|
+
oy + (y - by0) * sy
|
|
46580
|
+
];
|
|
46581
|
+
const baseProjection = projection;
|
|
46582
|
+
const tx = (0, import_d3_geo2.geoTransform)({
|
|
46583
|
+
point(x, y) {
|
|
46584
|
+
const [px, py] = stretch(x, y);
|
|
46585
|
+
this.stream.point(px, py);
|
|
46586
|
+
}
|
|
46587
|
+
});
|
|
46588
|
+
path = (0, import_d3_geo2.geoPath)({
|
|
46589
|
+
stream: (s) => baseProjection.stream(
|
|
46590
|
+
tx.stream(s)
|
|
46591
|
+
)
|
|
46592
|
+
});
|
|
46593
|
+
project = (lon, lat) => {
|
|
46594
|
+
const p = baseProjection([lon, lat]);
|
|
46595
|
+
return p ? stretch(p[0], p[1]) : null;
|
|
46596
|
+
};
|
|
46597
|
+
} else {
|
|
46598
|
+
path = (0, import_d3_geo2.geoPath)(projection);
|
|
46599
|
+
project = (lon, lat) => projection([lon, lat]) ?? null;
|
|
46600
|
+
}
|
|
46601
|
+
const insets = [];
|
|
46602
|
+
const insetRegions = [];
|
|
46603
|
+
const insetLabelSeeds = [];
|
|
46604
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46605
|
+
const PAD = 8;
|
|
46606
|
+
const GAP = 12;
|
|
46607
|
+
const yB = height - FIT_PAD;
|
|
46608
|
+
const BW = 8;
|
|
46609
|
+
const coast = /* @__PURE__ */ new Map();
|
|
46610
|
+
const addPt = (lon, lat) => {
|
|
46611
|
+
const p = projection([lon, lat]);
|
|
46612
|
+
if (!p) return;
|
|
46613
|
+
const bi = Math.floor(p[0] / BW);
|
|
46614
|
+
const cur = coast.get(bi);
|
|
46615
|
+
if (cur === void 0 || p[1] > cur) coast.set(bi, p[1]);
|
|
46616
|
+
};
|
|
46617
|
+
const walk = (co) => {
|
|
46618
|
+
if (Array.isArray(co) && typeof co[0] === "number")
|
|
46619
|
+
addPt(co[0], co[1]);
|
|
46620
|
+
else if (Array.isArray(co)) for (const c of co) walk(c);
|
|
46621
|
+
};
|
|
46622
|
+
for (const [iso, f] of usLayer) {
|
|
46623
|
+
if (US_NON_CONUS.has(iso)) continue;
|
|
46624
|
+
walk(f.geometry.coordinates);
|
|
46625
|
+
}
|
|
46626
|
+
const at = (x) => {
|
|
46627
|
+
const bi = Math.floor(x / BW);
|
|
46628
|
+
let y = -Infinity;
|
|
46629
|
+
for (let k = bi - 1; k <= bi + 1; k++) {
|
|
46630
|
+
const v = coast.get(k);
|
|
46631
|
+
if (v !== void 0 && v > y) y = v;
|
|
46632
|
+
}
|
|
46633
|
+
return y;
|
|
46634
|
+
};
|
|
46635
|
+
const coastTop = (x0, xr) => {
|
|
46636
|
+
const n = 24;
|
|
46637
|
+
const pts = [];
|
|
46638
|
+
let maxY = -Infinity;
|
|
46639
|
+
for (let i = 0; i <= n; i++) {
|
|
46640
|
+
const x = x0 + (xr - x0) * i / n;
|
|
46641
|
+
const y = at(x);
|
|
46642
|
+
if (y > -Infinity) {
|
|
46643
|
+
pts.push([x, y]);
|
|
46644
|
+
if (y > maxY) maxY = y;
|
|
46645
|
+
}
|
|
46646
|
+
}
|
|
46647
|
+
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46648
|
+
let m = 0;
|
|
46649
|
+
if (pts.length >= 2) {
|
|
46650
|
+
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46651
|
+
for (const [x, y] of pts) {
|
|
46652
|
+
sx += x;
|
|
46653
|
+
sy += y;
|
|
46654
|
+
sxx += x * x;
|
|
46655
|
+
sxy += x * y;
|
|
46656
|
+
}
|
|
46657
|
+
const den = pts.length * sxx - sx * sx;
|
|
46658
|
+
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46659
|
+
}
|
|
46660
|
+
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46661
|
+
let c = -Infinity;
|
|
46662
|
+
for (const [x, y] of pts) {
|
|
46663
|
+
const need = y - m * x + GAP;
|
|
46664
|
+
if (need > c) c = need;
|
|
46665
|
+
}
|
|
46666
|
+
return (x) => m * x + c;
|
|
46667
|
+
};
|
|
46668
|
+
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46669
|
+
const f = usLayer.get(iso);
|
|
46670
|
+
if (!f) return boxX;
|
|
46671
|
+
const x0 = boxX;
|
|
46672
|
+
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46673
|
+
if (iw < 24) return boxX;
|
|
46674
|
+
const xr = x0 + iw + 2 * PAD;
|
|
46675
|
+
const top = coastTop(x0, xr);
|
|
46676
|
+
const yL = top(x0);
|
|
46677
|
+
const yR = top(xr);
|
|
46678
|
+
proj.fitWidth(iw, f);
|
|
46679
|
+
const bb = (0, import_d3_geo2.geoPath)(proj).bounds(f);
|
|
46680
|
+
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46681
|
+
const needH = sh + 2 * PAD;
|
|
46682
|
+
let topFit = Math.max(yL, yR);
|
|
46683
|
+
const bottom = Math.min(topFit + needH, yB);
|
|
46684
|
+
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46685
|
+
const lift = topFit - Math.max(yL, yR);
|
|
46686
|
+
const topL = yL + lift;
|
|
46687
|
+
const topR = yR + lift;
|
|
46688
|
+
proj.fitExtent(
|
|
46689
|
+
[
|
|
46690
|
+
[x0 + PAD, topFit + PAD],
|
|
46691
|
+
[xr - PAD, bottom - PAD]
|
|
46692
|
+
],
|
|
46693
|
+
f
|
|
46694
|
+
);
|
|
46695
|
+
const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
|
|
46696
|
+
if (!d) return xr;
|
|
46697
|
+
const r = regionById.get(iso);
|
|
46698
|
+
let fill2 = neutralFill;
|
|
46699
|
+
let lineNumber = -1;
|
|
46700
|
+
if (r?.layer === "us-state") {
|
|
46701
|
+
fill2 = regionFill(r);
|
|
46702
|
+
lineNumber = r.lineNumber;
|
|
46703
|
+
}
|
|
46704
|
+
insets.push({
|
|
46705
|
+
x: x0,
|
|
46706
|
+
y: Math.min(topL, topR),
|
|
46707
|
+
w: xr - x0,
|
|
46708
|
+
h: bottom - Math.min(topL, topR),
|
|
46709
|
+
points: [
|
|
46710
|
+
[x0, topL],
|
|
46711
|
+
[xr, topR],
|
|
46712
|
+
[xr, bottom],
|
|
46713
|
+
[x0, bottom]
|
|
46714
|
+
]
|
|
46715
|
+
});
|
|
46716
|
+
insetRegions.push({
|
|
46717
|
+
id: iso,
|
|
46718
|
+
d,
|
|
46719
|
+
fill: fill2,
|
|
46720
|
+
stroke: regionStroke,
|
|
46721
|
+
lineNumber,
|
|
46722
|
+
layer: "us-state",
|
|
46723
|
+
...r?.score !== void 0 && { score: r.score },
|
|
46724
|
+
...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46725
|
+
});
|
|
46726
|
+
const ctr = (0, import_d3_geo2.geoPath)(proj).centroid(f);
|
|
46727
|
+
if (Number.isFinite(ctr[0])) {
|
|
46728
|
+
const name = f.properties?.name ?? iso;
|
|
46729
|
+
insetLabelSeeds.push({ x: ctr[0], y: ctr[1], iso, name, lineNumber });
|
|
46730
|
+
}
|
|
46731
|
+
return xr;
|
|
46732
|
+
};
|
|
46733
|
+
const akRight = placeInset(
|
|
46734
|
+
"US-AK",
|
|
46735
|
+
alaskaProjection(),
|
|
46736
|
+
FIT_PAD,
|
|
46737
|
+
width * 0.15
|
|
46738
|
+
);
|
|
46739
|
+
placeInset("US-HI", hawaiiProjection(), akRight + 24, width * 0.1);
|
|
46740
|
+
}
|
|
46741
|
+
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46742
|
+
const cullExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
|
|
46743
|
+
const [[exW, exS], [exE, exN]] = cullExtent;
|
|
46744
|
+
const lonSpan = exE - exW;
|
|
46745
|
+
const latSpan = exN - exS;
|
|
46746
|
+
const isGlobalView = lonSpan >= 270 || latSpan >= 130;
|
|
46747
|
+
const padLon = Math.max(8, lonSpan * 0.35);
|
|
46748
|
+
const padLat = Math.max(8, latSpan * 0.35);
|
|
46749
|
+
const vW = exW - padLon;
|
|
46750
|
+
const vE = exE + padLon;
|
|
46751
|
+
const vS = exS - padLat;
|
|
46752
|
+
const vN = exN + padLat;
|
|
46753
|
+
const vLonCenter = (exW + exE) / 2;
|
|
46754
|
+
const normLon = (lon) => {
|
|
46755
|
+
let L = lon;
|
|
46756
|
+
while (L < vLonCenter - 180) L += 360;
|
|
46757
|
+
while (L > vLonCenter + 180) L -= 360;
|
|
46758
|
+
return L;
|
|
46759
|
+
};
|
|
46760
|
+
const ringOverlapsView = (ring) => {
|
|
46761
|
+
let anyIn = false;
|
|
46762
|
+
let loMin = Infinity, loMax = -Infinity, laMin = Infinity, laMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
46763
|
+
for (const [rawLon, lat] of ring) {
|
|
46764
|
+
const lon = normLon(rawLon);
|
|
46765
|
+
if (lon >= vW && lon <= vE && lat >= vS && lat <= vN) anyIn = true;
|
|
46766
|
+
if (lon < loMin) loMin = lon;
|
|
46767
|
+
if (lon > loMax) loMax = lon;
|
|
46768
|
+
if (rawLon < rawMin) rawMin = rawLon;
|
|
46769
|
+
if (rawLon > rawMax) rawMax = rawLon;
|
|
46770
|
+
if (lat < laMin) laMin = lat;
|
|
46771
|
+
if (lat > laMax) laMax = lat;
|
|
46772
|
+
}
|
|
46773
|
+
if (loMax - loMin > 270) return false;
|
|
46774
|
+
if (rawMax - rawMin > 180 && loMax - loMin < 90) return false;
|
|
46775
|
+
if (anyIn) return true;
|
|
46776
|
+
if (loMax - loMin > 180) return false;
|
|
46777
|
+
return !(loMax < vW || loMin > vE || laMax < vS || laMin > vN);
|
|
46778
|
+
};
|
|
46779
|
+
const cullFeatureToView = (f) => {
|
|
46780
|
+
if (isGlobalView) return f;
|
|
46781
|
+
const g = f.geometry;
|
|
46782
|
+
if (!g) return f;
|
|
46783
|
+
if (g.type === "Polygon") {
|
|
46784
|
+
const ring = g.coordinates[0];
|
|
46785
|
+
return ringOverlapsView(ring) ? f : null;
|
|
46786
|
+
}
|
|
46787
|
+
if (g.type === "MultiPolygon") {
|
|
46788
|
+
const polys = g.coordinates;
|
|
46789
|
+
const keep = polys.filter(
|
|
46790
|
+
(p) => ringOverlapsView(p[0])
|
|
46791
|
+
);
|
|
46792
|
+
if (!keep.length) return null;
|
|
46793
|
+
if (keep.length === polys.length) return f;
|
|
46794
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46795
|
+
}
|
|
46796
|
+
return f;
|
|
46797
|
+
};
|
|
46798
|
+
const SEAM_SLIVER_MAX_SPAN = 100;
|
|
46799
|
+
const ringIsFrameFiller = (ring) => {
|
|
46800
|
+
const lons = ring.map(([lon]) => lon).sort((a, b) => a - b);
|
|
46801
|
+
if (lons.length < 2) return false;
|
|
46802
|
+
let maxGap = -1;
|
|
46803
|
+
let gapIdx = 0;
|
|
46804
|
+
for (let i = 1; i < lons.length; i++) {
|
|
46805
|
+
const g = lons[i] - lons[i - 1];
|
|
46806
|
+
if (g > maxGap) {
|
|
46807
|
+
maxGap = g;
|
|
46808
|
+
gapIdx = i;
|
|
46809
|
+
}
|
|
46810
|
+
}
|
|
46811
|
+
const wrapGap = lons[0] + 360 - lons[lons.length - 1];
|
|
46812
|
+
if (wrapGap >= maxGap) return false;
|
|
46813
|
+
const span = 360 - maxGap;
|
|
46814
|
+
const east = lons[gapIdx - 1] + 360;
|
|
46815
|
+
return east > 180 && span < SEAM_SLIVER_MAX_SPAN;
|
|
46816
|
+
};
|
|
46817
|
+
const dropFrameFillers = (f) => {
|
|
46818
|
+
const g = f.geometry;
|
|
46819
|
+
if (!g) return f;
|
|
46820
|
+
if (g.type === "Polygon") {
|
|
46821
|
+
const ring = g.coordinates[0];
|
|
46822
|
+
return ringIsFrameFiller(ring) ? null : f;
|
|
46823
|
+
}
|
|
46824
|
+
if (g.type === "MultiPolygon") {
|
|
46825
|
+
const polys = g.coordinates;
|
|
46826
|
+
const keep = polys.filter(
|
|
46827
|
+
(p) => !ringIsFrameFiller(p[0])
|
|
46828
|
+
);
|
|
46829
|
+
if (!keep.length) return null;
|
|
46830
|
+
if (keep.length === polys.length) return f;
|
|
46831
|
+
return { ...f, geometry: { ...g, coordinates: keep } };
|
|
46832
|
+
}
|
|
46833
|
+
return f;
|
|
46834
|
+
};
|
|
46353
46835
|
const regions = [];
|
|
46354
|
-
const pushRegionLayer = (layerFeatures, layerKind) => {
|
|
46836
|
+
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46355
46837
|
for (const [iso, f] of layerFeatures) {
|
|
46356
|
-
|
|
46357
|
-
|
|
46838
|
+
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
46839
|
+
continue;
|
|
46840
|
+
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46358
46841
|
const r = regionById.get(iso);
|
|
46842
|
+
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
46843
|
+
if (!viewF) continue;
|
|
46844
|
+
const d = path(viewF) ?? "";
|
|
46845
|
+
if (!d) continue;
|
|
46359
46846
|
const isThisLayer = r?.layer === layerKind;
|
|
46360
|
-
|
|
46847
|
+
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46848
|
+
let fill2 = isForeign ? foreignFill : neutralFill;
|
|
46361
46849
|
let label;
|
|
46362
46850
|
let lineNumber = -1;
|
|
46363
46851
|
let layer = "base";
|
|
46364
46852
|
if (isThisLayer) {
|
|
46365
|
-
|
|
46366
|
-
else fill2 = tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46853
|
+
fill2 = regionFill(r);
|
|
46367
46854
|
lineNumber = r.lineNumber;
|
|
46368
46855
|
layer = layerKind;
|
|
46369
46856
|
label = r.name;
|
|
@@ -46375,12 +46862,42 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46375
46862
|
stroke: regionStroke,
|
|
46376
46863
|
lineNumber,
|
|
46377
46864
|
layer,
|
|
46378
|
-
...label !== void 0 && { label }
|
|
46865
|
+
...label !== void 0 && { label },
|
|
46866
|
+
...isThisLayer && r.score !== void 0 && { score: r.score },
|
|
46867
|
+
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46379
46868
|
});
|
|
46380
46869
|
}
|
|
46381
46870
|
};
|
|
46382
|
-
pushRegionLayer(worldLayer, "country");
|
|
46383
|
-
if (usLayer) pushRegionLayer(usLayer, "us-state");
|
|
46871
|
+
pushRegionLayer(worldLayer, "country", !isGlobalView);
|
|
46872
|
+
if (usLayer) pushRegionLayer(usLayer, "us-state", !conusFit && !isGlobalView);
|
|
46873
|
+
const lakesTopo = usCrisp && data.naLakes ? data.naLakes : data.lakes;
|
|
46874
|
+
if (lakesTopo) {
|
|
46875
|
+
for (const [, f] of decodeLayer(lakesTopo)) {
|
|
46876
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46877
|
+
if (!viewF) continue;
|
|
46878
|
+
const d = path(viewF) ?? "";
|
|
46879
|
+
if (!d) continue;
|
|
46880
|
+
regions.push({
|
|
46881
|
+
id: "lake",
|
|
46882
|
+
d,
|
|
46883
|
+
fill: water,
|
|
46884
|
+
stroke: "none",
|
|
46885
|
+
lineNumber: -1,
|
|
46886
|
+
layer: "base"
|
|
46887
|
+
});
|
|
46888
|
+
}
|
|
46889
|
+
}
|
|
46890
|
+
const riverColor = water;
|
|
46891
|
+
const rivers = [];
|
|
46892
|
+
if (data.rivers) {
|
|
46893
|
+
for (const [, f] of decodeLayer(data.rivers)) {
|
|
46894
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46895
|
+
if (!viewF) continue;
|
|
46896
|
+
const d = path(viewF) ?? "";
|
|
46897
|
+
if (!d) continue;
|
|
46898
|
+
rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
|
|
46899
|
+
}
|
|
46900
|
+
}
|
|
46384
46901
|
const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
46385
46902
|
const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
|
|
46386
46903
|
const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
|
|
@@ -46401,8 +46918,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46401
46918
|
if (hex) return { fill: hex, stroke: mix(hex, palette.text, 18) };
|
|
46402
46919
|
}
|
|
46403
46920
|
return {
|
|
46404
|
-
fill: palette.
|
|
46405
|
-
stroke: mix(palette.
|
|
46921
|
+
fill: palette.colors.orange,
|
|
46922
|
+
stroke: mix(palette.colors.orange, palette.text, 18)
|
|
46406
46923
|
};
|
|
46407
46924
|
};
|
|
46408
46925
|
const routeNumberById = /* @__PURE__ */ new Map();
|
|
@@ -46440,7 +46957,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46440
46957
|
cy += Math.sin(ang) * COLO_R;
|
|
46441
46958
|
}
|
|
46442
46959
|
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
46443
|
-
poiScreen.set(e.p.id, { cx, cy });
|
|
46960
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
46444
46961
|
const num = routeNumberById.get(e.p.id);
|
|
46445
46962
|
pois.push({
|
|
46446
46963
|
id: e.p.id,
|
|
@@ -46457,17 +46974,36 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46457
46974
|
});
|
|
46458
46975
|
}
|
|
46459
46976
|
const legs = [];
|
|
46977
|
+
const RIM_GAP = 1.5;
|
|
46460
46978
|
const legPath = (a, b, curved, offset) => {
|
|
46461
|
-
if (!curved && offset === 0) return `M${a.cx},${a.cy}L${b.cx},${b.cy}`;
|
|
46462
46979
|
const mx = (a.cx + b.cx) / 2;
|
|
46463
46980
|
const my = (a.cy + b.cy) / 2;
|
|
46464
46981
|
const dx = b.cx - a.cx;
|
|
46465
46982
|
const dy = b.cy - a.cy;
|
|
46466
46983
|
const len = Math.hypot(dx, dy) || 1;
|
|
46984
|
+
const trimA = Math.min(a.r + RIM_GAP, len * 0.45);
|
|
46985
|
+
const trimB = Math.min(b.r + RIM_GAP, len * 0.45);
|
|
46986
|
+
if (!curved && offset === 0) {
|
|
46987
|
+
const ux = dx / len;
|
|
46988
|
+
const uy = dy / len;
|
|
46989
|
+
const ax2 = a.cx + ux * trimA;
|
|
46990
|
+
const ay2 = a.cy + uy * trimA;
|
|
46991
|
+
const bx2 = b.cx - ux * trimB;
|
|
46992
|
+
const by2 = b.cy - uy * trimB;
|
|
46993
|
+
return `M${ax2},${ay2}L${bx2},${by2}`;
|
|
46994
|
+
}
|
|
46467
46995
|
const nx = -dy / len;
|
|
46468
46996
|
const ny = dx / len;
|
|
46469
46997
|
const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
|
|
46470
|
-
|
|
46998
|
+
const px = mx + nx * bow;
|
|
46999
|
+
const py = my + ny * bow;
|
|
47000
|
+
const ta = Math.hypot(px - a.cx, py - a.cy) || 1;
|
|
47001
|
+
const tb = Math.hypot(b.cx - px, b.cy - py) || 1;
|
|
47002
|
+
const ax = a.cx + (px - a.cx) / ta * trimA;
|
|
47003
|
+
const ay = a.cy + (py - a.cy) / ta * trimA;
|
|
47004
|
+
const bx = b.cx - (b.cx - px) / tb * trimB;
|
|
47005
|
+
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
47006
|
+
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
46471
47007
|
};
|
|
46472
47008
|
for (const rt of resolved.routes) {
|
|
46473
47009
|
const curved = rt.meta["style"] === "arc";
|
|
@@ -46478,7 +47014,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46478
47014
|
legs.push({
|
|
46479
47015
|
d: legPath(a, b, curved, 0),
|
|
46480
47016
|
width: W_MIN,
|
|
46481
|
-
color: mix(palette.text, palette.bg,
|
|
47017
|
+
color: mix(palette.text, palette.bg, 72),
|
|
46482
47018
|
arrow: true,
|
|
46483
47019
|
lineNumber: rt.lineNumber
|
|
46484
47020
|
});
|
|
@@ -46514,7 +47050,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46514
47050
|
legs.push({
|
|
46515
47051
|
d: legPath(a, b, curved, offset),
|
|
46516
47052
|
width: widthFor(e),
|
|
46517
|
-
color: mix(palette.text, palette.bg,
|
|
47053
|
+
color: mix(palette.text, palette.bg, 66),
|
|
46518
47054
|
arrow: e.directed,
|
|
46519
47055
|
lineNumber: e.lineNumber,
|
|
46520
47056
|
...e.label !== void 0 && {
|
|
@@ -46526,38 +47062,92 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46526
47062
|
});
|
|
46527
47063
|
}
|
|
46528
47064
|
const labels = [];
|
|
46529
|
-
const pinList = [];
|
|
46530
47065
|
const obstacles = [];
|
|
46531
47066
|
const markers = pois.map((p) => ({
|
|
46532
47067
|
cx: p.cx,
|
|
46533
47068
|
cy: p.cy,
|
|
46534
47069
|
r: p.r
|
|
46535
47070
|
}));
|
|
46536
|
-
const
|
|
47071
|
+
const legSegments = [];
|
|
47072
|
+
for (const leg of legs) {
|
|
47073
|
+
const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
47074
|
+
leg.d
|
|
47075
|
+
);
|
|
47076
|
+
if (!m) continue;
|
|
47077
|
+
const x0 = +m[1];
|
|
47078
|
+
const y0 = +m[2];
|
|
47079
|
+
if (m[3] !== void 0) {
|
|
47080
|
+
legSegments.push([x0, y0, +m[3], +m[4]]);
|
|
47081
|
+
} else {
|
|
47082
|
+
const cx = +m[5];
|
|
47083
|
+
const cy = +m[6];
|
|
47084
|
+
const ex = +m[7];
|
|
47085
|
+
const ey = +m[8];
|
|
47086
|
+
const N = 8;
|
|
47087
|
+
let px = x0;
|
|
47088
|
+
let py = y0;
|
|
47089
|
+
for (let i = 1; i <= N; i++) {
|
|
47090
|
+
const t = i / N;
|
|
47091
|
+
const u = 1 - t;
|
|
47092
|
+
const qx = u * u * x0 + 2 * u * t * cx + t * t * ex;
|
|
47093
|
+
const qy = u * u * y0 + 2 * u * t * cy + t * t * ey;
|
|
47094
|
+
legSegments.push([px, py, qx, qy]);
|
|
47095
|
+
px = qx;
|
|
47096
|
+
py = qy;
|
|
47097
|
+
}
|
|
47098
|
+
}
|
|
47099
|
+
}
|
|
47100
|
+
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
47101
|
const regionLabelMode = resolved.directives.regionLabels ?? "off";
|
|
47102
|
+
const LABEL_PADX = 6;
|
|
47103
|
+
const LABEL_PADY = 3;
|
|
47104
|
+
const labelW = (text) => measureLegendText(text, FONT) + 2 * LABEL_PADX;
|
|
47105
|
+
const labelH = FONT + 2 * LABEL_PADY;
|
|
47106
|
+
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
47107
|
+
const color = contrastText(
|
|
47108
|
+
fill2,
|
|
47109
|
+
palette.textOnFillLight,
|
|
47110
|
+
palette.textOnFillDark
|
|
47111
|
+
);
|
|
47112
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47113
|
+
labels.push({
|
|
47114
|
+
x,
|
|
47115
|
+
y,
|
|
47116
|
+
text,
|
|
47117
|
+
anchor: "middle",
|
|
47118
|
+
color,
|
|
47119
|
+
halo: true,
|
|
47120
|
+
haloColor,
|
|
47121
|
+
lineNumber
|
|
47122
|
+
});
|
|
47123
|
+
};
|
|
47124
|
+
const WORLD_LABEL_ANCHORS = {
|
|
47125
|
+
US: [-98.5, 39.5]
|
|
47126
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
47127
|
+
};
|
|
46538
47128
|
if (regionLabelMode === "full" || regionLabelMode === "abbrev") {
|
|
46539
47129
|
for (const r of regions) {
|
|
46540
47130
|
if (r.layer === "base" || r.label === void 0) continue;
|
|
46541
47131
|
const f = r.layer === "us-state" ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
46542
47132
|
if (!f) continue;
|
|
46543
47133
|
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
47134
|
const text = regionLabelMode === "abbrev" ? r.id.replace(/^US-/, "") : r.label;
|
|
46548
|
-
|
|
46549
|
-
|
|
46550
|
-
|
|
47135
|
+
if (labelW(text) > x1 - x0 || labelH > y1 - y0) continue;
|
|
47136
|
+
const anchor = r.layer !== "us-state" ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
47137
|
+
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47138
|
+
if (!c || !Number.isFinite(c[0])) continue;
|
|
47139
|
+
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47140
|
+
}
|
|
47141
|
+
for (const seed of insetLabelSeeds) {
|
|
47142
|
+
const text = regionLabelMode === "abbrev" ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47143
|
+
const src = regionById.get(seed.iso);
|
|
47144
|
+
pushRegionLabel(
|
|
47145
|
+
seed.x,
|
|
47146
|
+
seed.y,
|
|
46551
47147
|
text,
|
|
46552
|
-
|
|
46553
|
-
|
|
46554
|
-
|
|
46555
|
-
palette.textOnFillLight,
|
|
46556
|
-
palette.textOnFillDark
|
|
46557
|
-
),
|
|
46558
|
-
halo: true,
|
|
46559
|
-
lineNumber: r.lineNumber
|
|
46560
|
-
});
|
|
47148
|
+
src ? regionFill(src) : neutralFill,
|
|
47149
|
+
seed.lineNumber
|
|
47150
|
+
);
|
|
46561
47151
|
}
|
|
46562
47152
|
}
|
|
46563
47153
|
const poiLabelMode = resolved.directives.poiLabels ?? "auto";
|
|
@@ -46570,68 +47160,106 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46570
47160
|
const src = poiById.get(p.id);
|
|
46571
47161
|
return src?.label ?? src?.name ?? p.id;
|
|
46572
47162
|
};
|
|
46573
|
-
|
|
46574
|
-
|
|
47163
|
+
const poiLabH = FONT * 1.25;
|
|
47164
|
+
const labelInfo = (p) => {
|
|
46575
47165
|
const text = labelText(p);
|
|
46576
|
-
|
|
46577
|
-
|
|
46578
|
-
|
|
46579
|
-
|
|
46580
|
-
|
|
47166
|
+
return { text, w: measureLegendText(text, FONT) };
|
|
47167
|
+
};
|
|
47168
|
+
const pushInline = (p, text, w, side) => {
|
|
47169
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
47170
|
+
obstacles.push({
|
|
47171
|
+
x: side === "right" ? tx : tx - w,
|
|
47172
|
+
y: p.cy - poiLabH / 2,
|
|
47173
|
+
w,
|
|
47174
|
+
h: poiLabH
|
|
47175
|
+
});
|
|
47176
|
+
labels.push({
|
|
47177
|
+
x: tx,
|
|
47178
|
+
y: p.cy + FONT / 3,
|
|
47179
|
+
text,
|
|
47180
|
+
anchor: side === "right" ? "start" : "end",
|
|
47181
|
+
color: palette.text,
|
|
47182
|
+
halo: true,
|
|
47183
|
+
haloColor: palette.bg,
|
|
47184
|
+
poiId: p.id,
|
|
47185
|
+
lineNumber: p.lineNumber
|
|
47186
|
+
});
|
|
47187
|
+
};
|
|
47188
|
+
const inlineFits = (p, w, side) => {
|
|
47189
|
+
const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
|
|
47190
|
+
const rect = {
|
|
47191
|
+
x: side === "right" ? tx : tx - w,
|
|
47192
|
+
y: p.cy - poiLabH / 2,
|
|
47193
|
+
w,
|
|
47194
|
+
h: poiLabH
|
|
47195
|
+
};
|
|
47196
|
+
return rect.x >= 0 && rect.x + rect.w <= width && !collides(rect);
|
|
47197
|
+
};
|
|
47198
|
+
const GROUP_R = 30;
|
|
47199
|
+
const groups = [];
|
|
47200
|
+
for (const p of ordered) {
|
|
47201
|
+
const near = groups.find(
|
|
47202
|
+
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47203
|
+
);
|
|
47204
|
+
if (near) near.push(p);
|
|
47205
|
+
else groups.push([p]);
|
|
47206
|
+
}
|
|
47207
|
+
const ROW_GAP2 = 3;
|
|
47208
|
+
const step = poiLabH + ROW_GAP2;
|
|
47209
|
+
const COL_GAP = 16;
|
|
47210
|
+
const placeColumn = (group) => {
|
|
47211
|
+
const items = group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
47212
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47213
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47214
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47215
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
47216
|
+
const side = right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
47217
|
+
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
47218
|
+
const totalH = items.length * step;
|
|
47219
|
+
let startY = cyMid - totalH / 2;
|
|
47220
|
+
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47221
|
+
items.forEach((o, i) => {
|
|
47222
|
+
const rowCy = startY + i * step + step / 2;
|
|
47223
|
+
obstacles.push({
|
|
47224
|
+
x: side === "right" ? colX : colX - o.w,
|
|
47225
|
+
y: rowCy - poiLabH / 2,
|
|
47226
|
+
w: o.w,
|
|
47227
|
+
h: poiLabH
|
|
47228
|
+
});
|
|
46581
47229
|
labels.push({
|
|
46582
|
-
x:
|
|
46583
|
-
y:
|
|
46584
|
-
text,
|
|
46585
|
-
anchor: "start",
|
|
47230
|
+
x: colX,
|
|
47231
|
+
y: rowCy + FONT / 3,
|
|
47232
|
+
text: o.text,
|
|
47233
|
+
anchor: side === "right" ? "start" : "end",
|
|
46586
47234
|
color: palette.text,
|
|
46587
47235
|
halo: true,
|
|
46588
|
-
|
|
47236
|
+
haloColor: palette.bg,
|
|
47237
|
+
leader: {
|
|
47238
|
+
x1: o.p.cx,
|
|
47239
|
+
y1: o.p.cy,
|
|
47240
|
+
x2: side === "right" ? colX - 2 : colX + 2,
|
|
47241
|
+
y2: rowCy
|
|
47242
|
+
},
|
|
47243
|
+
leaderColor: o.p.fill,
|
|
47244
|
+
poiId: o.p.id,
|
|
47245
|
+
lineNumber: o.p.lineNumber
|
|
46589
47246
|
});
|
|
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;
|
|
47247
|
+
});
|
|
47248
|
+
};
|
|
47249
|
+
for (const g of groups) {
|
|
47250
|
+
if (g.length === 1) {
|
|
47251
|
+
const p = g[0];
|
|
47252
|
+
const { text, w } = labelInfo(p);
|
|
47253
|
+
if (inlineFits(p, w, "right")) {
|
|
47254
|
+
pushInline(p, text, w, "right");
|
|
47255
|
+
continue;
|
|
47256
|
+
}
|
|
47257
|
+
if (inlineFits(p, w, "left")) {
|
|
47258
|
+
pushInline(p, text, w, "left");
|
|
47259
|
+
continue;
|
|
46620
47260
|
}
|
|
46621
47261
|
}
|
|
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
|
-
});
|
|
47262
|
+
placeColumn(g);
|
|
46635
47263
|
}
|
|
46636
47264
|
}
|
|
46637
47265
|
let legend = null;
|
|
@@ -46640,8 +47268,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46640
47268
|
name: g.name,
|
|
46641
47269
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
46642
47270
|
}));
|
|
46643
|
-
|
|
46644
|
-
if (hasAnything) {
|
|
47271
|
+
if (tagGroups.length > 0 || hasRamp) {
|
|
46645
47272
|
legend = {
|
|
46646
47273
|
tagGroups,
|
|
46647
47274
|
activeGroup,
|
|
@@ -46652,20 +47279,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46652
47279
|
},
|
|
46653
47280
|
min: rampMin,
|
|
46654
47281
|
max: rampMax,
|
|
46655
|
-
hue: rampHue
|
|
47282
|
+
hue: rampHue,
|
|
47283
|
+
base: rampBase
|
|
46656
47284
|
}
|
|
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
47285
|
}
|
|
46670
47286
|
};
|
|
46671
47287
|
}
|
|
@@ -46673,28 +47289,30 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46673
47289
|
return {
|
|
46674
47290
|
width,
|
|
46675
47291
|
height,
|
|
46676
|
-
background:
|
|
47292
|
+
background: water,
|
|
46677
47293
|
title: resolved.title,
|
|
46678
47294
|
...resolved.subtitle !== void 0 && { subtitle: resolved.subtitle },
|
|
46679
47295
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
46680
47296
|
regions,
|
|
47297
|
+
rivers,
|
|
46681
47298
|
legs,
|
|
46682
47299
|
pois,
|
|
46683
47300
|
labels,
|
|
46684
|
-
|
|
46685
|
-
|
|
47301
|
+
legend,
|
|
47302
|
+
insets,
|
|
47303
|
+
insetRegions
|
|
46686
47304
|
};
|
|
46687
47305
|
}
|
|
46688
|
-
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT,
|
|
47306
|
+
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
47307
|
var init_layout15 = __esm({
|
|
46690
47308
|
"src/map/layout.ts"() {
|
|
46691
47309
|
"use strict";
|
|
46692
47310
|
import_d3_geo2 = require("d3-geo");
|
|
46693
47311
|
import_topojson_client2 = require("topojson-client");
|
|
46694
47312
|
init_color_utils();
|
|
46695
|
-
init_tag_groups();
|
|
46696
47313
|
init_label_layout();
|
|
46697
47314
|
init_legend_constants();
|
|
47315
|
+
init_title_constants();
|
|
46698
47316
|
FIT_PAD = 24;
|
|
46699
47317
|
RAMP_FLOOR = 15;
|
|
46700
47318
|
R_DEFAULT = 6;
|
|
@@ -46703,23 +47321,32 @@ var init_layout15 = __esm({
|
|
|
46703
47321
|
W_MIN = 1.25;
|
|
46704
47322
|
W_MAX = 8;
|
|
46705
47323
|
FONT = 11;
|
|
46706
|
-
LEADER_STEP = 14;
|
|
46707
47324
|
COLO_EPS = 1.5;
|
|
47325
|
+
LAND_TINT_LIGHT = 58;
|
|
47326
|
+
LAND_TINT_DARK = 75;
|
|
47327
|
+
TAG_TINT_LIGHT = 60;
|
|
47328
|
+
TAG_TINT_DARK = 68;
|
|
47329
|
+
WATER_TINT = 55;
|
|
47330
|
+
RIVER_WIDTH = 1.3;
|
|
47331
|
+
FOREIGN_TINT_LIGHT = 30;
|
|
47332
|
+
FOREIGN_TINT_DARK = 62;
|
|
46708
47333
|
COLO_R = 9;
|
|
46709
47334
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
46710
47335
|
FAN_STEP = 16;
|
|
46711
|
-
TINY_REGION_AREA = 600;
|
|
46712
47336
|
ARC_CURVE_FRAC = 0.18;
|
|
46713
|
-
|
|
46714
|
-
|
|
46715
|
-
|
|
46716
|
-
|
|
46717
|
-
|
|
46718
|
-
|
|
46719
|
-
|
|
46720
|
-
|
|
46721
|
-
|
|
46722
|
-
|
|
47337
|
+
usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47338
|
+
alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47339
|
+
hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
|
|
47340
|
+
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
47341
|
+
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47342
|
+
"US-AK",
|
|
47343
|
+
"US-HI",
|
|
47344
|
+
"US-AS",
|
|
47345
|
+
"US-GU",
|
|
47346
|
+
"US-MP",
|
|
47347
|
+
"US-PR",
|
|
47348
|
+
"US-VI"
|
|
47349
|
+
]);
|
|
46723
47350
|
}
|
|
46724
47351
|
});
|
|
46725
47352
|
|
|
@@ -46729,7 +47356,7 @@ __export(renderer_exports16, {
|
|
|
46729
47356
|
renderMap: () => renderMap,
|
|
46730
47357
|
renderMapForExport: () => renderMapForExport
|
|
46731
47358
|
});
|
|
46732
|
-
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims) {
|
|
47359
|
+
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
46733
47360
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
46734
47361
|
const width = exportDims?.width ?? container.clientWidth;
|
|
46735
47362
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -46740,27 +47367,29 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46740
47367
|
{ width, height },
|
|
46741
47368
|
{
|
|
46742
47369
|
palette,
|
|
46743
|
-
isDark
|
|
47370
|
+
isDark,
|
|
47371
|
+
...activeGroupOverride !== void 0 && {
|
|
47372
|
+
activeGroup: activeGroupOverride
|
|
47373
|
+
}
|
|
46744
47374
|
}
|
|
46745
47375
|
);
|
|
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);
|
|
47376
|
+
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
47377
|
svg.append("rect").attr("width", width).attr("height", height).attr("fill", layout.background);
|
|
46748
|
-
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
46749
47378
|
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
|
-
}
|
|
47379
|
+
const arrowSize = (w) => Math.min(15, 7 + w * 0.95);
|
|
47380
|
+
const haloColor = palette.bg;
|
|
46761
47381
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
46762
|
-
|
|
46763
|
-
const p =
|
|
47382
|
+
const drawRegion = (g, r, strokeWidth) => {
|
|
47383
|
+
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
47384
|
+
if (r.layer !== "base") {
|
|
47385
|
+
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47386
|
+
if (r.score !== void 0) p.attr("data-score", r.score);
|
|
47387
|
+
if (r.tags) {
|
|
47388
|
+
for (const [group, value] of Object.entries(r.tags)) {
|
|
47389
|
+
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
47390
|
+
}
|
|
47391
|
+
}
|
|
47392
|
+
}
|
|
46764
47393
|
if (r.lineNumber >= 0) {
|
|
46765
47394
|
p.attr("data-line-number", r.lineNumber);
|
|
46766
47395
|
if (onClickItem) {
|
|
@@ -46770,11 +47399,31 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46770
47399
|
);
|
|
46771
47400
|
}
|
|
46772
47401
|
}
|
|
47402
|
+
};
|
|
47403
|
+
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
47404
|
+
if (layout.rivers.length) {
|
|
47405
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47406
|
+
for (const r of layout.rivers) {
|
|
47407
|
+
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
47408
|
+
}
|
|
47409
|
+
}
|
|
47410
|
+
if (layout.insets.length) {
|
|
47411
|
+
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47412
|
+
for (const box of layout.insets) {
|
|
47413
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47414
|
+
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");
|
|
47415
|
+
}
|
|
47416
|
+
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
46773
47417
|
}
|
|
46774
47418
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
46775
|
-
|
|
47419
|
+
layout.legs.forEach((leg, i) => {
|
|
46776
47420
|
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)
|
|
47421
|
+
if (leg.arrow) {
|
|
47422
|
+
const id = `dgmo-map-arrow-${i}`;
|
|
47423
|
+
const s = arrowSize(leg.width);
|
|
47424
|
+
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);
|
|
47425
|
+
p.attr("marker-end", `url(#${id})`);
|
|
47426
|
+
}
|
|
46778
47427
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
46779
47428
|
emitText(
|
|
46780
47429
|
gLegs,
|
|
@@ -46788,13 +47437,13 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46788
47437
|
LABEL_FONT - 1
|
|
46789
47438
|
);
|
|
46790
47439
|
}
|
|
46791
|
-
}
|
|
47440
|
+
});
|
|
46792
47441
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
46793
47442
|
for (const poi of layout.pois) {
|
|
46794
47443
|
if (poi.isOrigin) {
|
|
46795
47444
|
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
47445
|
}
|
|
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);
|
|
47446
|
+
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
47447
|
if (onClickItem) {
|
|
46799
47448
|
c.style("cursor", "pointer").on(
|
|
46800
47449
|
"click",
|
|
@@ -46818,48 +47467,66 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
46818
47467
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
46819
47468
|
for (const lab of layout.labels) {
|
|
46820
47469
|
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(
|
|
47470
|
+
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(
|
|
47471
|
+
"stroke",
|
|
47472
|
+
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47473
|
+
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47474
|
+
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
46822
47475
|
}
|
|
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(
|
|
47476
|
+
const t = emitText(
|
|
46827
47477
|
gLabels,
|
|
46828
47478
|
lab.x,
|
|
46829
47479
|
lab.y,
|
|
46830
47480
|
lab.text,
|
|
46831
47481
|
lab.anchor,
|
|
46832
47482
|
lab.color,
|
|
46833
|
-
haloColor,
|
|
47483
|
+
lab.haloColor,
|
|
46834
47484
|
lab.halo,
|
|
46835
47485
|
LABEL_FONT
|
|
46836
47486
|
);
|
|
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
|
-
});
|
|
47487
|
+
if (lab.poiId !== void 0) {
|
|
47488
|
+
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47489
|
+
}
|
|
46846
47490
|
}
|
|
46847
47491
|
if (layout.legend) {
|
|
46848
47492
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
46849
47493
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
46850
|
-
const
|
|
47494
|
+
const ramp = layout.legend.ramp;
|
|
47495
|
+
const scoreGroup = ramp ? {
|
|
47496
|
+
name: ramp.metric?.trim() || "Score",
|
|
47497
|
+
entries: [],
|
|
47498
|
+
gradient: {
|
|
47499
|
+
min: ramp.min,
|
|
47500
|
+
max: ramp.max,
|
|
47501
|
+
hue: ramp.hue,
|
|
47502
|
+
base: ramp.base
|
|
47503
|
+
}
|
|
47504
|
+
} : null;
|
|
47505
|
+
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47506
|
+
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
46851
47507
|
if (groups.length > 0) {
|
|
46852
47508
|
const config = {
|
|
46853
|
-
groups
|
|
47509
|
+
groups,
|
|
46854
47510
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
46855
47511
|
mode: exportDims ? "export" : "preview",
|
|
46856
|
-
showEmptyGroups: false
|
|
47512
|
+
showEmptyGroups: false,
|
|
47513
|
+
// Keep inactive siblings visible as pills so the user can click to flip
|
|
47514
|
+
// the active colouring dimension (preview only — export shows just the
|
|
47515
|
+
// active group).
|
|
47516
|
+
showInactivePills: true
|
|
46857
47517
|
};
|
|
46858
47518
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
46859
47519
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
46860
47520
|
}
|
|
46861
|
-
|
|
46862
|
-
|
|
47521
|
+
}
|
|
47522
|
+
if (layout.title) {
|
|
47523
|
+
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);
|
|
47524
|
+
}
|
|
47525
|
+
if (layout.subtitle) {
|
|
47526
|
+
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);
|
|
47527
|
+
}
|
|
47528
|
+
if (layout.caption) {
|
|
47529
|
+
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
47530
|
}
|
|
46864
47531
|
}
|
|
46865
47532
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
@@ -46870,54 +47537,7 @@ function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
|
46870
47537
|
if (withHalo) {
|
|
46871
47538
|
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7);
|
|
46872
47539
|
}
|
|
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();
|
|
47540
|
+
return t;
|
|
46921
47541
|
}
|
|
46922
47542
|
var d3Selection18, LABEL_FONT;
|
|
46923
47543
|
var init_renderer16 = __esm({
|
|
@@ -53441,18 +54061,18 @@ function renderWordCloud(container, parsed, palette, _isDark, onClickItem, expor
|
|
|
53441
54061
|
}).start();
|
|
53442
54062
|
}
|
|
53443
54063
|
function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
|
|
53444
|
-
return new Promise((
|
|
54064
|
+
return new Promise((resolve) => {
|
|
53445
54065
|
d3Selection23.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
53446
54066
|
const { words, cloudOptions } = parsed;
|
|
53447
54067
|
const title = parsed.noTitle ? null : parsed.title;
|
|
53448
54068
|
if (words.length === 0) {
|
|
53449
|
-
|
|
54069
|
+
resolve();
|
|
53450
54070
|
return;
|
|
53451
54071
|
}
|
|
53452
54072
|
const width = exportDims?.width ?? container.clientWidth;
|
|
53453
54073
|
const height = exportDims?.height ?? container.clientHeight;
|
|
53454
54074
|
if (width <= 0 || height <= 0) {
|
|
53455
|
-
|
|
54075
|
+
resolve();
|
|
53456
54076
|
return;
|
|
53457
54077
|
}
|
|
53458
54078
|
const titleHeight = title ? 40 : 0;
|
|
@@ -53481,7 +54101,7 @@ function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
|
|
|
53481
54101
|
"transform",
|
|
53482
54102
|
(d) => `translate(${d.x},${d.y}) rotate(${d.rotate})`
|
|
53483
54103
|
).text((d) => d.text);
|
|
53484
|
-
|
|
54104
|
+
resolve();
|
|
53485
54105
|
}).start();
|
|
53486
54106
|
});
|
|
53487
54107
|
}
|
|
@@ -56038,6 +56658,8 @@ __export(internal_exports, {
|
|
|
56038
56658
|
looksLikeSitemap: () => looksLikeSitemap,
|
|
56039
56659
|
looksLikeState: () => looksLikeState,
|
|
56040
56660
|
makeDgmoError: () => makeDgmoError,
|
|
56661
|
+
mapBackgroundColor: () => mapBackgroundColor,
|
|
56662
|
+
mapNeutralLandColor: () => mapNeutralLandColor,
|
|
56041
56663
|
matchesContiguously: () => matchesContiguously,
|
|
56042
56664
|
measurePertAnalysisBlock: () => measurePertAnalysisBlock,
|
|
56043
56665
|
migrateContent: () => migrateContent,
|
|
@@ -56914,12 +57536,12 @@ var KNOWN_HEADER_OPTIONS = /* @__PURE__ */ new Set([
|
|
|
56914
57536
|
"solid-fill",
|
|
56915
57537
|
"active-tag"
|
|
56916
57538
|
]);
|
|
56917
|
-
function
|
|
57539
|
+
function dirname(filePath) {
|
|
56918
57540
|
const last = filePath.lastIndexOf("/");
|
|
56919
57541
|
return last > 0 ? filePath.substring(0, last) : "/";
|
|
56920
57542
|
}
|
|
56921
57543
|
function resolvePath(base, relative) {
|
|
56922
|
-
const parts =
|
|
57544
|
+
const parts = dirname(base).split("/");
|
|
56923
57545
|
for (const seg of relative.split("/")) {
|
|
56924
57546
|
if (seg === "..") {
|
|
56925
57547
|
if (parts.length > 1) parts.pop();
|
|
@@ -57822,10 +58444,13 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
57822
58444
|
// keywords, not directives; metadata keys (score/size/label) live in the
|
|
57823
58445
|
// reserved-key registry.
|
|
57824
58446
|
withGlobals({
|
|
57825
|
-
region: {
|
|
58447
|
+
region: {
|
|
58448
|
+
description: "Basemap: us-states (force US state mesh + scoping) | world (inert \u2014 already the default)",
|
|
58449
|
+
values: ["us-states", "world"]
|
|
58450
|
+
},
|
|
57826
58451
|
projection: {
|
|
57827
58452
|
description: "Override the auto projection",
|
|
57828
|
-
values: ["natural-earth", "albers-usa", "mercator"]
|
|
58453
|
+
values: ["equirectangular", "natural-earth", "albers-usa", "mercator"]
|
|
57829
58454
|
},
|
|
57830
58455
|
metric: { description: "Label for the region score ramp" },
|
|
57831
58456
|
"size-metric": { description: "Label for the POI size channel" },
|
|
@@ -59043,7 +59668,7 @@ init_dgmo_router();
|
|
|
59043
59668
|
|
|
59044
59669
|
// src/migrate/index.ts
|
|
59045
59670
|
var import_node_fs = require("fs");
|
|
59046
|
-
var
|
|
59671
|
+
var import_node_path = require("path");
|
|
59047
59672
|
init_dgmo_router();
|
|
59048
59673
|
|
|
59049
59674
|
// src/migrate/line-classifier.ts
|
|
@@ -59413,6 +60038,8 @@ function formatLineDiff(path, original, migrated) {
|
|
|
59413
60038
|
looksLikeSitemap,
|
|
59414
60039
|
looksLikeState,
|
|
59415
60040
|
makeDgmoError,
|
|
60041
|
+
mapBackgroundColor,
|
|
60042
|
+
mapNeutralLandColor,
|
|
59416
60043
|
matchesContiguously,
|
|
59417
60044
|
measurePertAnalysisBlock,
|
|
59418
60045
|
migrateContent,
|