@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.
Files changed (48) hide show
  1. package/dist/advanced.cjs +948 -321
  2. package/dist/advanced.d.cts +148 -54
  3. package/dist/advanced.d.ts +148 -54
  4. package/dist/advanced.js +949 -321
  5. package/dist/auto.cjs +930 -317
  6. package/dist/auto.js +117 -117
  7. package/dist/auto.mjs +934 -318
  8. package/dist/cli.cjs +160 -160
  9. package/dist/index.cjs +929 -316
  10. package/dist/index.js +933 -317
  11. package/dist/internal.cjs +948 -321
  12. package/dist/internal.d.cts +148 -54
  13. package/dist/internal.d.ts +148 -54
  14. package/dist/internal.js +949 -321
  15. package/dist/map-data/PROVENANCE.json +1 -1
  16. package/dist/map-data/lakes.json +1 -0
  17. package/dist/map-data/na-lakes.json +1 -0
  18. package/dist/map-data/na-land.json +1 -0
  19. package/dist/map-data/rivers.json +1 -0
  20. package/docs/language-reference.md +12 -7
  21. package/gallery/fixtures/map-region-scope.dgmo +15 -0
  22. package/package.json +4 -4
  23. package/src/advanced.ts +7 -6
  24. package/src/c4/parser.ts +6 -6
  25. package/src/completion.ts +6 -2
  26. package/src/echarts.ts +1 -1
  27. package/src/infra/parser.ts +10 -10
  28. package/src/journey-map/parser.ts +1 -1
  29. package/src/label-layout.ts +36 -0
  30. package/src/map/data/PROVENANCE.json +1 -1
  31. package/src/map/data/README.md +2 -0
  32. package/src/map/data/lakes.json +1 -0
  33. package/src/map/data/na-lakes.json +1 -0
  34. package/src/map/data/na-land.json +1 -0
  35. package/src/map/data/rivers.json +1 -0
  36. package/src/map/layout.ts +1022 -205
  37. package/src/map/load-data.ts +73 -17
  38. package/src/map/parser.ts +22 -13
  39. package/src/map/renderer.ts +200 -219
  40. package/src/map/resolved-types.ts +18 -1
  41. package/src/map/resolver.ts +79 -7
  42. package/src/map/types.ts +4 -0
  43. package/src/mindmap/parser.ts +1 -1
  44. package/src/sitemap/parser.ts +1 -1
  45. package/src/utils/legend-d3.ts +42 -0
  46. package/src/utils/legend-layout.ts +83 -3
  47. package/src/utils/legend-svg.ts +1 -8
  48. package/src/utils/legend-types.ts +44 -1
package/dist/auto.cjs CHANGED
@@ -53,6 +53,33 @@ function rectCircleOverlap(rect, circle) {
53
53
  const dy = nearestY - circle.cy;
54
54
  return dx * dx + dy * dy < circle.r * circle.r;
55
55
  }
56
+ function segmentRectOverlap(x0, y0, x1, y1, rect) {
57
+ const dx = x1 - x0;
58
+ const dy = y1 - y0;
59
+ let t0 = 0;
60
+ let t1 = 1;
61
+ const edges = [
62
+ [-dx, x0 - rect.x],
63
+ [dx, rect.x + rect.w - x0],
64
+ [-dy, y0 - rect.y],
65
+ [dy, rect.y + rect.h - y0]
66
+ ];
67
+ for (const [p, q] of edges) {
68
+ if (p === 0) {
69
+ if (q < 0) return false;
70
+ } else {
71
+ const t = q / p;
72
+ if (p < 0) {
73
+ if (t > t1) return false;
74
+ if (t > t0) t0 = t;
75
+ } else {
76
+ if (t < t0) return false;
77
+ if (t < t1) t1 = t;
78
+ }
79
+ }
80
+ }
81
+ return true;
82
+ }
56
83
  function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius, fontSize) {
57
84
  const labelHeight = fontSize + 4;
58
85
  const stepSize = labelHeight + 2;
@@ -3181,6 +3208,57 @@ var init_legend_constants = __esm({
3181
3208
  });
3182
3209
 
3183
3210
  // src/utils/legend-layout.ts
3211
+ function fmtRamp(n) {
3212
+ return Number.isInteger(n) ? String(n) : String(Math.round(n * 10) / 10);
3213
+ }
3214
+ function gradientCapsuleWidth(name, gradient) {
3215
+ const pw = pillWidth(name);
3216
+ const minW = measureLegendText(fmtRamp(gradient.min), LEGEND_ENTRY_FONT_SIZE);
3217
+ const maxW = measureLegendText(fmtRamp(gradient.max), LEGEND_ENTRY_FONT_SIZE);
3218
+ return LEGEND_CAPSULE_PAD + pw + 4 + minW + RAMP_LABEL_GAP + RAMP_LEGEND_W + RAMP_LABEL_GAP + maxW + LEGEND_CAPSULE_PAD;
3219
+ }
3220
+ function buildGradientCapsuleLayout(group, gradient) {
3221
+ const pw = pillWidth(group.name);
3222
+ const minText = fmtRamp(gradient.min);
3223
+ const maxText = fmtRamp(gradient.max);
3224
+ const minW = measureLegendText(minText, LEGEND_ENTRY_FONT_SIZE);
3225
+ const gx = LEGEND_CAPSULE_PAD + pw + 4;
3226
+ const minX = gx;
3227
+ const rampX = gx + minW + RAMP_LABEL_GAP;
3228
+ const maxX = rampX + RAMP_LEGEND_W + RAMP_LABEL_GAP;
3229
+ const width = gradientCapsuleWidth(group.name, gradient);
3230
+ return {
3231
+ groupName: group.name,
3232
+ x: 0,
3233
+ y: 0,
3234
+ width,
3235
+ height: LEGEND_HEIGHT,
3236
+ pill: {
3237
+ groupName: group.name,
3238
+ x: LEGEND_CAPSULE_PAD,
3239
+ y: LEGEND_CAPSULE_PAD,
3240
+ width: pw,
3241
+ height: LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2,
3242
+ isActive: true
3243
+ },
3244
+ entries: [],
3245
+ gradient: {
3246
+ rampX,
3247
+ rampY: (LEGEND_HEIGHT - RAMP_LEGEND_H) / 2,
3248
+ rampW: RAMP_LEGEND_W,
3249
+ rampH: RAMP_LEGEND_H,
3250
+ min: gradient.min,
3251
+ max: gradient.max,
3252
+ minText,
3253
+ minX,
3254
+ maxText,
3255
+ maxX,
3256
+ textY: LEGEND_HEIGHT / 2,
3257
+ hue: gradient.hue,
3258
+ base: gradient.base
3259
+ }
3260
+ };
3261
+ }
3184
3262
  function pillWidth(name) {
3185
3263
  return measureLegendText(name, LEGEND_PILL_FONT_SIZE) + LEGEND_PILL_PAD;
3186
3264
  }
@@ -3323,7 +3401,7 @@ function computeLegendLayout(config, state, containerWidth) {
3323
3401
  };
3324
3402
  }
3325
3403
  const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
3326
- const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0);
3404
+ const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
3327
3405
  if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
3328
3406
  return {
3329
3407
  height: 0,
@@ -3402,7 +3480,7 @@ function computeLegendLayout(config, state, containerWidth) {
3402
3480
  groupAvailW,
3403
3481
  config.capsulePillAddonWidth ?? 0
3404
3482
  );
3405
- } else if (!activeGroupName) {
3483
+ } else if (!activeGroupName || config.showInactivePills) {
3406
3484
  const pw = pillWidth(g.name);
3407
3485
  pills.push({
3408
3486
  groupName: g.name,
@@ -3440,6 +3518,7 @@ function computeLegendLayout(config, state, containerWidth) {
3440
3518
  };
3441
3519
  }
3442
3520
  function buildCapsuleLayout(group, containerWidth, addonWidth = 0) {
3521
+ if (group.gradient) return buildGradientCapsuleLayout(group, group.gradient);
3443
3522
  const pw = pillWidth(group.name);
3444
3523
  const info = capsuleWidth(
3445
3524
  group.name,
@@ -3610,7 +3689,7 @@ function getMaxLegendReservedHeight(config, containerWidth) {
3610
3689
  }
3611
3690
  return max;
3612
3691
  }
3613
- var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
3692
+ var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP, RAMP_LEGEND_W, RAMP_LEGEND_H, RAMP_LABEL_GAP;
3614
3693
  var init_legend_layout = __esm({
3615
3694
  "src/utils/legend-layout.ts"() {
3616
3695
  "use strict";
@@ -3619,6 +3698,9 @@ var init_legend_layout = __esm({
3619
3698
  CONTROL_FONT_SIZE = 11;
3620
3699
  CONTROL_ICON_GAP = 4;
3621
3700
  CONTROL_GAP = 8;
3701
+ RAMP_LEGEND_W = 80;
3702
+ RAMP_LEGEND_H = 8;
3703
+ RAMP_LABEL_GAP = 6;
3622
3704
  }
3623
3705
  });
3624
3706
 
@@ -3706,6 +3788,16 @@ function renderCapsule(parent, capsule, palette, groupBg, pillBorder, _isDark, c
3706
3788
  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);
3707
3789
  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);
3708
3790
  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);
3791
+ if (capsule.gradient) {
3792
+ const gr = capsule.gradient;
3793
+ const gradId = `dgmo-legend-ramp-${capsule.groupName.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
3794
+ const def = g.append("defs").append("linearGradient").attr("id", gradId);
3795
+ def.append("stop").attr("offset", "0%").attr("stop-color", mix(gr.hue, gr.base, 15));
3796
+ def.append("stop").attr("offset", "100%").attr("stop-color", gr.hue);
3797
+ 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);
3798
+ 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})`);
3799
+ 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);
3800
+ }
3709
3801
  for (const entry of capsule.entries) {
3710
3802
  const entryG = g.append("g").attr("data-legend-entry", entry.value.toLowerCase()).attr("data-series-name", entry.value).style("cursor", "pointer");
3711
3803
  entryG.append("circle").attr("cx", entry.dotCx).attr("cy", entry.dotCy).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
@@ -11179,23 +11271,22 @@ function parseC4(content, palette) {
11179
11271
  }
11180
11272
  }
11181
11273
  const parent = findParentElement(indent, stack);
11182
- if (parent) {
11183
- const descResult = tryStripDescriptionKeyword(trimmed);
11274
+ const descResult = tryStripDescriptionKeyword(trimmed);
11275
+ if (parent && descResult.isKeyword) {
11184
11276
  if (descResult.needsColon) {
11185
11277
  pushError(
11186
11278
  lineNumber,
11187
- `Use "description: ${descResult.text}" \u2014 colon is required.`,
11279
+ `Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`,
11188
11280
  "warning"
11189
11281
  );
11190
11282
  }
11191
- const descText = descResult.isKeyword ? descResult.text : trimmed;
11192
11283
  let desc = elementDescription.get(parent.element);
11193
11284
  if (!desc) {
11194
11285
  desc = [];
11195
11286
  elementDescription.set(parent.element, desc);
11196
11287
  parent.element.description = desc;
11197
11288
  }
11198
- desc.push(descText);
11289
+ desc.push(descResult.text);
11199
11290
  } else {
11200
11291
  pushError(lineNumber, `Unexpected content: "${trimmed}"`);
11201
11292
  }
@@ -11662,7 +11753,7 @@ function parseSitemap(content, palette) {
11662
11753
  if (descResult.needsColon) {
11663
11754
  pushWarning(
11664
11755
  lineNumber,
11665
- `Use "description: ${descResult.text}" \u2014 colon is required.`
11756
+ `Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
11666
11757
  );
11667
11758
  }
11668
11759
  const parent = findParentNode(indent, indentStack);
@@ -12490,23 +12581,22 @@ function parseInfra(content) {
12490
12581
  }
12491
12582
  }
12492
12583
  const descResult = tryStripDescriptionKeyword(trimmed);
12493
- if (descResult.isKeyword && currentNode.isEdge) {
12494
- continue;
12495
- }
12496
- if (!currentNode.isEdge) {
12584
+ if (descResult.isKeyword) {
12585
+ if (currentNode.isEdge) {
12586
+ continue;
12587
+ }
12497
12588
  if (descResult.needsColon) {
12498
12589
  warn2(
12499
12590
  lineNumber,
12500
- `Use "description: ${descResult.text}" \u2014 colon is required.`
12591
+ `Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
12501
12592
  );
12502
12593
  }
12503
- const descText = descResult.isKeyword ? descResult.text : trimmed;
12504
- pushDescription(currentNode, descText);
12594
+ pushDescription(currentNode, descResult.text);
12505
12595
  continue;
12506
12596
  }
12507
12597
  warn2(
12508
12598
  lineNumber,
12509
- `Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or description text.`
12599
+ `Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or a description (description: text).`
12510
12600
  );
12511
12601
  continue;
12512
12602
  }
@@ -15643,9 +15733,6 @@ function parseMap(content) {
15643
15733
  const pushWarning = (line12, message) => {
15644
15734
  diagnostics.push(makeDgmoError(line12, message, "warning"));
15645
15735
  };
15646
- const pushInfo = (line12, message) => {
15647
- diagnostics.push(makeDgmoError(line12, message, "warning"));
15648
- };
15649
15736
  const lines = content.split("\n");
15650
15737
  let firstIdx = 0;
15651
15738
  while (firstIdx < lines.length) {
@@ -15775,10 +15862,15 @@ function parseMap(content) {
15775
15862
  break;
15776
15863
  case "projection":
15777
15864
  dup(d.projection);
15778
- if (value && !["natural-earth", "albers-usa", "mercator"].includes(value))
15865
+ if (value && ![
15866
+ "equirectangular",
15867
+ "natural-earth",
15868
+ "albers-usa",
15869
+ "mercator"
15870
+ ].includes(value))
15779
15871
  pushWarning(
15780
15872
  line12,
15781
- `Unknown projection "${value}" (expected natural-earth | albers-usa | mercator).`
15873
+ `Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
15782
15874
  );
15783
15875
  d.projection = value;
15784
15876
  break;
@@ -15917,17 +16009,21 @@ function parseMap(content) {
15917
16009
  scoreNum = void 0;
15918
16010
  }
15919
16011
  }
15920
- if (scoreNum !== void 0 && Object.keys(tags).length)
15921
- pushInfo(
15922
- line12,
15923
- "A region has both `score:` and a tag value \u2014 v1 renders only the score (bivariate is a future seam)."
15924
- );
16012
+ let regionName = split.name;
16013
+ let regionScope;
16014
+ const rToks = regionName.split(/\s+/);
16015
+ const rLast = rToks[rToks.length - 1];
16016
+ if (rToks.length > 1 && SCOPE_RE.test(rLast)) {
16017
+ regionName = rToks.slice(0, -1).join(" ");
16018
+ regionScope = rLast;
16019
+ }
15925
16020
  const region = {
15926
- name: split.name,
16021
+ name: regionName,
15927
16022
  tags,
15928
16023
  meta,
15929
16024
  lineNumber: line12
15930
16025
  };
16026
+ if (regionScope !== void 0) region.scope = regionScope;
15931
16027
  if (scoreNum !== void 0) region.score = scoreNum;
15932
16028
  regions.push(region);
15933
16029
  }
@@ -17051,7 +17147,7 @@ function parseMindmap(content, palette) {
17051
17147
  if (descResult.needsColon) {
17052
17148
  pushWarning(
17053
17149
  lineNumber,
17054
- `Use "description: ${descResult.text}" \u2014 colon is required.`
17150
+ `Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
17055
17151
  );
17056
17152
  }
17057
17153
  const parent = findMetadataParent2(indent, indentStack);
@@ -18839,7 +18935,7 @@ function parseJourneyMap(content, palette) {
18839
18935
  if (descResult.needsColon) {
18840
18936
  warn2(
18841
18937
  lineNumber,
18842
- `Use "description: ${descResult.text}" \u2014 colon is required.`
18938
+ `Use "description: ${descResult.text}" \u2014 bare "description" is deprecated.`
18843
18939
  );
18844
18940
  }
18845
18941
  currentStep.description = descResult.text;
@@ -45428,7 +45524,9 @@ function resolveMap(parsed, data) {
45428
45524
  const usScoped = parsed.directives.region === "us-states" || parsed.directives.defaultCountry?.toUpperCase() === "US" || parsed.regions.some((r) => {
45429
45525
  const f = fold(r.name);
45430
45526
  return usStateIndex.has(f) && !countryIndex.has(f);
45431
- }) || parsed.pois.some(
45527
+ }) || parsed.regions.some(
45528
+ (r) => r.scope === "US" || r.scope?.startsWith("US-")
45529
+ ) || parsed.pois.some(
45432
45530
  (p) => p.pos.kind === "name" && p.pos.scope?.startsWith("US-")
45433
45531
  );
45434
45532
  const regions = [];
@@ -45440,7 +45538,30 @@ function resolveMap(parsed, data) {
45440
45538
  const inCountry = countryIndex.get(f) ?? (REGION_ALIASES[f] ? countryIndex.get(REGION_ALIASES[f]) : void 0);
45441
45539
  const inState = usStateIndex.get(f);
45442
45540
  let chosen = null;
45443
- if (inCountry && inState) {
45541
+ const scope = r.scope;
45542
+ if (scope) {
45543
+ const wantsState = scope === "US" || scope.startsWith("US-");
45544
+ if (wantsState && inState) {
45545
+ if (scope.startsWith("US-") && inState.id !== scope) {
45546
+ err(
45547
+ r.lineNumber,
45548
+ `No subdivision "${r.name}" in scope ${scope} (it is ${inState.id}).`,
45549
+ "E_MAP_SCOPE_MISS"
45550
+ );
45551
+ continue;
45552
+ }
45553
+ chosen = { ...inState, layer: "us-state" };
45554
+ } else if (!wantsState && inCountry) {
45555
+ chosen = { ...inCountry, layer: "country" };
45556
+ } else {
45557
+ err(
45558
+ r.lineNumber,
45559
+ `No region "${r.name}" found in scope ${scope}.`,
45560
+ "E_MAP_SCOPE_MISS"
45561
+ );
45562
+ continue;
45563
+ }
45564
+ } else if (inCountry && inState) {
45444
45565
  if (usScoped) {
45445
45566
  chosen = { ...inState, layer: "us-state" };
45446
45567
  } else {
@@ -45448,7 +45569,7 @@ function resolveMap(parsed, data) {
45448
45569
  }
45449
45570
  warn2(
45450
45571
  r.lineNumber,
45451
- `"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}).`,
45572
+ `"${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}").`,
45452
45573
  "W_MAP_REGION_AMBIGUOUS"
45453
45574
  );
45454
45575
  } else if (inState) {
@@ -45620,9 +45741,17 @@ function resolveMap(parsed, data) {
45620
45741
  };
45621
45742
  registerPoi(id, poi, p.lineNumber);
45622
45743
  }
45744
+ const declaredByName = /* @__PURE__ */ new Map();
45745
+ for (const p of pois) {
45746
+ const fn = p.name ? fold(p.name) : void 0;
45747
+ if (fn && fn !== p.id && !declaredByName.has(fn))
45748
+ declaredByName.set(fn, p.id);
45749
+ }
45623
45750
  const resolveEndpoint2 = (ref, line12) => {
45624
45751
  const f = fold(ref);
45625
45752
  if (registry.has(f)) return f;
45753
+ const aliased = declaredByName.get(f);
45754
+ if (aliased) return aliased;
45626
45755
  const got = lookupName(ref, void 0, line12, inferredCountry, true);
45627
45756
  if (got.kind !== "ok") return null;
45628
45757
  noteCountry(got.iso);
@@ -45702,23 +45831,29 @@ function resolveMap(parsed, data) {
45702
45831
  [-180, -85],
45703
45832
  [180, 85]
45704
45833
  ];
45705
- const extent2 = unioned ? pad(unioned, PAD_FRACTION) : DEFAULT_EXTENT;
45834
+ let extent2 = unioned ? pad(unioned, PAD_FRACTION) : DEFAULT_EXTENT;
45706
45835
  const lonSpan = extent2[1][0] - extent2[0][0];
45707
45836
  const latSpan = extent2[1][1] - extent2[0][1];
45708
45837
  const span = Math.max(lonSpan, latSpan);
45709
45838
  const usDominant = (inferredCountry === "US" || subdivisions.includes("us-states")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
45710
45839
  let projection;
45711
45840
  const override = parsed.directives.projection;
45712
- if (override === "natural-earth" || override === "albers-usa" || override === "mercator") {
45841
+ if (override === "equirectangular" || override === "natural-earth" || override === "albers-usa" || override === "mercator") {
45713
45842
  projection = override;
45714
45843
  } else if (usDominant) {
45715
45844
  projection = "albers-usa";
45716
45845
  } else if (span > WORLD_SPAN) {
45717
- projection = "natural-earth";
45846
+ projection = "equirectangular";
45718
45847
  } else if (span < MERCATOR_MAX_SPAN) {
45719
45848
  projection = "mercator";
45720
45849
  } else {
45721
- projection = "natural-earth";
45850
+ projection = "equirectangular";
45851
+ }
45852
+ if (lonSpan >= 180) {
45853
+ extent2 = [
45854
+ [-180, Math.min(extent2[0][1], WORLD_LAT_SOUTH)],
45855
+ [180, Math.max(extent2[1][1], WORLD_LAT_NORTH)]
45856
+ ];
45722
45857
  }
45723
45858
  result.regions = regions;
45724
45859
  result.pois = pois;
@@ -45766,7 +45901,7 @@ function firstError(diags) {
45766
45901
  const e = diags.find((d) => d.severity === "error");
45767
45902
  return e ? formatDgmoError(e) : null;
45768
45903
  }
45769
- var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, REGION_ALIASES;
45904
+ var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES;
45770
45905
  var init_resolver2 = __esm({
45771
45906
  "src/map/resolver.ts"() {
45772
45907
  "use strict";
@@ -45775,6 +45910,8 @@ var init_resolver2 = __esm({
45775
45910
  WORLD_SPAN = 90;
45776
45911
  MERCATOR_MAX_SPAN = 25;
45777
45912
  PAD_FRACTION = 0.05;
45913
+ WORLD_LAT_SOUTH = -58;
45914
+ WORLD_LAT_NORTH = 78;
45778
45915
  REGION_ALIASES = {
45779
45916
  // Common everyday names → the Natural-Earth display name actually shipped.
45780
45917
  "united states": "united states of america",
@@ -45804,14 +45941,22 @@ var load_data_exports = {};
45804
45941
  __export(load_data_exports, {
45805
45942
  loadMapData: () => loadMapData
45806
45943
  });
45807
- async function readJson(dir, name) {
45808
- return JSON.parse(await (0, import_promises.readFile)((0, import_node_path.resolve)(dir, name), "utf8"));
45944
+ async function loadNodeBuiltins() {
45945
+ const [{ readFile }, { fileURLToPath }, { dirname, resolve }] = await Promise.all([
45946
+ import("fs/promises"),
45947
+ import("url"),
45948
+ import("path")
45949
+ ]);
45950
+ return { readFile, fileURLToPath, dirname, resolve };
45951
+ }
45952
+ async function readJson(nb, dir, name) {
45953
+ return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
45809
45954
  }
45810
- async function firstExistingDir(baseDir) {
45955
+ async function firstExistingDir(nb, baseDir) {
45811
45956
  for (const rel of CANDIDATE_DIRS) {
45812
- const dir = (0, import_node_path.resolve)(baseDir, rel);
45957
+ const dir = nb.resolve(baseDir, rel);
45813
45958
  try {
45814
- await (0, import_promises.readFile)((0, import_node_path.resolve)(dir, FILES.gazetteer), "utf8");
45959
+ await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
45815
45960
  return dir;
45816
45961
  } catch {
45817
45962
  }
@@ -45827,10 +45972,10 @@ function validate(data) {
45827
45972
  }
45828
45973
  return data;
45829
45974
  }
45830
- function moduleBaseDir() {
45975
+ function moduleBaseDir(nb) {
45831
45976
  try {
45832
45977
  const url = import_meta.url;
45833
- if (url) return (0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(url));
45978
+ if (url) return nb.dirname(nb.fileURLToPath(url));
45834
45979
  } catch {
45835
45980
  }
45836
45981
  if (typeof __dirname !== "undefined") return __dirname;
@@ -45838,32 +45983,57 @@ function moduleBaseDir() {
45838
45983
  }
45839
45984
  function loadMapData() {
45840
45985
  cache ??= (async () => {
45841
- const dir = await firstExistingDir(moduleBaseDir());
45842
- const [worldCoarse, worldDetail, usStates, gazetteer] = await Promise.all([
45843
- readJson(dir, FILES.worldCoarse),
45844
- readJson(dir, FILES.worldDetail),
45845
- readJson(dir, FILES.usStates),
45846
- readJson(dir, FILES.gazetteer)
45986
+ const nb = await loadNodeBuiltins();
45987
+ const dir = await firstExistingDir(nb, moduleBaseDir(nb));
45988
+ const [
45989
+ worldCoarse,
45990
+ worldDetail,
45991
+ usStates,
45992
+ lakes,
45993
+ rivers,
45994
+ naLand,
45995
+ naLakes,
45996
+ gazetteer
45997
+ ] = await Promise.all([
45998
+ readJson(nb, dir, FILES.worldCoarse),
45999
+ readJson(nb, dir, FILES.worldDetail),
46000
+ readJson(nb, dir, FILES.usStates),
46001
+ // Lakes/rivers/NA assets are optional — older bundles may predate them.
46002
+ readJson(nb, dir, FILES.lakes).catch(() => void 0),
46003
+ readJson(nb, dir, FILES.rivers).catch(() => void 0),
46004
+ readJson(nb, dir, FILES.naLand).catch(() => void 0),
46005
+ readJson(nb, dir, FILES.naLakes).catch(() => void 0),
46006
+ readJson(nb, dir, FILES.gazetteer)
45847
46007
  ]);
45848
- return validate({ worldCoarse, worldDetail, usStates, gazetteer });
46008
+ return validate({
46009
+ worldCoarse,
46010
+ worldDetail,
46011
+ usStates,
46012
+ gazetteer,
46013
+ ...lakes && { lakes },
46014
+ ...rivers && { rivers },
46015
+ ...naLand && { naLand },
46016
+ ...naLakes && { naLakes }
46017
+ });
45849
46018
  })().catch((e) => {
45850
46019
  cache = void 0;
45851
46020
  throw e;
45852
46021
  });
45853
46022
  return cache;
45854
46023
  }
45855
- var import_promises, import_node_url, import_node_path, import_meta, FILES, CANDIDATE_DIRS, cache;
46024
+ var import_meta, FILES, CANDIDATE_DIRS, cache;
45856
46025
  var init_load_data = __esm({
45857
46026
  "src/map/load-data.ts"() {
45858
46027
  "use strict";
45859
- import_promises = require("fs/promises");
45860
- import_node_url = require("url");
45861
- import_node_path = require("path");
45862
46028
  import_meta = {};
45863
46029
  FILES = {
45864
46030
  worldCoarse: "world-coarse.json",
45865
46031
  worldDetail: "world-detail.json",
45866
46032
  usStates: "us-states.json",
46033
+ lakes: "lakes.json",
46034
+ rivers: "rivers.json",
46035
+ naLand: "na-land.json",
46036
+ naLakes: "na-lakes.json",
45867
46037
  gazetteer: "gazetteer.json"
45868
46038
  };
45869
46039
  CANDIDATE_DIRS = [
@@ -45891,36 +46061,67 @@ function decodeLayer(topo) {
45891
46061
  function projectionFor(family) {
45892
46062
  switch (family) {
45893
46063
  case "albers-usa":
45894
- return (0, import_d3_geo2.geoAlbersUsa)();
46064
+ return usConusProjection();
45895
46065
  case "mercator":
45896
46066
  return (0, import_d3_geo2.geoMercator)();
45897
46067
  case "natural-earth":
45898
- default:
45899
46068
  return (0, import_d3_geo2.geoNaturalEarth1)();
46069
+ case "equirectangular":
46070
+ default:
46071
+ return (0, import_d3_geo2.geoEquirectangular)();
45900
46072
  }
45901
46073
  }
46074
+ function mapBackgroundColor(palette) {
46075
+ return mix(palette.colors.blue, palette.bg, WATER_TINT);
46076
+ }
45902
46077
  function layoutMap(resolved, data, size, opts) {
45903
46078
  const { palette, isDark } = opts;
45904
46079
  const { width, height } = size;
45905
- const worldTopo = resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
46080
+ const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
46081
+ const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
46082
+ const worldTopo = usCrisp ? data.naLand : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
45906
46083
  const worldLayer = decodeLayer(worldTopo);
45907
- const usLayer = resolved.basemaps.subdivisions.includes("us-states") ? decodeLayer(data.usStates) : null;
45908
- const neutralFill = mix(palette.border, palette.bg, 32);
45909
- const regionStroke = mix(palette.border, palette.bg, 70);
46084
+ const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
46085
+ const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
46086
+ const neutralFill = mix(palette.colors.green, palette.bg, landTint);
46087
+ const water = mapBackgroundColor(palette);
46088
+ const usContext = usLayer !== null;
46089
+ const foreignFill = mix(
46090
+ palette.colors.gray,
46091
+ palette.bg,
46092
+ isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
46093
+ );
46094
+ const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
45910
46095
  const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
45911
46096
  const scaleOverride = resolved.directives.scale;
45912
46097
  const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
45913
46098
  const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
45914
- const rampHue = palette.primary;
46099
+ const rampHue = palette.colors.red;
45915
46100
  const hasRamp = scores.length > 0;
45916
- const activeGroup = resolveActiveTagGroup(
45917
- resolved.tagGroups,
45918
- resolved.directives.activeTag
45919
- );
46101
+ const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
46102
+ const matchColorGroup = (v) => {
46103
+ const lv = v.trim().toLowerCase();
46104
+ if (lv === "none") return null;
46105
+ if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
46106
+ return SCORE_NAME;
46107
+ const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
46108
+ return tg ? tg.name : v;
46109
+ };
46110
+ const override = opts.activeGroup;
46111
+ let activeGroup;
46112
+ if (override !== void 0) {
46113
+ activeGroup = override === null ? null : matchColorGroup(override);
46114
+ } else if (resolved.directives.activeTag !== void 0) {
46115
+ activeGroup = matchColorGroup(resolved.directives.activeTag);
46116
+ } else {
46117
+ activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
46118
+ }
46119
+ const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
46120
+ const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
45920
46121
  const fillForScore = (s) => {
45921
46122
  const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
45922
46123
  const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
45923
- return mix(rampHue, isDark ? palette.surface : palette.bg, pct);
46124
+ return mix(rampHue, rampBase, pct);
45924
46125
  };
45925
46126
  const tagFill = (tags, groupName) => {
45926
46127
  if (!groupName) return null;
@@ -45934,40 +46135,40 @@ function layoutMap(resolved, data, size, opts) {
45934
46135
  (e) => e.value.toLowerCase() === val.toLowerCase()
45935
46136
  );
45936
46137
  if (!entry?.color) return null;
45937
- return shapeFill(palette, entry.color, isDark);
46138
+ return mix(
46139
+ entry.color,
46140
+ palette.bg,
46141
+ isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
46142
+ );
46143
+ };
46144
+ const regionFill = (r) => {
46145
+ if (activeIsScore) {
46146
+ return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
46147
+ }
46148
+ return tagFill(r.tags, activeGroup) ?? neutralFill;
45938
46149
  };
45939
46150
  const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
45940
- const regionFeatures = [];
45941
- for (const r of resolved.regions) {
45942
- const f = r.layer === "us-state" ? usLayer?.get(r.iso) : worldLayer.get(r.iso);
45943
- if (f) regionFeatures.push(f);
45944
- }
45945
- const extentCorners = () => {
46151
+ const extentOutline = () => {
45946
46152
  const [[w, s], [e, n]] = resolved.extent;
46153
+ const N = 16;
46154
+ const coords = [];
46155
+ for (let i = 0; i <= N; i++) {
46156
+ const t = i / N;
46157
+ const lon = w + (e - w) * t;
46158
+ const lat = s + (n - s) * t;
46159
+ coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
46160
+ }
45947
46161
  return {
45948
46162
  type: "Feature",
45949
46163
  properties: {},
45950
- geometry: {
45951
- type: "MultiPoint",
45952
- coordinates: [
45953
- [w, s],
45954
- [e, s],
45955
- [e, n],
45956
- [w, n]
45957
- ]
45958
- }
46164
+ geometry: { type: "MultiPoint", coordinates: coords }
45959
46165
  };
45960
46166
  };
45961
46167
  let fitFeatures;
45962
- if (resolved.projection === "albers-usa") {
45963
- if (regionFeatures.length > 0) fitFeatures = regionFeatures;
45964
- else if (usLayer) fitFeatures = [...usLayer.values()];
45965
- else {
45966
- const us = worldLayer.get("US");
45967
- fitFeatures = us ? [us] : [...worldLayer.values()];
45968
- }
46168
+ if (resolved.projection === "albers-usa" && usLayer) {
46169
+ fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
45969
46170
  } else {
45970
- fitFeatures = [extentCorners()];
46171
+ fitFeatures = [extentOutline()];
45971
46172
  }
45972
46173
  const fitTarget = { type: "FeatureCollection", features: fitFeatures };
45973
46174
  const projection = projectionFor(resolved.projection);
@@ -45976,32 +46177,311 @@ function layoutMap(resolved, data, size, opts) {
45976
46177
  if (centerLon > 180) centerLon -= 360;
45977
46178
  projection.rotate([-centerLon, 0]);
45978
46179
  }
45979
- projection.fitExtent(
46180
+ const TITLE_GAP = 16;
46181
+ let topPad = FIT_PAD;
46182
+ if (resolved.title && resolved.pois.length > 0) {
46183
+ const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
46184
+ topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP);
46185
+ }
46186
+ const fitBox = [
46187
+ [FIT_PAD, topPad],
45980
46188
  [
45981
- [FIT_PAD, FIT_PAD],
45982
- [
45983
- Math.max(FIT_PAD + 1, width - FIT_PAD),
45984
- Math.max(FIT_PAD + 1, height - FIT_PAD)
45985
- ]
45986
- ],
45987
- fitTarget
45988
- );
45989
- const path = (0, import_d3_geo2.geoPath)(projection);
45990
- const project = (lon, lat) => projection([lon, lat]) ?? null;
46189
+ Math.max(FIT_PAD + 1, width - FIT_PAD),
46190
+ Math.max(topPad + 1, height - FIT_PAD)
46191
+ ]
46192
+ ];
46193
+ projection.fitExtent(fitBox, fitTarget);
46194
+ const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
46195
+ const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
46196
+ let path;
46197
+ let project;
46198
+ if (fitIsGlobal) {
46199
+ const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
46200
+ const bx0 = cb[0][0];
46201
+ const by0 = cb[0][1];
46202
+ const cw = cb[1][0] - bx0;
46203
+ const ch = cb[1][1] - by0;
46204
+ const ox = fitBox[0][0];
46205
+ const oy = fitBox[0][1];
46206
+ const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
46207
+ const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
46208
+ const stretch = (x, y) => [
46209
+ ox + (x - bx0) * sx,
46210
+ oy + (y - by0) * sy
46211
+ ];
46212
+ const baseProjection = projection;
46213
+ const tx = (0, import_d3_geo2.geoTransform)({
46214
+ point(x, y) {
46215
+ const [px, py] = stretch(x, y);
46216
+ this.stream.point(px, py);
46217
+ }
46218
+ });
46219
+ path = (0, import_d3_geo2.geoPath)({
46220
+ stream: (s) => baseProjection.stream(
46221
+ tx.stream(s)
46222
+ )
46223
+ });
46224
+ project = (lon, lat) => {
46225
+ const p = baseProjection([lon, lat]);
46226
+ return p ? stretch(p[0], p[1]) : null;
46227
+ };
46228
+ } else {
46229
+ path = (0, import_d3_geo2.geoPath)(projection);
46230
+ project = (lon, lat) => projection([lon, lat]) ?? null;
46231
+ }
46232
+ const insets = [];
46233
+ const insetRegions = [];
46234
+ const insetLabelSeeds = [];
46235
+ if (resolved.projection === "albers-usa" && usLayer) {
46236
+ const PAD = 8;
46237
+ const GAP = 12;
46238
+ const yB = height - FIT_PAD;
46239
+ const BW = 8;
46240
+ const coast = /* @__PURE__ */ new Map();
46241
+ const addPt = (lon, lat) => {
46242
+ const p = projection([lon, lat]);
46243
+ if (!p) return;
46244
+ const bi = Math.floor(p[0] / BW);
46245
+ const cur = coast.get(bi);
46246
+ if (cur === void 0 || p[1] > cur) coast.set(bi, p[1]);
46247
+ };
46248
+ const walk = (co) => {
46249
+ if (Array.isArray(co) && typeof co[0] === "number")
46250
+ addPt(co[0], co[1]);
46251
+ else if (Array.isArray(co)) for (const c of co) walk(c);
46252
+ };
46253
+ for (const [iso, f] of usLayer) {
46254
+ if (US_NON_CONUS.has(iso)) continue;
46255
+ walk(f.geometry.coordinates);
46256
+ }
46257
+ const at = (x) => {
46258
+ const bi = Math.floor(x / BW);
46259
+ let y = -Infinity;
46260
+ for (let k = bi - 1; k <= bi + 1; k++) {
46261
+ const v = coast.get(k);
46262
+ if (v !== void 0 && v > y) y = v;
46263
+ }
46264
+ return y;
46265
+ };
46266
+ const coastTop = (x0, xr) => {
46267
+ const n = 24;
46268
+ const pts = [];
46269
+ let maxY = -Infinity;
46270
+ for (let i = 0; i <= n; i++) {
46271
+ const x = x0 + (xr - x0) * i / n;
46272
+ const y = at(x);
46273
+ if (y > -Infinity) {
46274
+ pts.push([x, y]);
46275
+ if (y > maxY) maxY = y;
46276
+ }
46277
+ }
46278
+ if (pts.length === 0) return () => yB - height * 0.42;
46279
+ let m = 0;
46280
+ if (pts.length >= 2) {
46281
+ let sx = 0, sy = 0, sxx = 0, sxy = 0;
46282
+ for (const [x, y] of pts) {
46283
+ sx += x;
46284
+ sy += y;
46285
+ sxx += x * x;
46286
+ sxy += x * y;
46287
+ }
46288
+ const den = pts.length * sxx - sx * sx;
46289
+ if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
46290
+ }
46291
+ m = Math.max(-0.35, Math.min(0.35, m));
46292
+ let c = -Infinity;
46293
+ for (const [x, y] of pts) {
46294
+ const need = y - m * x + GAP;
46295
+ if (need > c) c = need;
46296
+ }
46297
+ return (x) => m * x + c;
46298
+ };
46299
+ const placeInset = (iso, proj, boxX, iwReq) => {
46300
+ const f = usLayer.get(iso);
46301
+ if (!f) return boxX;
46302
+ const x0 = boxX;
46303
+ const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
46304
+ if (iw < 24) return boxX;
46305
+ const xr = x0 + iw + 2 * PAD;
46306
+ const top = coastTop(x0, xr);
46307
+ const yL = top(x0);
46308
+ const yR = top(xr);
46309
+ proj.fitWidth(iw, f);
46310
+ const bb = (0, import_d3_geo2.geoPath)(proj).bounds(f);
46311
+ const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
46312
+ const needH = sh + 2 * PAD;
46313
+ let topFit = Math.max(yL, yR);
46314
+ const bottom = Math.min(topFit + needH, yB);
46315
+ if (bottom - topFit < needH) topFit = bottom - needH;
46316
+ const lift = topFit - Math.max(yL, yR);
46317
+ const topL = yL + lift;
46318
+ const topR = yR + lift;
46319
+ proj.fitExtent(
46320
+ [
46321
+ [x0 + PAD, topFit + PAD],
46322
+ [xr - PAD, bottom - PAD]
46323
+ ],
46324
+ f
46325
+ );
46326
+ const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
46327
+ if (!d) return xr;
46328
+ const r = regionById.get(iso);
46329
+ let fill2 = neutralFill;
46330
+ let lineNumber = -1;
46331
+ if (r?.layer === "us-state") {
46332
+ fill2 = regionFill(r);
46333
+ lineNumber = r.lineNumber;
46334
+ }
46335
+ insets.push({
46336
+ x: x0,
46337
+ y: Math.min(topL, topR),
46338
+ w: xr - x0,
46339
+ h: bottom - Math.min(topL, topR),
46340
+ points: [
46341
+ [x0, topL],
46342
+ [xr, topR],
46343
+ [xr, bottom],
46344
+ [x0, bottom]
46345
+ ]
46346
+ });
46347
+ insetRegions.push({
46348
+ id: iso,
46349
+ d,
46350
+ fill: fill2,
46351
+ stroke: regionStroke,
46352
+ lineNumber,
46353
+ layer: "us-state",
46354
+ ...r?.score !== void 0 && { score: r.score },
46355
+ ...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
46356
+ });
46357
+ const ctr = (0, import_d3_geo2.geoPath)(proj).centroid(f);
46358
+ if (Number.isFinite(ctr[0])) {
46359
+ const name = f.properties?.name ?? iso;
46360
+ insetLabelSeeds.push({ x: ctr[0], y: ctr[1], iso, name, lineNumber });
46361
+ }
46362
+ return xr;
46363
+ };
46364
+ const akRight = placeInset(
46365
+ "US-AK",
46366
+ alaskaProjection(),
46367
+ FIT_PAD,
46368
+ width * 0.15
46369
+ );
46370
+ placeInset("US-HI", hawaiiProjection(), akRight + 24, width * 0.1);
46371
+ }
46372
+ const conusFit = resolved.projection === "albers-usa" && !!usLayer;
46373
+ const cullExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
46374
+ const [[exW, exS], [exE, exN]] = cullExtent;
46375
+ const lonSpan = exE - exW;
46376
+ const latSpan = exN - exS;
46377
+ const isGlobalView = lonSpan >= 270 || latSpan >= 130;
46378
+ const padLon = Math.max(8, lonSpan * 0.35);
46379
+ const padLat = Math.max(8, latSpan * 0.35);
46380
+ const vW = exW - padLon;
46381
+ const vE = exE + padLon;
46382
+ const vS = exS - padLat;
46383
+ const vN = exN + padLat;
46384
+ const vLonCenter = (exW + exE) / 2;
46385
+ const normLon = (lon) => {
46386
+ let L = lon;
46387
+ while (L < vLonCenter - 180) L += 360;
46388
+ while (L > vLonCenter + 180) L -= 360;
46389
+ return L;
46390
+ };
46391
+ const ringOverlapsView = (ring) => {
46392
+ let anyIn = false;
46393
+ let loMin = Infinity, loMax = -Infinity, laMin = Infinity, laMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
46394
+ for (const [rawLon, lat] of ring) {
46395
+ const lon = normLon(rawLon);
46396
+ if (lon >= vW && lon <= vE && lat >= vS && lat <= vN) anyIn = true;
46397
+ if (lon < loMin) loMin = lon;
46398
+ if (lon > loMax) loMax = lon;
46399
+ if (rawLon < rawMin) rawMin = rawLon;
46400
+ if (rawLon > rawMax) rawMax = rawLon;
46401
+ if (lat < laMin) laMin = lat;
46402
+ if (lat > laMax) laMax = lat;
46403
+ }
46404
+ if (loMax - loMin > 270) return false;
46405
+ if (rawMax - rawMin > 180 && loMax - loMin < 90) return false;
46406
+ if (anyIn) return true;
46407
+ if (loMax - loMin > 180) return false;
46408
+ return !(loMax < vW || loMin > vE || laMax < vS || laMin > vN);
46409
+ };
46410
+ const cullFeatureToView = (f) => {
46411
+ if (isGlobalView) return f;
46412
+ const g = f.geometry;
46413
+ if (!g) return f;
46414
+ if (g.type === "Polygon") {
46415
+ const ring = g.coordinates[0];
46416
+ return ringOverlapsView(ring) ? f : null;
46417
+ }
46418
+ if (g.type === "MultiPolygon") {
46419
+ const polys = g.coordinates;
46420
+ const keep = polys.filter(
46421
+ (p) => ringOverlapsView(p[0])
46422
+ );
46423
+ if (!keep.length) return null;
46424
+ if (keep.length === polys.length) return f;
46425
+ return { ...f, geometry: { ...g, coordinates: keep } };
46426
+ }
46427
+ return f;
46428
+ };
46429
+ const SEAM_SLIVER_MAX_SPAN = 100;
46430
+ const ringIsFrameFiller = (ring) => {
46431
+ const lons = ring.map(([lon]) => lon).sort((a, b) => a - b);
46432
+ if (lons.length < 2) return false;
46433
+ let maxGap = -1;
46434
+ let gapIdx = 0;
46435
+ for (let i = 1; i < lons.length; i++) {
46436
+ const g = lons[i] - lons[i - 1];
46437
+ if (g > maxGap) {
46438
+ maxGap = g;
46439
+ gapIdx = i;
46440
+ }
46441
+ }
46442
+ const wrapGap = lons[0] + 360 - lons[lons.length - 1];
46443
+ if (wrapGap >= maxGap) return false;
46444
+ const span = 360 - maxGap;
46445
+ const east = lons[gapIdx - 1] + 360;
46446
+ return east > 180 && span < SEAM_SLIVER_MAX_SPAN;
46447
+ };
46448
+ const dropFrameFillers = (f) => {
46449
+ const g = f.geometry;
46450
+ if (!g) return f;
46451
+ if (g.type === "Polygon") {
46452
+ const ring = g.coordinates[0];
46453
+ return ringIsFrameFiller(ring) ? null : f;
46454
+ }
46455
+ if (g.type === "MultiPolygon") {
46456
+ const polys = g.coordinates;
46457
+ const keep = polys.filter(
46458
+ (p) => !ringIsFrameFiller(p[0])
46459
+ );
46460
+ if (!keep.length) return null;
46461
+ if (keep.length === polys.length) return f;
46462
+ return { ...f, geometry: { ...g, coordinates: keep } };
46463
+ }
46464
+ return f;
46465
+ };
45991
46466
  const regions = [];
45992
- const pushRegionLayer = (layerFeatures, layerKind) => {
46467
+ const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
45993
46468
  for (const [iso, f] of layerFeatures) {
45994
- const d = path(f) ?? "";
45995
- if (!d) continue;
46469
+ if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
46470
+ continue;
46471
+ if (layerKind === "country" && usContext && iso === "US") continue;
45996
46472
  const r = regionById.get(iso);
46473
+ const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
46474
+ if (!viewF) continue;
46475
+ const d = path(viewF) ?? "";
46476
+ if (!d) continue;
45997
46477
  const isThisLayer = r?.layer === layerKind;
45998
- let fill2 = neutralFill;
46478
+ const isForeign = layerKind === "country" && usContext && iso !== "US";
46479
+ let fill2 = isForeign ? foreignFill : neutralFill;
45999
46480
  let label;
46000
46481
  let lineNumber = -1;
46001
46482
  let layer = "base";
46002
46483
  if (isThisLayer) {
46003
- if (r.score !== void 0) fill2 = fillForScore(r.score);
46004
- else fill2 = tagFill(r.tags, activeGroup) ?? neutralFill;
46484
+ fill2 = regionFill(r);
46005
46485
  lineNumber = r.lineNumber;
46006
46486
  layer = layerKind;
46007
46487
  label = r.name;
@@ -46013,12 +46493,42 @@ function layoutMap(resolved, data, size, opts) {
46013
46493
  stroke: regionStroke,
46014
46494
  lineNumber,
46015
46495
  layer,
46016
- ...label !== void 0 && { label }
46496
+ ...label !== void 0 && { label },
46497
+ ...isThisLayer && r.score !== void 0 && { score: r.score },
46498
+ ...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
46017
46499
  });
46018
46500
  }
46019
46501
  };
46020
- pushRegionLayer(worldLayer, "country");
46021
- if (usLayer) pushRegionLayer(usLayer, "us-state");
46502
+ pushRegionLayer(worldLayer, "country", !isGlobalView);
46503
+ if (usLayer) pushRegionLayer(usLayer, "us-state", !conusFit && !isGlobalView);
46504
+ const lakesTopo = usCrisp && data.naLakes ? data.naLakes : data.lakes;
46505
+ if (lakesTopo) {
46506
+ for (const [, f] of decodeLayer(lakesTopo)) {
46507
+ const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
46508
+ if (!viewF) continue;
46509
+ const d = path(viewF) ?? "";
46510
+ if (!d) continue;
46511
+ regions.push({
46512
+ id: "lake",
46513
+ d,
46514
+ fill: water,
46515
+ stroke: "none",
46516
+ lineNumber: -1,
46517
+ layer: "base"
46518
+ });
46519
+ }
46520
+ }
46521
+ const riverColor = water;
46522
+ const rivers = [];
46523
+ if (data.rivers) {
46524
+ for (const [, f] of decodeLayer(data.rivers)) {
46525
+ const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
46526
+ if (!viewF) continue;
46527
+ const d = path(viewF) ?? "";
46528
+ if (!d) continue;
46529
+ rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
46530
+ }
46531
+ }
46022
46532
  const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
46023
46533
  const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
46024
46534
  const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
@@ -46039,8 +46549,8 @@ function layoutMap(resolved, data, size, opts) {
46039
46549
  if (hex) return { fill: hex, stroke: mix(hex, palette.text, 18) };
46040
46550
  }
46041
46551
  return {
46042
- fill: palette.accent,
46043
- stroke: mix(palette.accent, palette.text, 18)
46552
+ fill: palette.colors.orange,
46553
+ stroke: mix(palette.colors.orange, palette.text, 18)
46044
46554
  };
46045
46555
  };
46046
46556
  const routeNumberById = /* @__PURE__ */ new Map();
@@ -46078,7 +46588,7 @@ function layoutMap(resolved, data, size, opts) {
46078
46588
  cy += Math.sin(ang) * COLO_R;
46079
46589
  }
46080
46590
  const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
46081
- poiScreen.set(e.p.id, { cx, cy });
46591
+ poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
46082
46592
  const num = routeNumberById.get(e.p.id);
46083
46593
  pois.push({
46084
46594
  id: e.p.id,
@@ -46095,17 +46605,36 @@ function layoutMap(resolved, data, size, opts) {
46095
46605
  });
46096
46606
  }
46097
46607
  const legs = [];
46608
+ const RIM_GAP = 1.5;
46098
46609
  const legPath = (a, b, curved, offset) => {
46099
- if (!curved && offset === 0) return `M${a.cx},${a.cy}L${b.cx},${b.cy}`;
46100
46610
  const mx = (a.cx + b.cx) / 2;
46101
46611
  const my = (a.cy + b.cy) / 2;
46102
46612
  const dx = b.cx - a.cx;
46103
46613
  const dy = b.cy - a.cy;
46104
46614
  const len = Math.hypot(dx, dy) || 1;
46615
+ const trimA = Math.min(a.r + RIM_GAP, len * 0.45);
46616
+ const trimB = Math.min(b.r + RIM_GAP, len * 0.45);
46617
+ if (!curved && offset === 0) {
46618
+ const ux = dx / len;
46619
+ const uy = dy / len;
46620
+ const ax2 = a.cx + ux * trimA;
46621
+ const ay2 = a.cy + uy * trimA;
46622
+ const bx2 = b.cx - ux * trimB;
46623
+ const by2 = b.cy - uy * trimB;
46624
+ return `M${ax2},${ay2}L${bx2},${by2}`;
46625
+ }
46105
46626
  const nx = -dy / len;
46106
46627
  const ny = dx / len;
46107
46628
  const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
46108
- return `M${a.cx},${a.cy}Q${mx + nx * bow},${my + ny * bow} ${b.cx},${b.cy}`;
46629
+ const px = mx + nx * bow;
46630
+ const py = my + ny * bow;
46631
+ const ta = Math.hypot(px - a.cx, py - a.cy) || 1;
46632
+ const tb = Math.hypot(b.cx - px, b.cy - py) || 1;
46633
+ const ax = a.cx + (px - a.cx) / ta * trimA;
46634
+ const ay = a.cy + (py - a.cy) / ta * trimA;
46635
+ const bx = b.cx - (b.cx - px) / tb * trimB;
46636
+ const by = b.cy - (b.cy - py) / tb * trimB;
46637
+ return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
46109
46638
  };
46110
46639
  for (const rt of resolved.routes) {
46111
46640
  const curved = rt.meta["style"] === "arc";
@@ -46116,7 +46645,7 @@ function layoutMap(resolved, data, size, opts) {
46116
46645
  legs.push({
46117
46646
  d: legPath(a, b, curved, 0),
46118
46647
  width: W_MIN,
46119
- color: mix(palette.text, palette.bg, 55),
46648
+ color: mix(palette.text, palette.bg, 72),
46120
46649
  arrow: true,
46121
46650
  lineNumber: rt.lineNumber
46122
46651
  });
@@ -46152,7 +46681,7 @@ function layoutMap(resolved, data, size, opts) {
46152
46681
  legs.push({
46153
46682
  d: legPath(a, b, curved, offset),
46154
46683
  width: widthFor(e),
46155
- color: mix(palette.text, palette.bg, 45),
46684
+ color: mix(palette.text, palette.bg, 66),
46156
46685
  arrow: e.directed,
46157
46686
  lineNumber: e.lineNumber,
46158
46687
  ...e.label !== void 0 && {
@@ -46164,38 +46693,92 @@ function layoutMap(resolved, data, size, opts) {
46164
46693
  });
46165
46694
  }
46166
46695
  const labels = [];
46167
- const pinList = [];
46168
46696
  const obstacles = [];
46169
46697
  const markers = pois.map((p) => ({
46170
46698
  cx: p.cx,
46171
46699
  cy: p.cy,
46172
46700
  r: p.r
46173
46701
  }));
46174
- const collides = (rect) => markers.some((m) => rectCircleOverlap(rect, m)) || obstacles.some((o) => rectsOverlap(rect, o));
46702
+ const legSegments = [];
46703
+ for (const leg of legs) {
46704
+ const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
46705
+ leg.d
46706
+ );
46707
+ if (!m) continue;
46708
+ const x0 = +m[1];
46709
+ const y0 = +m[2];
46710
+ if (m[3] !== void 0) {
46711
+ legSegments.push([x0, y0, +m[3], +m[4]]);
46712
+ } else {
46713
+ const cx = +m[5];
46714
+ const cy = +m[6];
46715
+ const ex = +m[7];
46716
+ const ey = +m[8];
46717
+ const N = 8;
46718
+ let px = x0;
46719
+ let py = y0;
46720
+ for (let i = 1; i <= N; i++) {
46721
+ const t = i / N;
46722
+ const u = 1 - t;
46723
+ const qx = u * u * x0 + 2 * u * t * cx + t * t * ex;
46724
+ const qy = u * u * y0 + 2 * u * t * cy + t * t * ey;
46725
+ legSegments.push([px, py, qx, qy]);
46726
+ px = qx;
46727
+ py = qy;
46728
+ }
46729
+ }
46730
+ }
46731
+ 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));
46175
46732
  const regionLabelMode = resolved.directives.regionLabels ?? "off";
46733
+ const LABEL_PADX = 6;
46734
+ const LABEL_PADY = 3;
46735
+ const labelW = (text) => measureLegendText(text, FONT) + 2 * LABEL_PADX;
46736
+ const labelH = FONT + 2 * LABEL_PADY;
46737
+ const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
46738
+ const color = contrastText(
46739
+ fill2,
46740
+ palette.textOnFillLight,
46741
+ palette.textOnFillDark
46742
+ );
46743
+ const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
46744
+ labels.push({
46745
+ x,
46746
+ y,
46747
+ text,
46748
+ anchor: "middle",
46749
+ color,
46750
+ halo: true,
46751
+ haloColor,
46752
+ lineNumber
46753
+ });
46754
+ };
46755
+ const WORLD_LABEL_ANCHORS = {
46756
+ US: [-98.5, 39.5]
46757
+ // CONUS geographic centre (near Lebanon, Kansas)
46758
+ };
46176
46759
  if (regionLabelMode === "full" || regionLabelMode === "abbrev") {
46177
46760
  for (const r of regions) {
46178
46761
  if (r.layer === "base" || r.label === void 0) continue;
46179
46762
  const f = r.layer === "us-state" ? usLayer?.get(r.id) : worldLayer.get(r.id);
46180
46763
  if (!f) continue;
46181
46764
  const [[x0, y0], [x1, y1]] = path.bounds(f);
46182
- if ((x1 - x0) * (y1 - y0) < TINY_REGION_AREA) continue;
46183
- const c = path.centroid(f);
46184
- if (!Number.isFinite(c[0])) continue;
46185
46765
  const text = regionLabelMode === "abbrev" ? r.id.replace(/^US-/, "") : r.label;
46186
- labels.push({
46187
- x: c[0],
46188
- y: c[1],
46766
+ if (labelW(text) > x1 - x0 || labelH > y1 - y0) continue;
46767
+ const anchor = r.layer !== "us-state" ? WORLD_LABEL_ANCHORS[r.id] : void 0;
46768
+ const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
46769
+ if (!c || !Number.isFinite(c[0])) continue;
46770
+ pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
46771
+ }
46772
+ for (const seed of insetLabelSeeds) {
46773
+ const text = regionLabelMode === "abbrev" ? seed.iso.replace(/^US-/, "") : seed.name;
46774
+ const src = regionById.get(seed.iso);
46775
+ pushRegionLabel(
46776
+ seed.x,
46777
+ seed.y,
46189
46778
  text,
46190
- anchor: "middle",
46191
- color: contrastText(
46192
- r.fill,
46193
- palette.textOnFillLight,
46194
- palette.textOnFillDark
46195
- ),
46196
- halo: true,
46197
- lineNumber: r.lineNumber
46198
- });
46779
+ src ? regionFill(src) : neutralFill,
46780
+ seed.lineNumber
46781
+ );
46199
46782
  }
46200
46783
  }
46201
46784
  const poiLabelMode = resolved.directives.poiLabels ?? "auto";
@@ -46208,68 +46791,106 @@ function layoutMap(resolved, data, size, opts) {
46208
46791
  const src = poiById.get(p.id);
46209
46792
  return src?.label ?? src?.name ?? p.id;
46210
46793
  };
46211
- let pinCounter = 0;
46212
- for (const p of ordered) {
46794
+ const poiLabH = FONT * 1.25;
46795
+ const labelInfo = (p) => {
46213
46796
  const text = labelText(p);
46214
- const w = measureLegendText(text, FONT);
46215
- const h = FONT * 1.25;
46216
- const inline = { x: p.cx + p.r + 3, y: p.cy - h / 2, w, h };
46217
- if (!collides(inline)) {
46218
- obstacles.push(inline);
46797
+ return { text, w: measureLegendText(text, FONT) };
46798
+ };
46799
+ const pushInline = (p, text, w, side) => {
46800
+ const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
46801
+ obstacles.push({
46802
+ x: side === "right" ? tx : tx - w,
46803
+ y: p.cy - poiLabH / 2,
46804
+ w,
46805
+ h: poiLabH
46806
+ });
46807
+ labels.push({
46808
+ x: tx,
46809
+ y: p.cy + FONT / 3,
46810
+ text,
46811
+ anchor: side === "right" ? "start" : "end",
46812
+ color: palette.text,
46813
+ halo: true,
46814
+ haloColor: palette.bg,
46815
+ poiId: p.id,
46816
+ lineNumber: p.lineNumber
46817
+ });
46818
+ };
46819
+ const inlineFits = (p, w, side) => {
46820
+ const tx = side === "right" ? p.cx + p.r + 3 : p.cx - p.r - 3;
46821
+ const rect = {
46822
+ x: side === "right" ? tx : tx - w,
46823
+ y: p.cy - poiLabH / 2,
46824
+ w,
46825
+ h: poiLabH
46826
+ };
46827
+ return rect.x >= 0 && rect.x + rect.w <= width && !collides(rect);
46828
+ };
46829
+ const GROUP_R = 30;
46830
+ const groups = [];
46831
+ for (const p of ordered) {
46832
+ const near = groups.find(
46833
+ (g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
46834
+ );
46835
+ if (near) near.push(p);
46836
+ else groups.push([p]);
46837
+ }
46838
+ const ROW_GAP2 = 3;
46839
+ const step = poiLabH + ROW_GAP2;
46840
+ const COL_GAP = 16;
46841
+ const placeColumn = (group) => {
46842
+ const items = group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
46843
+ const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
46844
+ const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
46845
+ const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
46846
+ const maxW = Math.max(...items.map((o) => o.w));
46847
+ const side = right + COL_GAP + maxW <= width - 2 ? "right" : "left";
46848
+ const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
46849
+ const totalH = items.length * step;
46850
+ let startY = cyMid - totalH / 2;
46851
+ startY = Math.max(2, Math.min(startY, height - totalH - 2));
46852
+ items.forEach((o, i) => {
46853
+ const rowCy = startY + i * step + step / 2;
46854
+ obstacles.push({
46855
+ x: side === "right" ? colX : colX - o.w,
46856
+ y: rowCy - poiLabH / 2,
46857
+ w: o.w,
46858
+ h: poiLabH
46859
+ });
46219
46860
  labels.push({
46220
- x: inline.x,
46221
- y: p.cy + FONT / 3,
46222
- text,
46223
- anchor: "start",
46861
+ x: colX,
46862
+ y: rowCy + FONT / 3,
46863
+ text: o.text,
46864
+ anchor: side === "right" ? "start" : "end",
46224
46865
  color: palette.text,
46225
46866
  halo: true,
46226
- lineNumber: p.lineNumber
46867
+ haloColor: palette.bg,
46868
+ leader: {
46869
+ x1: o.p.cx,
46870
+ y1: o.p.cy,
46871
+ x2: side === "right" ? colX - 2 : colX + 2,
46872
+ y2: rowCy
46873
+ },
46874
+ leaderColor: o.p.fill,
46875
+ poiId: o.p.id,
46876
+ lineNumber: o.p.lineNumber
46227
46877
  });
46228
- continue;
46229
- }
46230
- let placed = false;
46231
- for (let k = 1; k <= 2 && !placed; k++) {
46232
- for (const [dx, dy] of RING_DIRS) {
46233
- const cx = p.cx + dx * LEADER_STEP * k;
46234
- const cy = p.cy + dy * LEADER_STEP * k;
46235
- const rect = {
46236
- x: dx >= 0 ? cx : cx - w,
46237
- y: cy - h / 2,
46238
- w,
46239
- h
46240
- };
46241
- if (rect.x < 0 || rect.x + rect.w > width || rect.y < 0 || rect.y + rect.h > height) {
46242
- continue;
46243
- }
46244
- if (collides(rect)) continue;
46245
- obstacles.push(rect);
46246
- labels.push({
46247
- x: cx,
46248
- y: cy + FONT / 3,
46249
- text,
46250
- anchor: dx >= 0 ? "start" : "end",
46251
- color: palette.text,
46252
- halo: true,
46253
- leader: { x1: p.cx, y1: p.cy, x2: cx, y2: cy },
46254
- lineNumber: p.lineNumber
46255
- });
46256
- placed = true;
46257
- break;
46878
+ });
46879
+ };
46880
+ for (const g of groups) {
46881
+ if (g.length === 1) {
46882
+ const p = g[0];
46883
+ const { text, w } = labelInfo(p);
46884
+ if (inlineFits(p, w, "right")) {
46885
+ pushInline(p, text, w, "right");
46886
+ continue;
46887
+ }
46888
+ if (inlineFits(p, w, "left")) {
46889
+ pushInline(p, text, w, "left");
46890
+ continue;
46258
46891
  }
46259
46892
  }
46260
- if (placed) continue;
46261
- pinCounter += 1;
46262
- pinList.push({ pin: pinCounter, label: text });
46263
- labels.push({
46264
- x: p.cx + p.r + 2,
46265
- y: p.cy - p.r,
46266
- text: String(pinCounter),
46267
- anchor: "start",
46268
- color: palette.text,
46269
- halo: true,
46270
- pin: pinCounter,
46271
- lineNumber: p.lineNumber
46272
- });
46893
+ placeColumn(g);
46273
46894
  }
46274
46895
  }
46275
46896
  let legend = null;
@@ -46278,8 +46899,7 @@ function layoutMap(resolved, data, size, opts) {
46278
46899
  name: g.name,
46279
46900
  entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
46280
46901
  }));
46281
- const hasAnything = tagGroups.length > 0 || hasRamp || sizeVals.length > 0 || weightVals.length > 0;
46282
- if (hasAnything) {
46902
+ if (tagGroups.length > 0 || hasRamp) {
46283
46903
  legend = {
46284
46904
  tagGroups,
46285
46905
  activeGroup,
@@ -46290,20 +46910,9 @@ function layoutMap(resolved, data, size, opts) {
46290
46910
  },
46291
46911
  min: rampMin,
46292
46912
  max: rampMax,
46293
- hue: rampHue
46294
- }
46295
- },
46296
- ...sizeVals.length > 0 && {
46297
- size: {
46298
- ...resolved.directives.sizeMetric !== void 0 && {
46299
- metric: resolved.directives.sizeMetric
46300
- },
46301
- min: sizeMin,
46302
- max: sizeMax
46913
+ hue: rampHue,
46914
+ base: rampBase
46303
46915
  }
46304
- },
46305
- ...weightVals.length > 0 && {
46306
- weight: { min: wMin, max: wMax }
46307
46916
  }
46308
46917
  };
46309
46918
  }
@@ -46311,28 +46920,30 @@ function layoutMap(resolved, data, size, opts) {
46311
46920
  return {
46312
46921
  width,
46313
46922
  height,
46314
- background: palette.bg,
46923
+ background: water,
46315
46924
  title: resolved.title,
46316
46925
  ...resolved.subtitle !== void 0 && { subtitle: resolved.subtitle },
46317
46926
  ...resolved.caption !== void 0 && { caption: resolved.caption },
46318
46927
  regions,
46928
+ rivers,
46319
46929
  legs,
46320
46930
  pois,
46321
46931
  labels,
46322
- pinList,
46323
- legend
46932
+ legend,
46933
+ insets,
46934
+ insetRegions
46324
46935
  };
46325
46936
  }
46326
- var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT, LEADER_STEP, COLO_EPS, COLO_R, GOLDEN_ANGLE, FAN_STEP, TINY_REGION_AREA, ARC_CURVE_FRAC, RING_DIRS;
46937
+ 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;
46327
46938
  var init_layout15 = __esm({
46328
46939
  "src/map/layout.ts"() {
46329
46940
  "use strict";
46330
46941
  import_d3_geo2 = require("d3-geo");
46331
46942
  import_topojson_client2 = require("topojson-client");
46332
46943
  init_color_utils();
46333
- init_tag_groups();
46334
46944
  init_label_layout();
46335
46945
  init_legend_constants();
46946
+ init_title_constants();
46336
46947
  FIT_PAD = 24;
46337
46948
  RAMP_FLOOR = 15;
46338
46949
  R_DEFAULT = 6;
@@ -46341,23 +46952,32 @@ var init_layout15 = __esm({
46341
46952
  W_MIN = 1.25;
46342
46953
  W_MAX = 8;
46343
46954
  FONT = 11;
46344
- LEADER_STEP = 14;
46345
46955
  COLO_EPS = 1.5;
46956
+ LAND_TINT_LIGHT = 58;
46957
+ LAND_TINT_DARK = 75;
46958
+ TAG_TINT_LIGHT = 60;
46959
+ TAG_TINT_DARK = 68;
46960
+ WATER_TINT = 55;
46961
+ RIVER_WIDTH = 1.3;
46962
+ FOREIGN_TINT_LIGHT = 30;
46963
+ FOREIGN_TINT_DARK = 62;
46346
46964
  COLO_R = 9;
46347
46965
  GOLDEN_ANGLE = 2.399963229728653;
46348
46966
  FAN_STEP = 16;
46349
- TINY_REGION_AREA = 600;
46350
46967
  ARC_CURVE_FRAC = 0.18;
46351
- RING_DIRS = [
46352
- [1, 0],
46353
- [0, 1],
46354
- [-1, 0],
46355
- [0, -1],
46356
- [1, 1],
46357
- [-1, 1],
46358
- [-1, -1],
46359
- [1, -1]
46360
- ];
46968
+ usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
46969
+ alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
46970
+ hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
46971
+ INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
46972
+ US_NON_CONUS = /* @__PURE__ */ new Set([
46973
+ "US-AK",
46974
+ "US-HI",
46975
+ "US-AS",
46976
+ "US-GU",
46977
+ "US-MP",
46978
+ "US-PR",
46979
+ "US-VI"
46980
+ ]);
46361
46981
  }
46362
46982
  });
46363
46983
 
@@ -46367,7 +46987,7 @@ __export(renderer_exports16, {
46367
46987
  renderMap: () => renderMap,
46368
46988
  renderMapForExport: () => renderMapForExport
46369
46989
  });
46370
- function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims) {
46990
+ function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
46371
46991
  d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
46372
46992
  const width = exportDims?.width ?? container.clientWidth;
46373
46993
  const height = exportDims?.height ?? container.clientHeight;
@@ -46378,27 +46998,29 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
46378
46998
  { width, height },
46379
46999
  {
46380
47000
  palette,
46381
- isDark
47001
+ isDark,
47002
+ ...activeGroupOverride !== void 0 && {
47003
+ activeGroup: activeGroupOverride
47004
+ }
46382
47005
  }
46383
47006
  );
46384
- 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);
47007
+ 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);
46385
47008
  svg.append("rect").attr("width", width).attr("height", height).attr("fill", layout.background);
46386
- const arrowColor = mix(palette.text, palette.bg, 50);
46387
47009
  const defs = svg.append("defs");
46388
- defs.append("marker").attr("id", "dgmo-map-arrow").attr("viewBox", "0 0 10 10").attr("refX", 9).attr("refY", 5).attr("markerWidth", 7).attr("markerHeight", 7).attr("orient", "auto-start-reverse").append("path").attr("d", "M0,0L10,5L0,10z").attr("fill", arrowColor);
46389
- const haloColor = layout.background;
46390
- if (layout.title) {
46391
- 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);
46392
- }
46393
- if (layout.subtitle) {
46394
- 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);
46395
- }
46396
- if (layout.caption) {
46397
- 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);
46398
- }
47010
+ const arrowSize = (w) => Math.min(15, 7 + w * 0.95);
47011
+ const haloColor = palette.bg;
46399
47012
  const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
46400
- for (const r of layout.regions) {
46401
- const p = gRegions.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", 0.5);
47013
+ const drawRegion = (g, r, strokeWidth) => {
47014
+ const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
47015
+ if (r.layer !== "base") {
47016
+ p.classed("dgmo-map-region", true).attr("data-region", r.id);
47017
+ if (r.score !== void 0) p.attr("data-score", r.score);
47018
+ if (r.tags) {
47019
+ for (const [group, value] of Object.entries(r.tags)) {
47020
+ p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
47021
+ }
47022
+ }
47023
+ }
46402
47024
  if (r.lineNumber >= 0) {
46403
47025
  p.attr("data-line-number", r.lineNumber);
46404
47026
  if (onClickItem) {
@@ -46408,11 +47030,31 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
46408
47030
  );
46409
47031
  }
46410
47032
  }
47033
+ };
47034
+ for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
47035
+ if (layout.rivers.length) {
47036
+ const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
47037
+ for (const r of layout.rivers) {
47038
+ gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
47039
+ }
47040
+ }
47041
+ if (layout.insets.length) {
47042
+ const insetG = svg.append("g").attr("class", "dgmo-map-insets");
47043
+ for (const box of layout.insets) {
47044
+ const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
47045
+ 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");
47046
+ }
47047
+ for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
46411
47048
  }
46412
47049
  const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
46413
- for (const leg of layout.legs) {
47050
+ layout.legs.forEach((leg, i) => {
46414
47051
  const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
46415
- if (leg.arrow) p.attr("marker-end", "url(#dgmo-map-arrow)");
47052
+ if (leg.arrow) {
47053
+ const id = `dgmo-map-arrow-${i}`;
47054
+ const s = arrowSize(leg.width);
47055
+ 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);
47056
+ p.attr("marker-end", `url(#${id})`);
47057
+ }
46416
47058
  if (leg.label !== void 0 && leg.labelX !== void 0) {
46417
47059
  emitText(
46418
47060
  gLegs,
@@ -46426,13 +47068,13 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
46426
47068
  LABEL_FONT - 1
46427
47069
  );
46428
47070
  }
46429
- }
47071
+ });
46430
47072
  const gPois = svg.append("g").attr("class", "dgmo-map-pois");
46431
47073
  for (const poi of layout.pois) {
46432
47074
  if (poi.isOrigin) {
46433
47075
  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);
46434
47076
  }
46435
- 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);
47077
+ 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);
46436
47078
  if (onClickItem) {
46437
47079
  c.style("cursor", "pointer").on(
46438
47080
  "click",
@@ -46456,48 +47098,66 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
46456
47098
  const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
46457
47099
  for (const lab of layout.labels) {
46458
47100
  if (lab.leader) {
46459
- gLabels.append("line").attr("x1", lab.leader.x1).attr("y1", lab.leader.y1).attr("x2", lab.leader.x2).attr("y2", lab.leader.y2).attr("stroke", mix(palette.textMuted, palette.bg, 60)).attr("stroke-width", 0.75);
47101
+ 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(
47102
+ "stroke",
47103
+ lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
47104
+ ).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
47105
+ if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
46460
47106
  }
46461
- if (lab.pin !== void 0) {
46462
- 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);
46463
- }
46464
- emitText(
47107
+ const t = emitText(
46465
47108
  gLabels,
46466
47109
  lab.x,
46467
47110
  lab.y,
46468
47111
  lab.text,
46469
47112
  lab.anchor,
46470
47113
  lab.color,
46471
- haloColor,
47114
+ lab.haloColor,
46472
47115
  lab.halo,
46473
47116
  LABEL_FONT
46474
47117
  );
46475
- }
46476
- if (layout.pinList.length > 0) {
46477
- const gPins = svg.append("g").attr("class", "dgmo-map-pin-list").attr(
46478
- "transform",
46479
- `translate(12, ${height - layout.pinList.length * 14 - 8})`
46480
- );
46481
- layout.pinList.forEach((entry, i) => {
46482
- 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}`);
46483
- });
47118
+ if (lab.poiId !== void 0) {
47119
+ t.attr("data-poi", lab.poiId).style("cursor", "default");
47120
+ }
46484
47121
  }
46485
47122
  if (layout.legend) {
46486
47123
  const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
46487
47124
  const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
46488
- const groups = layout.legend.tagGroups.filter((g) => g.entries.length > 0);
47125
+ const ramp = layout.legend.ramp;
47126
+ const scoreGroup = ramp ? {
47127
+ name: ramp.metric?.trim() || "Score",
47128
+ entries: [],
47129
+ gradient: {
47130
+ min: ramp.min,
47131
+ max: ramp.max,
47132
+ hue: ramp.hue,
47133
+ base: ramp.base
47134
+ }
47135
+ } : null;
47136
+ const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
47137
+ const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
46489
47138
  if (groups.length > 0) {
46490
47139
  const config = {
46491
- groups: groups.map((g) => ({ name: g.name, entries: [...g.entries] })),
47140
+ groups,
46492
47141
  position: { placement: "top-center", titleRelation: "below-title" },
46493
47142
  mode: exportDims ? "export" : "preview",
46494
- showEmptyGroups: false
47143
+ showEmptyGroups: false,
47144
+ // Keep inactive siblings visible as pills so the user can click to flip
47145
+ // the active colouring dimension (preview only — export shows just the
47146
+ // active group).
47147
+ showInactivePills: true
46495
47148
  };
46496
47149
  const state = { activeGroup: layout.legend.activeGroup };
46497
47150
  renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
46498
47151
  }
46499
- const pinGap = layout.pinList.length ? layout.pinList.length * 14 + 14 : 0;
46500
- emitExtraLegend(svg, layout, palette, height, pinGap);
47152
+ }
47153
+ if (layout.title) {
47154
+ 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);
47155
+ }
47156
+ if (layout.subtitle) {
47157
+ 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);
47158
+ }
47159
+ if (layout.caption) {
47160
+ 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);
46501
47161
  }
46502
47162
  }
46503
47163
  function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
@@ -46508,54 +47168,7 @@ function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
46508
47168
  if (withHalo) {
46509
47169
  t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7);
46510
47170
  }
46511
- }
46512
- function emitExtraLegend(svg, layout, palette, height, bottomGap) {
46513
- const { legend } = layout;
46514
- if (!legend) return;
46515
- if (!legend.ramp && !legend.size && !legend.weight) return;
46516
- const blocks = [];
46517
- const g = svg.append("g").attr("class", "dgmo-map-legend-keys").attr("transform", `translate(12, ${height - 56 - bottomGap})`);
46518
- let xCursor = 0;
46519
- if (legend.ramp) {
46520
- const ramp = legend.ramp;
46521
- blocks.push(() => {
46522
- const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
46523
- const gradId = "dgmo-map-ramp";
46524
- const grad = block.append("defs").append("linearGradient").attr("id", gradId).attr("x1", "0%").attr("x2", "100%");
46525
- grad.append("stop").attr("offset", "0%").attr("stop-color", mix(ramp.hue, palette.bg, 15));
46526
- grad.append("stop").attr("offset", "100%").attr("stop-color", ramp.hue);
46527
- block.append("rect").attr("width", 80).attr("height", 8).attr("fill", `url(#${gradId})`);
46528
- block.append("text").attr("x", 0).attr("y", 22).attr("font-size", 9).attr("fill", palette.textMuted).text(String(ramp.min));
46529
- 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));
46530
- if (ramp.metric) {
46531
- block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(ramp.metric);
46532
- }
46533
- xCursor += 110;
46534
- });
46535
- }
46536
- if (legend.size) {
46537
- const sz = legend.size;
46538
- blocks.push(() => {
46539
- const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
46540
- [3, 6, 10].forEach((r, i) => {
46541
- block.append("circle").attr("cx", i * 26 + r).attr("cy", 8).attr("r", r).attr("fill", "none").attr("stroke", palette.textMuted);
46542
- });
46543
- block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(sz.metric ?? "size");
46544
- xCursor += 110;
46545
- });
46546
- }
46547
- if (legend.weight) {
46548
- const wt = legend.weight;
46549
- blocks.push(() => {
46550
- const block = g.append("g").attr("transform", `translate(${xCursor},0)`);
46551
- [1, 3, 6].forEach((w, i) => {
46552
- 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);
46553
- });
46554
- block.append("text").attr("x", 0).attr("y", -4).attr("font-size", 9).attr("fill", palette.textMuted).text(wt.metric ?? "weight");
46555
- xCursor += 110;
46556
- });
46557
- }
46558
- for (const draw of blocks) draw();
47171
+ return t;
46559
47172
  }
46560
47173
  var d3Selection18, LABEL_FONT;
46561
47174
  var init_renderer16 = __esm({
@@ -53023,18 +53636,18 @@ function getRotateFn(mode) {
53023
53636
  return () => 0;
53024
53637
  }
53025
53638
  function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
53026
- return new Promise((resolve2) => {
53639
+ return new Promise((resolve) => {
53027
53640
  d3Selection23.select(container).selectAll(":not([data-d3-tooltip])").remove();
53028
53641
  const { words, cloudOptions } = parsed;
53029
53642
  const title = parsed.noTitle ? null : parsed.title;
53030
53643
  if (words.length === 0) {
53031
- resolve2();
53644
+ resolve();
53032
53645
  return;
53033
53646
  }
53034
53647
  const width = exportDims?.width ?? container.clientWidth;
53035
53648
  const height = exportDims?.height ?? container.clientHeight;
53036
53649
  if (width <= 0 || height <= 0) {
53037
- resolve2();
53650
+ resolve();
53038
53651
  return;
53039
53652
  }
53040
53653
  const titleHeight = title ? 40 : 0;
@@ -53063,7 +53676,7 @@ function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
53063
53676
  "transform",
53064
53677
  (d) => `translate(${d.x},${d.y}) rotate(${d.rotate})`
53065
53678
  ).text((d) => d.text);
53066
- resolve2();
53679
+ resolve();
53067
53680
  }).start();
53068
53681
  });
53069
53682
  }
@@ -56429,7 +57042,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
56429
57042
 
56430
57043
  // src/auto/index.ts
56431
57044
  init_safe_href();
56432
- var VERSION = "0.19.0";
57045
+ var VERSION = "0.20.1";
56433
57046
  var DEFAULTS = {
56434
57047
  theme: "auto",
56435
57048
  palette: "nord",