@diagrammo/dgmo 0.20.3 → 0.21.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 +867 -286
- package/dist/advanced.js +866 -286
- package/dist/auto.cjs +635 -284
- package/dist/auto.js +113 -113
- package/dist/auto.mjs +635 -284
- package/dist/cli.cjs +156 -156
- package/dist/editor.cjs +6 -2
- package/dist/editor.js +6 -2
- package/dist/highlight.cjs +6 -2
- package/dist/highlight.js +6 -2
- package/dist/index.cjs +628 -281
- package/dist/index.js +628 -281
- package/dist/internal.cjs +867 -286
- package/dist/internal.js +866 -286
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/mountain-ranges.json +1 -0
- package/docs/language-reference.md +27 -25
- package/gallery/fixtures/map-choropleth.dgmo +7 -7
- package/gallery/fixtures/map-direct-color.dgmo +10 -0
- package/gallery/fixtures/map-pois.dgmo +4 -4
- package/gallery/fixtures/map-region-scope.dgmo +8 -8
- package/gallery/fixtures/map-route.dgmo +5 -6
- package/package.json +1 -1
- package/src/advanced.ts +14 -0
- package/src/completion.ts +10 -4
- package/src/d3.ts +15 -9
- package/src/editor/keywords.ts +6 -2
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/mountain-ranges.json +1 -0
- package/src/map/geo-query.ts +277 -0
- package/src/map/geo.ts +258 -1
- package/src/map/invert.ts +111 -0
- package/src/map/layout.ts +333 -139
- package/src/map/load-data.ts +7 -1
- package/src/map/parser.ts +142 -33
- package/src/map/renderer.ts +57 -6
- package/src/map/resolved-types.ts +21 -2
- package/src/map/resolver.ts +219 -53
- package/src/map/types.ts +57 -14
- package/src/utils/reserved-key-registry.ts +7 -7
- package/dist/advanced.d.cts +0 -5290
- package/dist/advanced.d.ts +0 -5290
- package/dist/auto.d.cts +0 -39
- package/dist/auto.d.ts +0 -39
- package/dist/index.d.cts +0 -336
- package/dist/index.d.ts +0 -336
- package/dist/internal.d.cts +0 -5290
- package/dist/internal.d.ts +0 -5290
package/dist/internal.js
CHANGED
|
@@ -855,13 +855,9 @@ var init_reserved_key_registry = __esm({
|
|
|
855
855
|
"icon"
|
|
856
856
|
]);
|
|
857
857
|
MAP_REGISTRY = staticRegistry([
|
|
858
|
-
"
|
|
858
|
+
"value",
|
|
859
859
|
"label",
|
|
860
|
-
"
|
|
861
|
-
"description",
|
|
862
|
-
"weight",
|
|
863
|
-
"style",
|
|
864
|
-
"date"
|
|
860
|
+
"style"
|
|
865
861
|
]);
|
|
866
862
|
ORG_REGISTRY = staticRegistry([
|
|
867
863
|
"color",
|
|
@@ -15844,7 +15840,8 @@ function parseMap(content) {
|
|
|
15844
15840
|
continue;
|
|
15845
15841
|
}
|
|
15846
15842
|
if (open.route && indent > open.route.indent) {
|
|
15847
|
-
open.route.route.
|
|
15843
|
+
const leg = parseLeg(trimmed, lineNumber, open.route.route.style);
|
|
15844
|
+
open.route.route.legs.push(leg);
|
|
15848
15845
|
continue;
|
|
15849
15846
|
}
|
|
15850
15847
|
if (open.poi && indent > open.poi.indent) {
|
|
@@ -15875,6 +15872,10 @@ function parseMap(content) {
|
|
|
15875
15872
|
handleTag(trimmed, lineNumber);
|
|
15876
15873
|
continue;
|
|
15877
15874
|
}
|
|
15875
|
+
if ((firstWord === "muted" || firstWord === "natural") && trimmed === firstWord) {
|
|
15876
|
+
handleDirective(firstWord, "", lineNumber);
|
|
15877
|
+
continue;
|
|
15878
|
+
}
|
|
15878
15879
|
if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
|
|
15879
15880
|
handleDirective(
|
|
15880
15881
|
firstWord,
|
|
@@ -15939,13 +15940,20 @@ function parseMap(content) {
|
|
|
15939
15940
|
);
|
|
15940
15941
|
d.projection = value;
|
|
15941
15942
|
break;
|
|
15942
|
-
case "metric":
|
|
15943
|
-
dup(d.
|
|
15944
|
-
|
|
15943
|
+
case "region-metric": {
|
|
15944
|
+
dup(d.regionMetric);
|
|
15945
|
+
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
15946
|
+
d.regionMetric = rmLabel;
|
|
15947
|
+
if (rmColor) d.regionMetricColor = rmColor;
|
|
15948
|
+
break;
|
|
15949
|
+
}
|
|
15950
|
+
case "poi-metric":
|
|
15951
|
+
dup(d.poiMetric);
|
|
15952
|
+
d.poiMetric = value;
|
|
15945
15953
|
break;
|
|
15946
|
-
case "
|
|
15947
|
-
dup(d.
|
|
15948
|
-
d.
|
|
15954
|
+
case "flow-metric":
|
|
15955
|
+
dup(d.flowMetric);
|
|
15956
|
+
d.flowMetric = value;
|
|
15949
15957
|
break;
|
|
15950
15958
|
case "scale":
|
|
15951
15959
|
dup(d.scale);
|
|
@@ -15987,6 +15995,21 @@ function parseMap(content) {
|
|
|
15987
15995
|
case "no-legend":
|
|
15988
15996
|
d.noLegend = true;
|
|
15989
15997
|
break;
|
|
15998
|
+
case "no-insets":
|
|
15999
|
+
d.noInsets = true;
|
|
16000
|
+
break;
|
|
16001
|
+
case "relief":
|
|
16002
|
+
d.relief = true;
|
|
16003
|
+
break;
|
|
16004
|
+
case "muted":
|
|
16005
|
+
case "natural":
|
|
16006
|
+
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
16007
|
+
pushWarning(
|
|
16008
|
+
line12,
|
|
16009
|
+
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
16010
|
+
);
|
|
16011
|
+
d.basemapStyle = key;
|
|
16012
|
+
break;
|
|
15990
16013
|
case "subtitle":
|
|
15991
16014
|
dup(d.subtitle);
|
|
15992
16015
|
d.subtitle = value;
|
|
@@ -16064,14 +16087,14 @@ function parseMap(content) {
|
|
|
16064
16087
|
line12
|
|
16065
16088
|
);
|
|
16066
16089
|
const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
|
|
16067
|
-
let
|
|
16068
|
-
const
|
|
16069
|
-
if (
|
|
16070
|
-
delete meta["
|
|
16071
|
-
|
|
16072
|
-
if (!Number.isFinite(
|
|
16073
|
-
pushError(line12, `
|
|
16074
|
-
|
|
16090
|
+
let valueNum;
|
|
16091
|
+
const value = meta["value"];
|
|
16092
|
+
if (value !== void 0) {
|
|
16093
|
+
delete meta["value"];
|
|
16094
|
+
valueNum = Number(value);
|
|
16095
|
+
if (!Number.isFinite(valueNum)) {
|
|
16096
|
+
pushError(line12, `value must be a number (got "${value}").`);
|
|
16097
|
+
valueNum = void 0;
|
|
16075
16098
|
}
|
|
16076
16099
|
}
|
|
16077
16100
|
let regionName = split.name;
|
|
@@ -16089,7 +16112,8 @@ function parseMap(content) {
|
|
|
16089
16112
|
lineNumber: line12
|
|
16090
16113
|
};
|
|
16091
16114
|
if (regionScope !== void 0) region.scope = regionScope;
|
|
16092
|
-
if (
|
|
16115
|
+
if (valueNum !== void 0) region.value = valueNum;
|
|
16116
|
+
if (split.color) region.color = split.color;
|
|
16093
16117
|
regions.push(region);
|
|
16094
16118
|
}
|
|
16095
16119
|
function handlePoi(rest, line12, indent) {
|
|
@@ -16114,28 +16138,81 @@ function parseMap(content) {
|
|
|
16114
16138
|
const poi = { pos, tags, meta, lineNumber: line12 };
|
|
16115
16139
|
if (split.alias) poi.alias = split.alias;
|
|
16116
16140
|
if (label !== void 0) poi.label = label;
|
|
16141
|
+
if (split.color) poi.color = split.color;
|
|
16117
16142
|
pois.push(poi);
|
|
16118
16143
|
open.poi = { poi, indent };
|
|
16119
16144
|
}
|
|
16120
16145
|
function handleRoute(rest, line12, indent) {
|
|
16121
|
-
const
|
|
16122
|
-
|
|
16146
|
+
const split = rest ? splitNameAndMeta(
|
|
16147
|
+
rest,
|
|
16148
|
+
registry(),
|
|
16149
|
+
aliasMap,
|
|
16150
|
+
void 0,
|
|
16151
|
+
diagnostics,
|
|
16152
|
+
line12
|
|
16153
|
+
) : { name: "", meta: {}, alias: void 0 };
|
|
16154
|
+
const pos = parsePos(split.name, line12);
|
|
16155
|
+
if (!pos || pos.kind === "name" && !pos.name) {
|
|
16156
|
+
pushError(
|
|
16157
|
+
line12,
|
|
16158
|
+
"route requires an origin: `route <origin> [style: arc]`."
|
|
16159
|
+
);
|
|
16160
|
+
return;
|
|
16161
|
+
}
|
|
16162
|
+
const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
|
|
16163
|
+
const originLabel = meta["label"];
|
|
16164
|
+
const originValue = meta["value"];
|
|
16165
|
+
const style = meta["style"] === "arc" ? "arc" : "straight";
|
|
16166
|
+
const route = {
|
|
16167
|
+
origin: pos,
|
|
16168
|
+
...split.alias !== void 0 && { originAlias: split.alias },
|
|
16169
|
+
...originLabel !== void 0 && { originLabel },
|
|
16170
|
+
...originValue !== void 0 && { originValue },
|
|
16171
|
+
originTags: tags,
|
|
16172
|
+
style,
|
|
16173
|
+
legs: [],
|
|
16174
|
+
lineNumber: line12
|
|
16175
|
+
};
|
|
16123
16176
|
routes.push(route);
|
|
16124
16177
|
open.route = { route, indent };
|
|
16125
16178
|
}
|
|
16126
|
-
function
|
|
16127
|
-
|
|
16128
|
-
|
|
16179
|
+
function parseLeg(trimmed, line12, headerStyle) {
|
|
16180
|
+
let arrowStyle = "straight";
|
|
16181
|
+
let label;
|
|
16182
|
+
let rest = trimmed;
|
|
16183
|
+
const m = trimmed.match(LEG_ARROW_RE);
|
|
16184
|
+
if (m) {
|
|
16185
|
+
const arr = classifyArrow(m[1], line12);
|
|
16186
|
+
arrowStyle = arr.style;
|
|
16187
|
+
label = arr.label;
|
|
16188
|
+
rest = m[2];
|
|
16189
|
+
}
|
|
16190
|
+
const split = splitNameAndMeta(
|
|
16191
|
+
rest,
|
|
16192
|
+
registry(),
|
|
16193
|
+
aliasMap,
|
|
16194
|
+
void 0,
|
|
16195
|
+
diagnostics,
|
|
16196
|
+
line12
|
|
16197
|
+
);
|
|
16198
|
+
const pos = parsePos(split.name, line12) ?? {
|
|
16129
16199
|
kind: "name",
|
|
16130
16200
|
name: split.name
|
|
16131
16201
|
};
|
|
16132
|
-
const
|
|
16133
|
-
|
|
16134
|
-
|
|
16202
|
+
const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
|
|
16203
|
+
const value = meta["value"];
|
|
16204
|
+
const destLabel = meta["label"];
|
|
16205
|
+
const style = arrowStyle === "arc" || headerStyle === "arc" ? "arc" : "straight";
|
|
16206
|
+
return {
|
|
16207
|
+
...label !== void 0 && { label },
|
|
16208
|
+
style,
|
|
16209
|
+
...value !== void 0 && { value },
|
|
16210
|
+
dest: pos,
|
|
16211
|
+
...split.alias !== void 0 && { destAlias: split.alias },
|
|
16212
|
+
...destLabel !== void 0 && { destLabel },
|
|
16213
|
+
destTags: tags,
|
|
16135
16214
|
lineNumber: line12
|
|
16136
16215
|
};
|
|
16137
|
-
if (split.alias) stop.alias = split.alias;
|
|
16138
|
-
return stop;
|
|
16139
16216
|
}
|
|
16140
16217
|
function handleEdges(trimmed, line12) {
|
|
16141
16218
|
const parts = trimmed.split(ARROW_SPLIT);
|
|
@@ -16237,7 +16314,7 @@ function partitionMeta(meta, tagGroupNames) {
|
|
|
16237
16314
|
function poiName(pos) {
|
|
16238
16315
|
return pos.kind === "name" ? pos.name : void 0;
|
|
16239
16316
|
}
|
|
16240
|
-
var COORD_RE, NUMERIC_LEAD_RE, SCOPE_RE, ARROW_SPLIT, HUB_RE, AT_RE, DIRECTIVE_SET;
|
|
16317
|
+
var COORD_RE, NUMERIC_LEAD_RE, SCOPE_RE, ARROW_SPLIT, HUB_RE, LEG_ARROW_RE, AT_RE, DIRECTIVE_SET;
|
|
16241
16318
|
var init_parser12 = __esm({
|
|
16242
16319
|
"src/map/parser.ts"() {
|
|
16243
16320
|
"use strict";
|
|
@@ -16251,12 +16328,14 @@ var init_parser12 = __esm({
|
|
|
16251
16328
|
SCOPE_RE = /^[A-Z]{2}(?:-[A-Z0-9]{1,3})?$/;
|
|
16252
16329
|
ARROW_SPLIT = /\s+(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+/;
|
|
16253
16330
|
HUB_RE = /^(->|~>)\s+(.+)$/;
|
|
16331
|
+
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16254
16332
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16255
16333
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16256
16334
|
"region",
|
|
16257
16335
|
"projection",
|
|
16258
|
-
"metric",
|
|
16259
|
-
"
|
|
16336
|
+
"region-metric",
|
|
16337
|
+
"poi-metric",
|
|
16338
|
+
"flow-metric",
|
|
16260
16339
|
"scale",
|
|
16261
16340
|
"region-labels",
|
|
16262
16341
|
"poi-labels",
|
|
@@ -16264,6 +16343,8 @@ var init_parser12 = __esm({
|
|
|
16264
16343
|
"default-state",
|
|
16265
16344
|
"active-tag",
|
|
16266
16345
|
"no-legend",
|
|
16346
|
+
"no-insets",
|
|
16347
|
+
"relief",
|
|
16267
16348
|
"subtitle",
|
|
16268
16349
|
"caption"
|
|
16269
16350
|
]);
|
|
@@ -45775,7 +45856,7 @@ var init_renderer15 = __esm({
|
|
|
45775
45856
|
|
|
45776
45857
|
// src/map/geo.ts
|
|
45777
45858
|
import { feature } from "topojson-client";
|
|
45778
|
-
import { geoBounds } from "d3-geo";
|
|
45859
|
+
import { geoBounds, geoArea } from "d3-geo";
|
|
45779
45860
|
function geomObject(topo) {
|
|
45780
45861
|
const key = Object.keys(topo.objects)[0];
|
|
45781
45862
|
return topo.objects[key];
|
|
@@ -45792,6 +45873,84 @@ function featureIndex(topo) {
|
|
|
45792
45873
|
}
|
|
45793
45874
|
return idx;
|
|
45794
45875
|
}
|
|
45876
|
+
function decodeFeatures(topo) {
|
|
45877
|
+
return geomObject(topo).geometries.map((g) => {
|
|
45878
|
+
const f = feature(topo, g);
|
|
45879
|
+
return {
|
|
45880
|
+
type: "Feature",
|
|
45881
|
+
id: g.id,
|
|
45882
|
+
properties: g.properties,
|
|
45883
|
+
geometry: f.geometry
|
|
45884
|
+
};
|
|
45885
|
+
});
|
|
45886
|
+
}
|
|
45887
|
+
function pointInRing(lon, lat, ring) {
|
|
45888
|
+
let inside = false;
|
|
45889
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
45890
|
+
const xi = ring[i][0];
|
|
45891
|
+
const yi = ring[i][1];
|
|
45892
|
+
const xj = ring[j][0];
|
|
45893
|
+
const yj = ring[j][1];
|
|
45894
|
+
const intersect = yi > lat !== yj > lat && lon < (xj - xi) * (lat - yi) / (yj - yi) + xi;
|
|
45895
|
+
if (intersect) inside = !inside;
|
|
45896
|
+
}
|
|
45897
|
+
return inside;
|
|
45898
|
+
}
|
|
45899
|
+
function pointOnRingEdge(lon, lat, ring) {
|
|
45900
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
45901
|
+
const xi = ring[i][0];
|
|
45902
|
+
const yi = ring[i][1];
|
|
45903
|
+
const xj = ring[j][0];
|
|
45904
|
+
const yj = ring[j][1];
|
|
45905
|
+
if (lon < Math.min(xi, xj) - EDGE_EPS || lon > Math.max(xi, xj) + EDGE_EPS)
|
|
45906
|
+
continue;
|
|
45907
|
+
if (lat < Math.min(yi, yj) - EDGE_EPS || lat > Math.max(yi, yj) + EDGE_EPS)
|
|
45908
|
+
continue;
|
|
45909
|
+
const cross = (xj - xi) * (lat - yi) - (yj - yi) * (lon - xi);
|
|
45910
|
+
if (Math.abs(cross) <= EDGE_EPS) return true;
|
|
45911
|
+
}
|
|
45912
|
+
return false;
|
|
45913
|
+
}
|
|
45914
|
+
function pointInGeometry(geometry, lon, lat) {
|
|
45915
|
+
const g = geometry;
|
|
45916
|
+
if (!g) return false;
|
|
45917
|
+
const polys = g.type === "Polygon" ? [g.coordinates] : g.type === "MultiPolygon" ? g.coordinates : [];
|
|
45918
|
+
for (const rings of polys) {
|
|
45919
|
+
if (!rings.length) continue;
|
|
45920
|
+
if (pointOnRingEdge(lon, lat, rings[0])) return true;
|
|
45921
|
+
if (!pointInRing(lon, lat, rings[0])) continue;
|
|
45922
|
+
let inHole = false;
|
|
45923
|
+
for (let h = 1; h < rings.length; h++) {
|
|
45924
|
+
if (pointInRing(lon, lat, rings[h]) && !pointOnRingEdge(lon, lat, rings[h])) {
|
|
45925
|
+
inHole = true;
|
|
45926
|
+
break;
|
|
45927
|
+
}
|
|
45928
|
+
}
|
|
45929
|
+
if (!inHole) return true;
|
|
45930
|
+
}
|
|
45931
|
+
return false;
|
|
45932
|
+
}
|
|
45933
|
+
function regionAt(lonLat, countries, states) {
|
|
45934
|
+
const lon = lonLat[0];
|
|
45935
|
+
const lat = lonLat[1];
|
|
45936
|
+
let country = null;
|
|
45937
|
+
for (const f of countries) {
|
|
45938
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
45939
|
+
country = { iso: f.id, name: f.properties.name };
|
|
45940
|
+
break;
|
|
45941
|
+
}
|
|
45942
|
+
}
|
|
45943
|
+
let state = null;
|
|
45944
|
+
if (country?.iso === "US" && states) {
|
|
45945
|
+
for (const f of states) {
|
|
45946
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
45947
|
+
state = { iso: f.id, name: f.properties.name };
|
|
45948
|
+
break;
|
|
45949
|
+
}
|
|
45950
|
+
}
|
|
45951
|
+
}
|
|
45952
|
+
return { country, state };
|
|
45953
|
+
}
|
|
45795
45954
|
function featureBbox(topo, geomId) {
|
|
45796
45955
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45797
45956
|
if (!geom) return null;
|
|
@@ -45803,6 +45962,74 @@ function featureBbox(topo, geomId) {
|
|
|
45803
45962
|
[b[1][0], b[1][1]]
|
|
45804
45963
|
];
|
|
45805
45964
|
}
|
|
45965
|
+
function explodePolygons(gj) {
|
|
45966
|
+
const g = gj.geometry ?? gj;
|
|
45967
|
+
const t = g.type;
|
|
45968
|
+
const coords = g.coordinates;
|
|
45969
|
+
if (t === "Polygon") {
|
|
45970
|
+
return [
|
|
45971
|
+
{ type: "Feature", geometry: { type: "Polygon", coordinates: coords } }
|
|
45972
|
+
];
|
|
45973
|
+
}
|
|
45974
|
+
if (t === "MultiPolygon") {
|
|
45975
|
+
return coords.map((rings) => ({
|
|
45976
|
+
type: "Feature",
|
|
45977
|
+
geometry: { type: "Polygon", coordinates: rings }
|
|
45978
|
+
}));
|
|
45979
|
+
}
|
|
45980
|
+
return [];
|
|
45981
|
+
}
|
|
45982
|
+
function bboxGap(a, b) {
|
|
45983
|
+
const lonGap = Math.max(0, a[0][0] - b[1][0], b[0][0] - a[1][0]);
|
|
45984
|
+
const latGap = Math.max(0, a[0][1] - b[1][1], b[0][1] - a[1][1]);
|
|
45985
|
+
return Math.max(lonGap, latGap);
|
|
45986
|
+
}
|
|
45987
|
+
function featureBboxPrimary(topo, geomId) {
|
|
45988
|
+
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45989
|
+
if (!geom) return null;
|
|
45990
|
+
const gj = feature(topo, geom);
|
|
45991
|
+
const parts = explodePolygons(gj);
|
|
45992
|
+
if (parts.length <= 1) return featureBbox(topo, geomId);
|
|
45993
|
+
const polys = parts.map((p) => {
|
|
45994
|
+
const b = geoBounds(p);
|
|
45995
|
+
if (!b || !Number.isFinite(b[0][0])) return null;
|
|
45996
|
+
const wraps = b[1][0] < b[0][0];
|
|
45997
|
+
const bbox = [
|
|
45998
|
+
[b[0][0], b[0][1]],
|
|
45999
|
+
[b[1][0], b[1][1]]
|
|
46000
|
+
];
|
|
46001
|
+
return { bbox, area: geoArea(p), wraps };
|
|
46002
|
+
}).filter(
|
|
46003
|
+
(p) => p !== null
|
|
46004
|
+
);
|
|
46005
|
+
if (polys.length <= 1 || polys.some((p) => p.wraps))
|
|
46006
|
+
return featureBbox(topo, geomId);
|
|
46007
|
+
const maxArea = Math.max(...polys.map((p) => p.area));
|
|
46008
|
+
const anchor = polys.find((p) => p.area === maxArea);
|
|
46009
|
+
const cluster = [
|
|
46010
|
+
[anchor.bbox[0][0], anchor.bbox[0][1]],
|
|
46011
|
+
[anchor.bbox[1][0], anchor.bbox[1][1]]
|
|
46012
|
+
];
|
|
46013
|
+
const remaining = polys.filter((p) => p !== anchor);
|
|
46014
|
+
let added = true;
|
|
46015
|
+
while (added) {
|
|
46016
|
+
added = false;
|
|
46017
|
+
for (let i = remaining.length - 1; i >= 0; i--) {
|
|
46018
|
+
const p = remaining[i];
|
|
46019
|
+
const near = bboxGap(p.bbox, cluster) <= DETACH_GAP_DEG;
|
|
46020
|
+
const large = p.area >= DETACH_AREA_FRAC * maxArea;
|
|
46021
|
+
if (near || large) {
|
|
46022
|
+
cluster[0][0] = Math.min(cluster[0][0], p.bbox[0][0]);
|
|
46023
|
+
cluster[0][1] = Math.min(cluster[0][1], p.bbox[0][1]);
|
|
46024
|
+
cluster[1][0] = Math.max(cluster[1][0], p.bbox[1][0]);
|
|
46025
|
+
cluster[1][1] = Math.max(cluster[1][1], p.bbox[1][1]);
|
|
46026
|
+
remaining.splice(i, 1);
|
|
46027
|
+
added = true;
|
|
46028
|
+
}
|
|
46029
|
+
}
|
|
46030
|
+
}
|
|
46031
|
+
return cluster;
|
|
46032
|
+
}
|
|
45806
46033
|
function unionExtent(boxes, points) {
|
|
45807
46034
|
const lats = [];
|
|
45808
46035
|
const lons = [];
|
|
@@ -45841,11 +46068,14 @@ function unionLongitudes(lons) {
|
|
|
45841
46068
|
}
|
|
45842
46069
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45843
46070
|
}
|
|
45844
|
-
var fold;
|
|
46071
|
+
var fold, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45845
46072
|
var init_geo = __esm({
|
|
45846
46073
|
"src/map/geo.ts"() {
|
|
45847
46074
|
"use strict";
|
|
45848
46075
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46076
|
+
EDGE_EPS = 1e-9;
|
|
46077
|
+
DETACH_GAP_DEG = 10;
|
|
46078
|
+
DETACH_AREA_FRAC = 0.25;
|
|
45849
46079
|
}
|
|
45850
46080
|
});
|
|
45851
46081
|
|
|
@@ -45854,6 +46084,11 @@ var resolver_exports = {};
|
|
|
45854
46084
|
__export(resolver_exports, {
|
|
45855
46085
|
resolveMap: () => resolveMap
|
|
45856
46086
|
});
|
|
46087
|
+
function usStateFromBareScope(scope) {
|
|
46088
|
+
if (!scope) return null;
|
|
46089
|
+
const up = scope.toUpperCase();
|
|
46090
|
+
return US_STATE_POSTAL.has(up) ? `US-${up}` : null;
|
|
46091
|
+
}
|
|
45857
46092
|
function looksUS(lat, lon) {
|
|
45858
46093
|
if (lat < 15 || lat > 72) return false;
|
|
45859
46094
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
@@ -45903,9 +46138,9 @@ function resolveMap(parsed, data) {
|
|
|
45903
46138
|
const f = fold(r.name);
|
|
45904
46139
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45905
46140
|
}) || parsed.regions.some(
|
|
45906
|
-
(r) => r.scope === "US" || r.scope?.startsWith("US-")
|
|
46141
|
+
(r) => r.scope === "US" || r.scope?.startsWith("US-") || usStateFromBareScope(r.scope) !== null
|
|
45907
46142
|
) || parsed.pois.some(
|
|
45908
|
-
(p) => p.pos.kind === "name" && p.pos.scope?.startsWith("US-")
|
|
46143
|
+
(p) => p.pos.kind === "name" && (p.pos.scope?.startsWith("US-") || usStateFromBareScope(p.pos.scope) !== null)
|
|
45909
46144
|
);
|
|
45910
46145
|
const regions = [];
|
|
45911
46146
|
const seenRegion = /* @__PURE__ */ new Map();
|
|
@@ -45944,12 +46179,12 @@ function resolveMap(parsed, data) {
|
|
|
45944
46179
|
chosen = { ...inState, layer: "us-state" };
|
|
45945
46180
|
} else {
|
|
45946
46181
|
chosen = { ...inCountry, layer: "country" };
|
|
46182
|
+
warn(
|
|
46183
|
+
r.lineNumber,
|
|
46184
|
+
`"${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}").`,
|
|
46185
|
+
"W_MAP_REGION_AMBIGUOUS"
|
|
46186
|
+
);
|
|
45947
46187
|
}
|
|
45948
|
-
warn(
|
|
45949
|
-
r.lineNumber,
|
|
45950
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
|
|
45951
|
-
"W_MAP_REGION_AMBIGUOUS"
|
|
45952
|
-
);
|
|
45953
46188
|
} else if (inState) {
|
|
45954
46189
|
chosen = { ...inState, layer: "us-state" };
|
|
45955
46190
|
} else if (inCountry) {
|
|
@@ -45972,7 +46207,8 @@ function resolveMap(parsed, data) {
|
|
|
45972
46207
|
iso: chosen.id,
|
|
45973
46208
|
name: chosen.name,
|
|
45974
46209
|
layer: chosen.layer,
|
|
45975
|
-
...r.
|
|
46210
|
+
...r.value !== void 0 && { value: r.value },
|
|
46211
|
+
...r.color !== void 0 && { color: r.color },
|
|
45976
46212
|
tags: r.tags,
|
|
45977
46213
|
meta: r.meta,
|
|
45978
46214
|
lineNumber: r.lineNumber
|
|
@@ -46030,9 +46266,10 @@ function resolveMap(parsed, data) {
|
|
|
46030
46266
|
let cands = idxs.map((i) => data.gazetteer.cities[i]);
|
|
46031
46267
|
const scopeUse = scope ?? scopeHint;
|
|
46032
46268
|
if (scopeUse) {
|
|
46033
|
-
const
|
|
46269
|
+
const bareState = usStateFromBareScope(scopeUse);
|
|
46270
|
+
const subScope = /^[A-Za-z]{2}-/.test(scopeUse) ? scopeUse : bareState;
|
|
46034
46271
|
const filtered = cands.filter(
|
|
46035
|
-
(c2) =>
|
|
46272
|
+
(c2) => subScope ? c2[5] === subScope : c2[2] === scopeUse
|
|
46036
46273
|
);
|
|
46037
46274
|
if (filtered.length) cands = filtered;
|
|
46038
46275
|
else if (scope) {
|
|
@@ -46113,6 +46350,7 @@ function resolveMap(parsed, data) {
|
|
|
46113
46350
|
lat,
|
|
46114
46351
|
lon,
|
|
46115
46352
|
...p.label !== void 0 && { label: p.label },
|
|
46353
|
+
...p.color !== void 0 && { color: p.color },
|
|
46116
46354
|
tags: p.tags,
|
|
46117
46355
|
meta: p.meta,
|
|
46118
46356
|
lineNumber: p.lineNumber
|
|
@@ -46161,33 +46399,89 @@ function resolveMap(parsed, data) {
|
|
|
46161
46399
|
lineNumber: e.lineNumber
|
|
46162
46400
|
});
|
|
46163
46401
|
}
|
|
46164
|
-
const
|
|
46165
|
-
|
|
46166
|
-
|
|
46167
|
-
|
|
46168
|
-
|
|
46169
|
-
if (
|
|
46170
|
-
|
|
46171
|
-
|
|
46172
|
-
|
|
46173
|
-
const poi = {
|
|
46402
|
+
const resolveStop = (pos, alias, label, tags, sizeValue, line12) => {
|
|
46403
|
+
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
46404
|
+
if (pos.kind === "coords") {
|
|
46405
|
+
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
46406
|
+
if (!looksUS(pos.lat, pos.lon)) anyNonUsPoi = true;
|
|
46407
|
+
if (!registry.has(id)) {
|
|
46408
|
+
registerPoi(
|
|
46409
|
+
id,
|
|
46410
|
+
{
|
|
46174
46411
|
id,
|
|
46175
|
-
...
|
|
46176
|
-
lat:
|
|
46177
|
-
lon:
|
|
46178
|
-
|
|
46179
|
-
|
|
46180
|
-
|
|
46181
|
-
|
|
46182
|
-
}
|
|
46183
|
-
|
|
46184
|
-
|
|
46185
|
-
} else {
|
|
46186
|
-
id = stop.alias && registry.has(fold(stop.alias)) ? fold(stop.alias) : resolveEndpoint2(stop.ref.name, stop.lineNumber);
|
|
46412
|
+
...alias !== void 0 && { name: alias },
|
|
46413
|
+
lat: pos.lat,
|
|
46414
|
+
lon: pos.lon,
|
|
46415
|
+
...label !== void 0 && { label },
|
|
46416
|
+
tags,
|
|
46417
|
+
meta,
|
|
46418
|
+
lineNumber: line12
|
|
46419
|
+
},
|
|
46420
|
+
line12
|
|
46421
|
+
);
|
|
46187
46422
|
}
|
|
46188
|
-
|
|
46423
|
+
return id;
|
|
46424
|
+
}
|
|
46425
|
+
const f = fold(pos.name);
|
|
46426
|
+
if (registry.has(f)) return f;
|
|
46427
|
+
const aliased = declaredByName.get(f);
|
|
46428
|
+
if (aliased) return aliased;
|
|
46429
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredCountry, true);
|
|
46430
|
+
if (got.kind !== "ok") return null;
|
|
46431
|
+
noteCountry(got.iso);
|
|
46432
|
+
registerPoi(
|
|
46433
|
+
f,
|
|
46434
|
+
{
|
|
46435
|
+
id: f,
|
|
46436
|
+
name: pos.name,
|
|
46437
|
+
lat: got.lat,
|
|
46438
|
+
lon: got.lon,
|
|
46439
|
+
...label !== void 0 && { label },
|
|
46440
|
+
tags,
|
|
46441
|
+
meta,
|
|
46442
|
+
lineNumber: line12
|
|
46443
|
+
},
|
|
46444
|
+
line12
|
|
46445
|
+
);
|
|
46446
|
+
return f;
|
|
46447
|
+
};
|
|
46448
|
+
const routes = [];
|
|
46449
|
+
for (const rt of parsed.routes) {
|
|
46450
|
+
const originId = resolveStop(
|
|
46451
|
+
rt.origin,
|
|
46452
|
+
rt.originAlias,
|
|
46453
|
+
rt.originLabel,
|
|
46454
|
+
rt.originTags,
|
|
46455
|
+
rt.originValue,
|
|
46456
|
+
rt.lineNumber
|
|
46457
|
+
);
|
|
46458
|
+
if (!originId) continue;
|
|
46459
|
+
const stopIds = [originId];
|
|
46460
|
+
const legs = [];
|
|
46461
|
+
let prevId = originId;
|
|
46462
|
+
for (const leg of rt.legs) {
|
|
46463
|
+
const destId = resolveStop(
|
|
46464
|
+
leg.dest,
|
|
46465
|
+
leg.destAlias,
|
|
46466
|
+
leg.destLabel,
|
|
46467
|
+
leg.destTags,
|
|
46468
|
+
void 0,
|
|
46469
|
+
// a leg's `value:` is leg thickness, not the dest's size
|
|
46470
|
+
leg.lineNumber
|
|
46471
|
+
);
|
|
46472
|
+
if (!destId) continue;
|
|
46473
|
+
legs.push({
|
|
46474
|
+
fromId: prevId,
|
|
46475
|
+
toId: destId,
|
|
46476
|
+
...leg.label !== void 0 && { label: leg.label },
|
|
46477
|
+
style: leg.style,
|
|
46478
|
+
...leg.value !== void 0 && { value: leg.value },
|
|
46479
|
+
lineNumber: leg.lineNumber
|
|
46480
|
+
});
|
|
46481
|
+
if (!stopIds.includes(destId)) stopIds.push(destId);
|
|
46482
|
+
prevId = destId;
|
|
46189
46483
|
}
|
|
46190
|
-
routes.push({ stopIds,
|
|
46484
|
+
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
46191
46485
|
}
|
|
46192
46486
|
const subdivisions = [];
|
|
46193
46487
|
if (usSubdivisionReferenced || parsed.directives.region === "us-states")
|
|
@@ -46199,7 +46493,7 @@ function resolveMap(parsed, data) {
|
|
|
46199
46493
|
}
|
|
46200
46494
|
for (const r of regions) {
|
|
46201
46495
|
if (r.layer === "country") {
|
|
46202
|
-
const bb =
|
|
46496
|
+
const bb = featureBboxPrimary(data.worldCoarse, r.iso);
|
|
46203
46497
|
if (bb) regionBoxes.push(bb);
|
|
46204
46498
|
}
|
|
46205
46499
|
}
|
|
@@ -46213,6 +46507,7 @@ function resolveMap(parsed, data) {
|
|
|
46213
46507
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46214
46508
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46215
46509
|
const span = Math.max(lonSpan, latSpan);
|
|
46510
|
+
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
46216
46511
|
const usDominant = (subdivisions.includes("us-states") || regions.some((r) => r.layer === "us-state")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
46217
46512
|
let projection;
|
|
46218
46513
|
const override = parsed.directives.projection;
|
|
@@ -46220,12 +46515,10 @@ function resolveMap(parsed, data) {
|
|
|
46220
46515
|
projection = override;
|
|
46221
46516
|
} else if (usDominant) {
|
|
46222
46517
|
projection = "albers-usa";
|
|
46223
|
-
} else if (span > WORLD_SPAN) {
|
|
46518
|
+
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
46224
46519
|
projection = "equirectangular";
|
|
46225
|
-
} else if (span < MERCATOR_MAX_SPAN) {
|
|
46226
|
-
projection = "mercator";
|
|
46227
46520
|
} else {
|
|
46228
|
-
projection = "
|
|
46521
|
+
projection = "mercator";
|
|
46229
46522
|
}
|
|
46230
46523
|
if (lonSpan >= 180) {
|
|
46231
46524
|
extent2 = [
|
|
@@ -46279,14 +46572,14 @@ function firstError(diags) {
|
|
|
46279
46572
|
const e = diags.find((d) => d.severity === "error");
|
|
46280
46573
|
return e ? formatDgmoError(e) : null;
|
|
46281
46574
|
}
|
|
46282
|
-
var WORLD_SPAN,
|
|
46575
|
+
var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES, US_STATE_POSTAL;
|
|
46283
46576
|
var init_resolver2 = __esm({
|
|
46284
46577
|
"src/map/resolver.ts"() {
|
|
46285
46578
|
"use strict";
|
|
46286
46579
|
init_diagnostics();
|
|
46287
46580
|
init_geo();
|
|
46288
46581
|
WORLD_SPAN = 90;
|
|
46289
|
-
|
|
46582
|
+
MERCATOR_MAX_LAT = 80;
|
|
46290
46583
|
PAD_FRACTION = 0.05;
|
|
46291
46584
|
WORLD_LAT_SOUTH = -58;
|
|
46292
46585
|
WORLD_LAT_NORTH = 78;
|
|
@@ -46311,114 +46604,59 @@ var init_resolver2 = __esm({
|
|
|
46311
46604
|
"north macedonia": "macedonia",
|
|
46312
46605
|
"czech republic": "czechia"
|
|
46313
46606
|
};
|
|
46314
|
-
|
|
46315
|
-
|
|
46316
|
-
|
|
46317
|
-
|
|
46318
|
-
|
|
46319
|
-
|
|
46320
|
-
|
|
46321
|
-
|
|
46322
|
-
|
|
46323
|
-
|
|
46324
|
-
|
|
46325
|
-
|
|
46326
|
-
|
|
46327
|
-
|
|
46328
|
-
|
|
46329
|
-
|
|
46330
|
-
|
|
46331
|
-
|
|
46332
|
-
|
|
46333
|
-
|
|
46334
|
-
|
|
46335
|
-
|
|
46336
|
-
|
|
46337
|
-
|
|
46338
|
-
|
|
46339
|
-
|
|
46340
|
-
|
|
46341
|
-
|
|
46342
|
-
|
|
46343
|
-
|
|
46344
|
-
|
|
46345
|
-
|
|
46346
|
-
|
|
46347
|
-
|
|
46348
|
-
|
|
46349
|
-
|
|
46350
|
-
|
|
46351
|
-
|
|
46352
|
-
|
|
46353
|
-
|
|
46354
|
-
|
|
46355
|
-
|
|
46356
|
-
|
|
46357
|
-
|
|
46358
|
-
|
|
46359
|
-
|
|
46360
|
-
|
|
46361
|
-
|
|
46362
|
-
|
|
46363
|
-
|
|
46364
|
-
|
|
46365
|
-
|
|
46366
|
-
const [
|
|
46367
|
-
worldCoarse,
|
|
46368
|
-
worldDetail,
|
|
46369
|
-
usStates,
|
|
46370
|
-
lakes,
|
|
46371
|
-
rivers,
|
|
46372
|
-
naLand,
|
|
46373
|
-
naLakes,
|
|
46374
|
-
gazetteer
|
|
46375
|
-
] = await Promise.all([
|
|
46376
|
-
readJson(nb, dir, FILES.worldCoarse),
|
|
46377
|
-
readJson(nb, dir, FILES.worldDetail),
|
|
46378
|
-
readJson(nb, dir, FILES.usStates),
|
|
46379
|
-
// Lakes/rivers/NA assets are optional — older bundles may predate them.
|
|
46380
|
-
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
46381
|
-
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
46382
|
-
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
46383
|
-
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
46384
|
-
readJson(nb, dir, FILES.gazetteer)
|
|
46607
|
+
US_STATE_POSTAL = /* @__PURE__ */ new Set([
|
|
46608
|
+
"AL",
|
|
46609
|
+
"AK",
|
|
46610
|
+
"AZ",
|
|
46611
|
+
"AR",
|
|
46612
|
+
"CA",
|
|
46613
|
+
"CO",
|
|
46614
|
+
"CT",
|
|
46615
|
+
"DE",
|
|
46616
|
+
"FL",
|
|
46617
|
+
"GA",
|
|
46618
|
+
"HI",
|
|
46619
|
+
"ID",
|
|
46620
|
+
"IL",
|
|
46621
|
+
"IN",
|
|
46622
|
+
"IA",
|
|
46623
|
+
"KS",
|
|
46624
|
+
"KY",
|
|
46625
|
+
"LA",
|
|
46626
|
+
"ME",
|
|
46627
|
+
"MD",
|
|
46628
|
+
"MA",
|
|
46629
|
+
"MI",
|
|
46630
|
+
"MN",
|
|
46631
|
+
"MS",
|
|
46632
|
+
"MO",
|
|
46633
|
+
"MT",
|
|
46634
|
+
"NE",
|
|
46635
|
+
"NV",
|
|
46636
|
+
"NH",
|
|
46637
|
+
"NJ",
|
|
46638
|
+
"NM",
|
|
46639
|
+
"NY",
|
|
46640
|
+
"NC",
|
|
46641
|
+
"ND",
|
|
46642
|
+
"OH",
|
|
46643
|
+
"OK",
|
|
46644
|
+
"OR",
|
|
46645
|
+
"PA",
|
|
46646
|
+
"RI",
|
|
46647
|
+
"SC",
|
|
46648
|
+
"SD",
|
|
46649
|
+
"TN",
|
|
46650
|
+
"TX",
|
|
46651
|
+
"UT",
|
|
46652
|
+
"VT",
|
|
46653
|
+
"VA",
|
|
46654
|
+
"WA",
|
|
46655
|
+
"WV",
|
|
46656
|
+
"WI",
|
|
46657
|
+
"WY",
|
|
46658
|
+
"DC"
|
|
46385
46659
|
]);
|
|
46386
|
-
return validate({
|
|
46387
|
-
worldCoarse,
|
|
46388
|
-
worldDetail,
|
|
46389
|
-
usStates,
|
|
46390
|
-
gazetteer,
|
|
46391
|
-
...lakes && { lakes },
|
|
46392
|
-
...rivers && { rivers },
|
|
46393
|
-
...naLand && { naLand },
|
|
46394
|
-
...naLakes && { naLakes }
|
|
46395
|
-
});
|
|
46396
|
-
})().catch((e) => {
|
|
46397
|
-
cache = void 0;
|
|
46398
|
-
throw e;
|
|
46399
|
-
});
|
|
46400
|
-
return cache;
|
|
46401
|
-
}
|
|
46402
|
-
var FILES, CANDIDATE_DIRS, cache;
|
|
46403
|
-
var init_load_data = __esm({
|
|
46404
|
-
"src/map/load-data.ts"() {
|
|
46405
|
-
"use strict";
|
|
46406
|
-
FILES = {
|
|
46407
|
-
worldCoarse: "world-coarse.json",
|
|
46408
|
-
worldDetail: "world-detail.json",
|
|
46409
|
-
usStates: "us-states.json",
|
|
46410
|
-
lakes: "lakes.json",
|
|
46411
|
-
rivers: "rivers.json",
|
|
46412
|
-
naLand: "na-land.json",
|
|
46413
|
-
naLakes: "na-lakes.json",
|
|
46414
|
-
gazetteer: "gazetteer.json"
|
|
46415
|
-
};
|
|
46416
|
-
CANDIDATE_DIRS = [
|
|
46417
|
-
"./data",
|
|
46418
|
-
"./map-data",
|
|
46419
|
-
"../map-data",
|
|
46420
|
-
"../src/map/data"
|
|
46421
|
-
];
|
|
46422
46660
|
}
|
|
46423
46661
|
});
|
|
46424
46662
|
|
|
@@ -46458,10 +46696,14 @@ function projectionFor(family) {
|
|
|
46458
46696
|
return geoEquirectangular();
|
|
46459
46697
|
}
|
|
46460
46698
|
}
|
|
46461
|
-
function mapBackgroundColor(palette) {
|
|
46462
|
-
return mix(
|
|
46699
|
+
function mapBackgroundColor(palette, isDark = false, _dataActive = false) {
|
|
46700
|
+
return mix(
|
|
46701
|
+
palette.colors.blue,
|
|
46702
|
+
palette.bg,
|
|
46703
|
+
isDark ? WATER_TINT_DARK : WATER_TINT_LIGHT
|
|
46704
|
+
);
|
|
46463
46705
|
}
|
|
46464
|
-
function mapNeutralLandColor(palette, isDark) {
|
|
46706
|
+
function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
46465
46707
|
return mix(
|
|
46466
46708
|
palette.colors.green,
|
|
46467
46709
|
palette.bg,
|
|
@@ -46487,28 +46729,19 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46487
46729
|
}
|
|
46488
46730
|
}
|
|
46489
46731
|
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
46490
|
-
const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
|
|
46491
|
-
const neutralFill = mix(palette.colors.green, palette.bg, landTint);
|
|
46492
|
-
const water = mapBackgroundColor(palette);
|
|
46493
46732
|
const usContext = usLayer !== null;
|
|
46494
|
-
const foreignFill = mix(
|
|
46495
|
-
palette.colors.gray,
|
|
46496
|
-
palette.bg,
|
|
46497
|
-
isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46498
|
-
);
|
|
46499
46733
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46500
|
-
const
|
|
46734
|
+
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46501
46735
|
const scaleOverride = resolved.directives.scale;
|
|
46502
|
-
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...
|
|
46503
|
-
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...
|
|
46504
|
-
const rampHue = palette.colors.red;
|
|
46505
|
-
const hasRamp =
|
|
46506
|
-
const
|
|
46736
|
+
const rampMin = scaleOverride ? scaleOverride.min : Math.min(...values);
|
|
46737
|
+
const rampMax = scaleOverride ? scaleOverride.max : Math.max(...values);
|
|
46738
|
+
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46739
|
+
const hasRamp = values.length > 0;
|
|
46740
|
+
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
46507
46741
|
const matchColorGroup = (v) => {
|
|
46508
46742
|
const lv = v.trim().toLowerCase();
|
|
46509
46743
|
if (lv === "none") return null;
|
|
46510
|
-
if (
|
|
46511
|
-
return SCORE_NAME;
|
|
46744
|
+
if (lv === VALUE_NAME?.toLowerCase()) return VALUE_NAME;
|
|
46512
46745
|
const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
46513
46746
|
return tg ? tg.name : v;
|
|
46514
46747
|
};
|
|
@@ -46519,11 +46752,20 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46519
46752
|
} else if (resolved.directives.activeTag !== void 0) {
|
|
46520
46753
|
activeGroup = matchColorGroup(resolved.directives.activeTag);
|
|
46521
46754
|
} else {
|
|
46522
|
-
activeGroup =
|
|
46755
|
+
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46523
46756
|
}
|
|
46524
|
-
const activeIsScore =
|
|
46757
|
+
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46758
|
+
const mutedBasemap = resolved.directives.basemapStyle === "muted" ? true : resolved.directives.basemapStyle === "natural" ? false : activeGroup !== null;
|
|
46759
|
+
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46760
|
+
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
46761
|
+
const lakeStroke = mix(regionStroke, water, 45);
|
|
46762
|
+
const foreignFill = mix(
|
|
46763
|
+
palette.colors.gray,
|
|
46764
|
+
palette.bg,
|
|
46765
|
+
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46766
|
+
);
|
|
46525
46767
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46526
|
-
const
|
|
46768
|
+
const fillForValue = (s) => {
|
|
46527
46769
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
46528
46770
|
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
46529
46771
|
return mix(rampHue, rampBase, pct);
|
|
@@ -46546,9 +46788,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46546
46788
|
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46547
46789
|
);
|
|
46548
46790
|
};
|
|
46791
|
+
const directFill = (name) => {
|
|
46792
|
+
const hex = name ? resolveColor(name, palette) : null;
|
|
46793
|
+
if (!hex) return null;
|
|
46794
|
+
return mix(hex, palette.bg, isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT);
|
|
46795
|
+
};
|
|
46549
46796
|
const regionFill = (r) => {
|
|
46797
|
+
const direct = directFill(r.color);
|
|
46798
|
+
if (direct) return direct;
|
|
46550
46799
|
if (activeIsScore) {
|
|
46551
|
-
return r.
|
|
46800
|
+
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46552
46801
|
}
|
|
46553
46802
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46554
46803
|
};
|
|
@@ -46600,6 +46849,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46600
46849
|
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46601
46850
|
let path;
|
|
46602
46851
|
let project;
|
|
46852
|
+
let stretchParams = null;
|
|
46603
46853
|
if (fitIsGlobal) {
|
|
46604
46854
|
const cb = geoPath(projection).bounds(fitTarget);
|
|
46605
46855
|
const bx0 = cb[0][0];
|
|
@@ -46610,6 +46860,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46610
46860
|
const oy = fitBox[0][1];
|
|
46611
46861
|
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46612
46862
|
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
46863
|
+
stretchParams = { sx, sy, ox, oy, bx0, by0 };
|
|
46613
46864
|
const stretch = (x, y) => [
|
|
46614
46865
|
ox + (x - bx0) * sx,
|
|
46615
46866
|
oy + (y - by0) * sy
|
|
@@ -46641,7 +46892,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46641
46892
|
const insets = [];
|
|
46642
46893
|
const insetRegions = [];
|
|
46643
46894
|
const insetLabelSeeds = [];
|
|
46644
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46895
|
+
if (resolved.projection === "albers-usa" && usLayer && !resolved.directives.noInsets) {
|
|
46645
46896
|
const PAD = 8;
|
|
46646
46897
|
const GAP = 12;
|
|
46647
46898
|
const yB = height - FIT_PAD;
|
|
@@ -46672,38 +46923,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46672
46923
|
}
|
|
46673
46924
|
return y;
|
|
46674
46925
|
};
|
|
46675
|
-
const
|
|
46926
|
+
const coastFloor = (x0, xr) => {
|
|
46676
46927
|
const n = 24;
|
|
46677
|
-
const pts = [];
|
|
46678
46928
|
let maxY = -Infinity;
|
|
46679
46929
|
for (let i = 0; i <= n; i++) {
|
|
46680
|
-
const
|
|
46681
|
-
|
|
46682
|
-
|
|
46683
|
-
|
|
46684
|
-
if (y > maxY) maxY = y;
|
|
46685
|
-
}
|
|
46686
|
-
}
|
|
46687
|
-
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46688
|
-
let m = 0;
|
|
46689
|
-
if (pts.length >= 2) {
|
|
46690
|
-
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46691
|
-
for (const [x, y] of pts) {
|
|
46692
|
-
sx += x;
|
|
46693
|
-
sy += y;
|
|
46694
|
-
sxx += x * x;
|
|
46695
|
-
sxy += x * y;
|
|
46696
|
-
}
|
|
46697
|
-
const den = pts.length * sxx - sx * sx;
|
|
46698
|
-
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46699
|
-
}
|
|
46700
|
-
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46701
|
-
let c = -Infinity;
|
|
46702
|
-
for (const [x, y] of pts) {
|
|
46703
|
-
const need = y - m * x + GAP;
|
|
46704
|
-
if (need > c) c = need;
|
|
46705
|
-
}
|
|
46706
|
-
return (x) => m * x + c;
|
|
46930
|
+
const y = at(x0 + (xr - x0) * i / n);
|
|
46931
|
+
if (y > maxY) maxY = y;
|
|
46932
|
+
}
|
|
46933
|
+
return maxY;
|
|
46707
46934
|
};
|
|
46708
46935
|
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46709
46936
|
const f = usLayer.get(iso);
|
|
@@ -46712,19 +46939,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46712
46939
|
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46713
46940
|
if (iw < 24) return boxX;
|
|
46714
46941
|
const xr = x0 + iw + 2 * PAD;
|
|
46715
|
-
const
|
|
46716
|
-
const
|
|
46717
|
-
const yR = top(xr);
|
|
46942
|
+
const floor = coastFloor(x0, xr);
|
|
46943
|
+
const topGuess = floor > -Infinity ? floor + GAP : yB - height * 0.42;
|
|
46718
46944
|
proj.fitWidth(iw, f);
|
|
46719
46945
|
const bb = geoPath(proj).bounds(f);
|
|
46720
46946
|
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46721
46947
|
const needH = sh + 2 * PAD;
|
|
46722
|
-
let topFit =
|
|
46948
|
+
let topFit = topGuess;
|
|
46723
46949
|
const bottom = Math.min(topFit + needH, yB);
|
|
46724
46950
|
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46725
|
-
const lift = topFit - Math.max(yL, yR);
|
|
46726
|
-
const topL = yL + lift;
|
|
46727
|
-
const topR = yR + lift;
|
|
46728
46951
|
proj.fitExtent(
|
|
46729
46952
|
[
|
|
46730
46953
|
[x0 + PAD, topFit + PAD],
|
|
@@ -46743,15 +46966,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46743
46966
|
}
|
|
46744
46967
|
insets.push({
|
|
46745
46968
|
x: x0,
|
|
46746
|
-
y:
|
|
46969
|
+
y: topFit,
|
|
46747
46970
|
w: xr - x0,
|
|
46748
|
-
h: bottom -
|
|
46971
|
+
h: bottom - topFit,
|
|
46749
46972
|
points: [
|
|
46750
|
-
[x0,
|
|
46751
|
-
[xr,
|
|
46973
|
+
[x0, topFit],
|
|
46974
|
+
[xr, topFit],
|
|
46752
46975
|
[xr, bottom],
|
|
46753
46976
|
[x0, bottom]
|
|
46754
|
-
]
|
|
46977
|
+
],
|
|
46978
|
+
// The FITTED inset projection (just fit to this box) — captured so the
|
|
46979
|
+
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
46980
|
+
projection: proj
|
|
46755
46981
|
});
|
|
46756
46982
|
insetRegions.push({
|
|
46757
46983
|
id: iso,
|
|
@@ -46760,7 +46986,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46760
46986
|
stroke: regionStroke,
|
|
46761
46987
|
lineNumber,
|
|
46762
46988
|
layer: "us-state",
|
|
46763
|
-
...r?.
|
|
46989
|
+
...r?.value !== void 0 && { value: r.value },
|
|
46764
46990
|
...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46765
46991
|
});
|
|
46766
46992
|
const ctr = geoPath(proj).centroid(f);
|
|
@@ -46903,7 +47129,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46903
47129
|
lineNumber,
|
|
46904
47130
|
layer,
|
|
46905
47131
|
...label !== void 0 && { label },
|
|
46906
|
-
...isThisLayer && r.
|
|
47132
|
+
...isThisLayer && r.value !== void 0 && { value: r.value },
|
|
46907
47133
|
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
46908
47134
|
});
|
|
46909
47135
|
}
|
|
@@ -46921,13 +47147,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46921
47147
|
id: "lake",
|
|
46922
47148
|
d,
|
|
46923
47149
|
fill: water,
|
|
46924
|
-
stroke:
|
|
47150
|
+
stroke: lakeStroke,
|
|
46925
47151
|
lineNumber: -1,
|
|
46926
47152
|
layer: "base"
|
|
46927
47153
|
});
|
|
46928
47154
|
}
|
|
46929
47155
|
}
|
|
46930
|
-
const
|
|
47156
|
+
const relief = [];
|
|
47157
|
+
let reliefHatch = null;
|
|
47158
|
+
if (resolved.directives.relief === true && data.mountainRanges) {
|
|
47159
|
+
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
47160
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
47161
|
+
if (!viewF) continue;
|
|
47162
|
+
const area2 = path.area(viewF);
|
|
47163
|
+
if (!Number.isFinite(area2) || area2 < RELIEF_MIN_AREA) continue;
|
|
47164
|
+
const box = path.bounds(viewF);
|
|
47165
|
+
if (box[1][0] - box[0][0] < RELIEF_MIN_DIM || box[1][1] - box[0][1] < RELIEF_MIN_DIM)
|
|
47166
|
+
continue;
|
|
47167
|
+
const d = path(viewF) ?? "";
|
|
47168
|
+
if (!d) continue;
|
|
47169
|
+
relief.push({ d });
|
|
47170
|
+
}
|
|
47171
|
+
if (relief.length) {
|
|
47172
|
+
const darkTone = isDark ? palette.bg : palette.text;
|
|
47173
|
+
const lightTone = isDark ? palette.text : palette.bg;
|
|
47174
|
+
const landLum = relativeLuminance(neutralFill);
|
|
47175
|
+
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
47176
|
+
reliefHatch = {
|
|
47177
|
+
color: mix(tone, neutralFill, RELIEF_HATCH_STRENGTH),
|
|
47178
|
+
spacing: RELIEF_HATCH_SPACING,
|
|
47179
|
+
width: RELIEF_HATCH_WIDTH
|
|
47180
|
+
};
|
|
47181
|
+
}
|
|
47182
|
+
}
|
|
47183
|
+
const riverColor = mix(water, regionStroke, 16);
|
|
46931
47184
|
const rivers = [];
|
|
46932
47185
|
if (data.rivers) {
|
|
46933
47186
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -46938,16 +47191,19 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46938
47191
|
rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
|
|
46939
47192
|
}
|
|
46940
47193
|
}
|
|
46941
|
-
const sizeVals = resolved.pois.map((p) => Number(p.meta["
|
|
47194
|
+
const sizeVals = resolved.pois.map((p) => Number(p.meta["value"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
46942
47195
|
const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
|
|
46943
47196
|
const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
|
|
46944
47197
|
const radiusFor = (p) => {
|
|
46945
|
-
const v = Number(p.meta["
|
|
47198
|
+
const v = Number(p.meta["value"]);
|
|
46946
47199
|
if (!Number.isFinite(v) || v <= 0 || sizeMax <= 0) return R_DEFAULT;
|
|
46947
47200
|
const t = sizeMax > sizeMin ? (Math.sqrt(v) - Math.sqrt(sizeMin)) / (Math.sqrt(sizeMax) - Math.sqrt(sizeMin)) : 1;
|
|
46948
47201
|
return R_MIN + Math.max(0, Math.min(1, t)) * (R_MAX - R_MIN);
|
|
46949
47202
|
};
|
|
46950
47203
|
const poiFill = (p) => {
|
|
47204
|
+
const directHex = p.color ? resolveColor(p.color, palette) : null;
|
|
47205
|
+
if (directHex)
|
|
47206
|
+
return { fill: directHex, stroke: mix(directHex, palette.text, 18) };
|
|
46951
47207
|
for (const group of resolved.tagGroups) {
|
|
46952
47208
|
const val = p.tags[group.name.toLowerCase()];
|
|
46953
47209
|
if (!val) continue;
|
|
@@ -47009,7 +47265,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47009
47265
|
lineNumber: e.p.lineNumber,
|
|
47010
47266
|
implicit: !!e.p.implicit,
|
|
47011
47267
|
isOrigin: originIds.has(e.p.id),
|
|
47012
|
-
...num !== void 0 && { routeNumber: num }
|
|
47268
|
+
...num !== void 0 && { routeNumber: num },
|
|
47269
|
+
...Object.keys(e.p.tags).length > 0 && { tags: e.p.tags }
|
|
47013
47270
|
});
|
|
47014
47271
|
});
|
|
47015
47272
|
}
|
|
@@ -47045,26 +47302,40 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47045
47302
|
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
47046
47303
|
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
47047
47304
|
};
|
|
47305
|
+
const routeLegVals = resolved.routes.flatMap((rt) => rt.legs).map((l) => Number(l.value)).filter((n) => Number.isFinite(n) && n > 0);
|
|
47306
|
+
const rlMin = routeLegVals.length ? Math.min(...routeLegVals) : 0;
|
|
47307
|
+
const rlMax = routeLegVals.length ? Math.max(...routeLegVals) : 0;
|
|
47308
|
+
const routeWidthFor = (v) => {
|
|
47309
|
+
if (!Number.isFinite(v) || v <= 0 || rlMax <= 0) return W_MIN;
|
|
47310
|
+
const t = rlMax > rlMin ? (v - rlMin) / (rlMax - rlMin) : 1;
|
|
47311
|
+
return W_MIN + t * (W_MAX - W_MIN);
|
|
47312
|
+
};
|
|
47048
47313
|
for (const rt of resolved.routes) {
|
|
47049
|
-
const
|
|
47050
|
-
|
|
47051
|
-
const
|
|
47052
|
-
const b = poiScreen.get(rt.stopIds[i]);
|
|
47314
|
+
for (const leg of rt.legs) {
|
|
47315
|
+
const a = poiScreen.get(leg.fromId);
|
|
47316
|
+
const b = poiScreen.get(leg.toId);
|
|
47053
47317
|
if (!a || !b) continue;
|
|
47318
|
+
const mx = (a.cx + b.cx) / 2;
|
|
47319
|
+
const my = (a.cy + b.cy) / 2;
|
|
47054
47320
|
legs.push({
|
|
47055
|
-
d: legPath(a, b,
|
|
47056
|
-
width:
|
|
47321
|
+
d: legPath(a, b, leg.style === "arc", 0),
|
|
47322
|
+
width: routeWidthFor(Number(leg.value)),
|
|
47057
47323
|
color: mix(palette.text, palette.bg, 72),
|
|
47058
47324
|
arrow: true,
|
|
47059
|
-
lineNumber:
|
|
47325
|
+
lineNumber: leg.lineNumber,
|
|
47326
|
+
...leg.label !== void 0 && {
|
|
47327
|
+
label: leg.label,
|
|
47328
|
+
labelX: mx,
|
|
47329
|
+
labelY: my - 4
|
|
47330
|
+
}
|
|
47060
47331
|
});
|
|
47061
47332
|
}
|
|
47062
47333
|
}
|
|
47063
|
-
const weightVals = resolved.edges.map((e) => Number(e.meta["
|
|
47334
|
+
const weightVals = resolved.edges.map((e) => Number(e.meta["value"])).filter((n) => Number.isFinite(n) && n > 0);
|
|
47064
47335
|
const wMin = weightVals.length ? Math.min(...weightVals) : 0;
|
|
47065
47336
|
const wMax = weightVals.length ? Math.max(...weightVals) : 0;
|
|
47066
47337
|
const widthFor = (e) => {
|
|
47067
|
-
const v = Number(e.meta["
|
|
47338
|
+
const v = Number(e.meta["value"]);
|
|
47068
47339
|
if (!Number.isFinite(v) || v <= 0 || wMax <= 0) return W_MIN;
|
|
47069
47340
|
const t = wMax > wMin ? (v - wMin) / (wMax - wMin) : 1;
|
|
47070
47341
|
return W_MIN + t * (W_MAX - W_MIN);
|
|
@@ -47327,8 +47598,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47327
47598
|
activeGroup,
|
|
47328
47599
|
...hasRamp && {
|
|
47329
47600
|
ramp: {
|
|
47330
|
-
...resolved.directives.
|
|
47331
|
-
metric: resolved.directives.
|
|
47601
|
+
...resolved.directives.regionMetric !== void 0 && {
|
|
47602
|
+
metric: resolved.directives.regionMetric
|
|
47332
47603
|
},
|
|
47333
47604
|
min: rampMin,
|
|
47334
47605
|
max: rampMax,
|
|
@@ -47348,19 +47619,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47348
47619
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
47349
47620
|
regions,
|
|
47350
47621
|
rivers,
|
|
47622
|
+
relief,
|
|
47623
|
+
reliefHatch,
|
|
47351
47624
|
legs,
|
|
47352
47625
|
pois,
|
|
47353
47626
|
labels,
|
|
47354
47627
|
legend,
|
|
47355
47628
|
insets,
|
|
47356
|
-
insetRegions
|
|
47629
|
+
insetRegions,
|
|
47630
|
+
projection,
|
|
47631
|
+
stretch: stretchParams
|
|
47357
47632
|
};
|
|
47358
47633
|
}
|
|
47359
|
-
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT, COLO_EPS, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK,
|
|
47634
|
+
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT, COLO_EPS, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT_LIGHT, WATER_TINT_DARK, RIVER_WIDTH, RELIEF_MIN_AREA, RELIEF_MIN_DIM, RELIEF_HATCH_SPACING, RELIEF_HATCH_WIDTH, RELIEF_HATCH_STRENGTH, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, MUTED_FOREIGN_LIGHT, MUTED_FOREIGN_DARK, COLO_R, GOLDEN_ANGLE, FAN_STEP, ARC_CURVE_FRAC, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, US_NON_CONUS;
|
|
47360
47635
|
var init_layout15 = __esm({
|
|
47361
47636
|
"src/map/layout.ts"() {
|
|
47362
47637
|
"use strict";
|
|
47363
47638
|
init_color_utils();
|
|
47639
|
+
init_colors();
|
|
47364
47640
|
init_label_layout();
|
|
47365
47641
|
init_legend_constants();
|
|
47366
47642
|
init_title_constants();
|
|
@@ -47373,14 +47649,22 @@ var init_layout15 = __esm({
|
|
|
47373
47649
|
W_MAX = 8;
|
|
47374
47650
|
FONT = 11;
|
|
47375
47651
|
COLO_EPS = 1.5;
|
|
47376
|
-
LAND_TINT_LIGHT =
|
|
47377
|
-
LAND_TINT_DARK =
|
|
47652
|
+
LAND_TINT_LIGHT = 12;
|
|
47653
|
+
LAND_TINT_DARK = 24;
|
|
47378
47654
|
TAG_TINT_LIGHT = 60;
|
|
47379
47655
|
TAG_TINT_DARK = 68;
|
|
47380
|
-
|
|
47656
|
+
WATER_TINT_LIGHT = 13;
|
|
47657
|
+
WATER_TINT_DARK = 14;
|
|
47381
47658
|
RIVER_WIDTH = 1.3;
|
|
47659
|
+
RELIEF_MIN_AREA = 12;
|
|
47660
|
+
RELIEF_MIN_DIM = 2;
|
|
47661
|
+
RELIEF_HATCH_SPACING = 3;
|
|
47662
|
+
RELIEF_HATCH_WIDTH = 0.25;
|
|
47663
|
+
RELIEF_HATCH_STRENGTH = 32;
|
|
47382
47664
|
FOREIGN_TINT_LIGHT = 30;
|
|
47383
47665
|
FOREIGN_TINT_DARK = 62;
|
|
47666
|
+
MUTED_FOREIGN_LIGHT = 28;
|
|
47667
|
+
MUTED_FOREIGN_DARK = 16;
|
|
47384
47668
|
COLO_R = 9;
|
|
47385
47669
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
47386
47670
|
FAN_STEP = 16;
|
|
@@ -47435,7 +47719,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47435
47719
|
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
47436
47720
|
if (r.layer !== "base") {
|
|
47437
47721
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47438
|
-
if (r.
|
|
47722
|
+
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
47439
47723
|
if (r.tags) {
|
|
47440
47724
|
for (const [group, value] of Object.entries(r.tags)) {
|
|
47441
47725
|
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47453,6 +47737,20 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47453
47737
|
}
|
|
47454
47738
|
};
|
|
47455
47739
|
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
47740
|
+
if (layout.relief.length && layout.reliefHatch) {
|
|
47741
|
+
const h = layout.reliefHatch;
|
|
47742
|
+
const rangeClipId = "dgmo-relief-clip";
|
|
47743
|
+
const landClipId = "dgmo-relief-land";
|
|
47744
|
+
const rangeClip = defs.append("clipPath").attr("id", rangeClipId);
|
|
47745
|
+
for (const s of layout.relief) rangeClip.append("path").attr("d", s.d);
|
|
47746
|
+
const landClip = defs.append("clipPath").attr("id", landClipId);
|
|
47747
|
+
for (const r of layout.regions)
|
|
47748
|
+
if (r.id !== "lake") landClip.append("path").attr("d", r.d);
|
|
47749
|
+
const gRelief = svg.append("g").attr("clip-path", `url(#${landClipId})`).append("g").attr("class", "dgmo-map-relief").attr("clip-path", `url(#${rangeClipId})`).attr("stroke", h.color).attr("stroke-width", h.width).attr("vector-effect", "non-scaling-stroke");
|
|
47750
|
+
for (let y = h.spacing; y < height; y += h.spacing) {
|
|
47751
|
+
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
47752
|
+
}
|
|
47753
|
+
}
|
|
47456
47754
|
if (layout.rivers.length) {
|
|
47457
47755
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47458
47756
|
for (const r of layout.rivers) {
|
|
@@ -47496,6 +47794,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47496
47794
|
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);
|
|
47497
47795
|
}
|
|
47498
47796
|
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);
|
|
47797
|
+
if (poi.tags) {
|
|
47798
|
+
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47799
|
+
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
47800
|
+
}
|
|
47801
|
+
}
|
|
47499
47802
|
if (onClickItem) {
|
|
47500
47803
|
c.style("cursor", "pointer").on(
|
|
47501
47804
|
"click",
|
|
@@ -47545,7 +47848,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47545
47848
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
47546
47849
|
const ramp = layout.legend.ramp;
|
|
47547
47850
|
const scoreGroup = ramp ? {
|
|
47548
|
-
name: ramp.metric?.trim() || "
|
|
47851
|
+
name: ramp.metric?.trim() || "Value",
|
|
47549
47852
|
entries: [],
|
|
47550
47853
|
gradient: {
|
|
47551
47854
|
min: ramp.min,
|
|
@@ -47572,7 +47875,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47572
47875
|
}
|
|
47573
47876
|
}
|
|
47574
47877
|
if (layout.title) {
|
|
47575
|
-
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);
|
|
47878
|
+
svg.append("text").attr("class", "dgmo-map-title").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);
|
|
47576
47879
|
}
|
|
47577
47880
|
if (layout.subtitle) {
|
|
47578
47881
|
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);
|
|
@@ -47604,6 +47907,120 @@ var init_renderer16 = __esm({
|
|
|
47604
47907
|
}
|
|
47605
47908
|
});
|
|
47606
47909
|
|
|
47910
|
+
// src/map/load-data.ts
|
|
47911
|
+
var load_data_exports = {};
|
|
47912
|
+
__export(load_data_exports, {
|
|
47913
|
+
loadMapData: () => loadMapData
|
|
47914
|
+
});
|
|
47915
|
+
async function loadNodeBuiltins() {
|
|
47916
|
+
const [{ readFile }, { fileURLToPath }, { dirname: dirname2, resolve }] = await Promise.all([
|
|
47917
|
+
import("fs/promises"),
|
|
47918
|
+
import("url"),
|
|
47919
|
+
import("path")
|
|
47920
|
+
]);
|
|
47921
|
+
return { readFile, fileURLToPath, dirname: dirname2, resolve };
|
|
47922
|
+
}
|
|
47923
|
+
async function readJson(nb, dir, name) {
|
|
47924
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
47925
|
+
}
|
|
47926
|
+
async function firstExistingDir(nb, baseDir) {
|
|
47927
|
+
for (const rel of CANDIDATE_DIRS) {
|
|
47928
|
+
const dir = nb.resolve(baseDir, rel);
|
|
47929
|
+
try {
|
|
47930
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
47931
|
+
return dir;
|
|
47932
|
+
} catch {
|
|
47933
|
+
}
|
|
47934
|
+
}
|
|
47935
|
+
throw new Error(
|
|
47936
|
+
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
47937
|
+
);
|
|
47938
|
+
}
|
|
47939
|
+
function validate(data) {
|
|
47940
|
+
const topoOk = (t) => !!t && t.type === "Topology" && !!t.objects;
|
|
47941
|
+
if (!topoOk(data.worldCoarse) || !topoOk(data.worldDetail) || !topoOk(data.usStates) || !data.gazetteer || !Array.isArray(data.gazetteer.cities) || !data.gazetteer.byName) {
|
|
47942
|
+
throw new Error("map data assets are malformed (failed shape validation)");
|
|
47943
|
+
}
|
|
47944
|
+
return data;
|
|
47945
|
+
}
|
|
47946
|
+
function moduleBaseDir(nb) {
|
|
47947
|
+
try {
|
|
47948
|
+
const url = import.meta.url;
|
|
47949
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
47950
|
+
} catch {
|
|
47951
|
+
}
|
|
47952
|
+
if (typeof __dirname !== "undefined") return __dirname;
|
|
47953
|
+
return process.cwd();
|
|
47954
|
+
}
|
|
47955
|
+
function loadMapData() {
|
|
47956
|
+
cache ??= (async () => {
|
|
47957
|
+
const nb = await loadNodeBuiltins();
|
|
47958
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
47959
|
+
const [
|
|
47960
|
+
worldCoarse,
|
|
47961
|
+
worldDetail,
|
|
47962
|
+
usStates,
|
|
47963
|
+
lakes,
|
|
47964
|
+
rivers,
|
|
47965
|
+
mountainRanges,
|
|
47966
|
+
naLand,
|
|
47967
|
+
naLakes,
|
|
47968
|
+
gazetteer
|
|
47969
|
+
] = await Promise.all([
|
|
47970
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
47971
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
47972
|
+
readJson(nb, dir, FILES.usStates),
|
|
47973
|
+
// Lakes/rivers/mountain/NA assets are optional — older bundles may predate them.
|
|
47974
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
47975
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
47976
|
+
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
47977
|
+
() => void 0
|
|
47978
|
+
),
|
|
47979
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
47980
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
47981
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
47982
|
+
]);
|
|
47983
|
+
return validate({
|
|
47984
|
+
worldCoarse,
|
|
47985
|
+
worldDetail,
|
|
47986
|
+
usStates,
|
|
47987
|
+
gazetteer,
|
|
47988
|
+
...lakes && { lakes },
|
|
47989
|
+
...rivers && { rivers },
|
|
47990
|
+
...mountainRanges && { mountainRanges },
|
|
47991
|
+
...naLand && { naLand },
|
|
47992
|
+
...naLakes && { naLakes }
|
|
47993
|
+
});
|
|
47994
|
+
})().catch((e) => {
|
|
47995
|
+
cache = void 0;
|
|
47996
|
+
throw e;
|
|
47997
|
+
});
|
|
47998
|
+
return cache;
|
|
47999
|
+
}
|
|
48000
|
+
var FILES, CANDIDATE_DIRS, cache;
|
|
48001
|
+
var init_load_data = __esm({
|
|
48002
|
+
"src/map/load-data.ts"() {
|
|
48003
|
+
"use strict";
|
|
48004
|
+
FILES = {
|
|
48005
|
+
worldCoarse: "world-coarse.json",
|
|
48006
|
+
worldDetail: "world-detail.json",
|
|
48007
|
+
usStates: "us-states.json",
|
|
48008
|
+
lakes: "lakes.json",
|
|
48009
|
+
rivers: "rivers.json",
|
|
48010
|
+
mountainRanges: "mountain-ranges.json",
|
|
48011
|
+
naLand: "na-land.json",
|
|
48012
|
+
naLakes: "na-lakes.json",
|
|
48013
|
+
gazetteer: "gazetteer.json"
|
|
48014
|
+
};
|
|
48015
|
+
CANDIDATE_DIRS = [
|
|
48016
|
+
"./data",
|
|
48017
|
+
"./map-data",
|
|
48018
|
+
"../map-data",
|
|
48019
|
+
"../src/map/data"
|
|
48020
|
+
];
|
|
48021
|
+
}
|
|
48022
|
+
});
|
|
48023
|
+
|
|
47607
48024
|
// src/pyramid/renderer.ts
|
|
47608
48025
|
var renderer_exports17 = {};
|
|
47609
48026
|
__export(renderer_exports17, {
|
|
@@ -55788,15 +56205,17 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55788
56205
|
if (detectedType === "map") {
|
|
55789
56206
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
55790
56207
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
55791
|
-
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
55792
56208
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
55793
56209
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
55794
56210
|
const mapParsed = parseMap2(content);
|
|
55795
|
-
let mapData;
|
|
55796
|
-
|
|
55797
|
-
|
|
55798
|
-
|
|
55799
|
-
|
|
56211
|
+
let mapData = options?.mapData;
|
|
56212
|
+
if (!mapData) {
|
|
56213
|
+
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
56214
|
+
try {
|
|
56215
|
+
mapData = await loadMapData2();
|
|
56216
|
+
} catch {
|
|
56217
|
+
return "";
|
|
56218
|
+
}
|
|
55800
56219
|
}
|
|
55801
56220
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
55802
56221
|
const container2 = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
|
|
@@ -57090,6 +57509,160 @@ init_load_data();
|
|
|
57090
57509
|
init_layout15();
|
|
57091
57510
|
init_renderer16();
|
|
57092
57511
|
|
|
57512
|
+
// src/map/geo-query.ts
|
|
57513
|
+
init_parser12();
|
|
57514
|
+
init_resolver2();
|
|
57515
|
+
init_layout15();
|
|
57516
|
+
init_geo();
|
|
57517
|
+
|
|
57518
|
+
// src/map/invert.ts
|
|
57519
|
+
function inInsetFrame(inset, px, py) {
|
|
57520
|
+
return px >= inset.x && px <= inset.x + inset.w && py >= inset.y && py <= inset.y + inset.h;
|
|
57521
|
+
}
|
|
57522
|
+
function unstretch(layout, px, py) {
|
|
57523
|
+
const s = layout.stretch;
|
|
57524
|
+
return [
|
|
57525
|
+
s.bx0 + (s.sx !== 0 ? (px - s.ox) / s.sx : 0),
|
|
57526
|
+
s.by0 + (s.sy !== 0 ? (py - s.oy) / s.sy : 0)
|
|
57527
|
+
];
|
|
57528
|
+
}
|
|
57529
|
+
function applyStretch(layout, x, y) {
|
|
57530
|
+
const s = layout.stretch;
|
|
57531
|
+
return [s.ox + (x - s.bx0) * s.sx, s.oy + (y - s.by0) * s.sy];
|
|
57532
|
+
}
|
|
57533
|
+
function pixelToLonLat(layout, px, py) {
|
|
57534
|
+
for (const inset of layout.insets) {
|
|
57535
|
+
if (inInsetFrame(inset, px, py)) {
|
|
57536
|
+
const ll2 = inset.projection.invert?.([px, py]);
|
|
57537
|
+
return ll2 && Number.isFinite(ll2[0]) && Number.isFinite(ll2[1]) ? [ll2[0], ll2[1]] : null;
|
|
57538
|
+
}
|
|
57539
|
+
}
|
|
57540
|
+
const [x, y] = layout.stretch ? unstretch(layout, px, py) : [px, py];
|
|
57541
|
+
const ll = layout.projection.invert?.([x, y]);
|
|
57542
|
+
return ll && Number.isFinite(ll[0]) && Number.isFinite(ll[1]) ? [ll[0], ll[1]] : null;
|
|
57543
|
+
}
|
|
57544
|
+
function lonLatToPixel(layout, lonLat) {
|
|
57545
|
+
const pt = [lonLat[0], lonLat[1]];
|
|
57546
|
+
const main = layout.projection(pt);
|
|
57547
|
+
const mainPx = main && Number.isFinite(main[0]) && Number.isFinite(main[1]) ? layout.stretch ? applyStretch(layout, main[0], main[1]) : [main[0], main[1]] : null;
|
|
57548
|
+
const onCanvas = !!mainPx && mainPx[0] >= 0 && mainPx[0] <= layout.width && mainPx[1] >= 0 && mainPx[1] <= layout.height;
|
|
57549
|
+
if (onCanvas) return mainPx;
|
|
57550
|
+
for (const inset of layout.insets) {
|
|
57551
|
+
const p = inset.projection(pt);
|
|
57552
|
+
if (p && Number.isFinite(p[0]) && Number.isFinite(p[1]) && inInsetFrame(inset, p[0], p[1]))
|
|
57553
|
+
return [p[0], p[1]];
|
|
57554
|
+
}
|
|
57555
|
+
return mainPx;
|
|
57556
|
+
}
|
|
57557
|
+
|
|
57558
|
+
// src/map/geo-query.ts
|
|
57559
|
+
var EARTH_R_KM = 6371;
|
|
57560
|
+
var DEG = Math.PI / 180;
|
|
57561
|
+
function haversineKm(lat1, lon1, lat2, lon2) {
|
|
57562
|
+
const dLat = (lat2 - lat1) * DEG;
|
|
57563
|
+
const dLon = (lon2 - lon1) * DEG;
|
|
57564
|
+
const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1 * DEG) * Math.cos(lat2 * DEG) * Math.sin(dLon / 2) ** 2;
|
|
57565
|
+
return 2 * EARTH_R_KM * Math.asin(Math.min(1, Math.sqrt(a)));
|
|
57566
|
+
}
|
|
57567
|
+
var POP_PULL_KM = 12;
|
|
57568
|
+
function nearestCity(lonLat, gazetteer) {
|
|
57569
|
+
const [lon, lat] = lonLat;
|
|
57570
|
+
let best = null;
|
|
57571
|
+
const cities = gazetteer.cities;
|
|
57572
|
+
for (let i = 0; i < cities.length; i++) {
|
|
57573
|
+
const c2 = cities[i];
|
|
57574
|
+
const dist = haversineKm(lat, lon, c2[0], c2[1]);
|
|
57575
|
+
const score = dist - POP_PULL_KM * Math.log10((c2[3] || 0) + 1);
|
|
57576
|
+
if (!best || score < best.score) best = { score, idx: i, dist };
|
|
57577
|
+
}
|
|
57578
|
+
if (!best) return null;
|
|
57579
|
+
const c = cities[best.idx];
|
|
57580
|
+
return {
|
|
57581
|
+
name: c[4],
|
|
57582
|
+
iso: c[2],
|
|
57583
|
+
...c[5] !== void 0 && { sub: c[5] },
|
|
57584
|
+
distanceKm: best.dist
|
|
57585
|
+
};
|
|
57586
|
+
}
|
|
57587
|
+
function roundCoord(n) {
|
|
57588
|
+
return Number(n.toFixed(2));
|
|
57589
|
+
}
|
|
57590
|
+
function buildTokens(lonLat, region, city) {
|
|
57591
|
+
const coordPoiLine = `poi ${roundCoord(lonLat[1])} ${roundCoord(lonLat[0])}`;
|
|
57592
|
+
let stateTok = null;
|
|
57593
|
+
if (region.state) {
|
|
57594
|
+
const { iso, name } = region.state;
|
|
57595
|
+
stateTok = { primary: `${name} ${iso}`, alternates: [iso, name] };
|
|
57596
|
+
}
|
|
57597
|
+
let countryTok = null;
|
|
57598
|
+
if (region.country) {
|
|
57599
|
+
const { iso, name } = region.country;
|
|
57600
|
+
countryTok = { primary: name, alternates: [iso] };
|
|
57601
|
+
}
|
|
57602
|
+
let cityTok = null;
|
|
57603
|
+
if (city) {
|
|
57604
|
+
const scope = city.sub ?? (city.iso || "");
|
|
57605
|
+
cityTok = scope ? { token: `poi ${city.name} ${scope}`, ambiguous: false } : { token: `poi ${city.name}`, ambiguous: true };
|
|
57606
|
+
}
|
|
57607
|
+
return { coordPoiLine, state: stateTok, country: countryTok, city: cityTok };
|
|
57608
|
+
}
|
|
57609
|
+
var MAX_CITY_DOTS = 250;
|
|
57610
|
+
function createMapGeoQuery(opts) {
|
|
57611
|
+
const { content, width, height, data, palette, isDark } = opts;
|
|
57612
|
+
const resolved = resolveMap(parseMap(content), data);
|
|
57613
|
+
const layout = layoutMap(
|
|
57614
|
+
resolved,
|
|
57615
|
+
data,
|
|
57616
|
+
{ width, height },
|
|
57617
|
+
{ palette, isDark }
|
|
57618
|
+
);
|
|
57619
|
+
const countries = decodeFeatures(data.worldDetail);
|
|
57620
|
+
const states = decodeFeatures(data.usStates);
|
|
57621
|
+
const gazetteer = data.gazetteer;
|
|
57622
|
+
const invert = (px, py) => pixelToLonLat(layout, px, py);
|
|
57623
|
+
const project = (lonLat) => lonLatToPixel(layout, lonLat);
|
|
57624
|
+
const locate = (px, py) => {
|
|
57625
|
+
const lonLat = invert(px, py);
|
|
57626
|
+
if (!lonLat) return null;
|
|
57627
|
+
const region = regionAt(lonLat, countries, states);
|
|
57628
|
+
const city = nearestCity(lonLat, gazetteer);
|
|
57629
|
+
return {
|
|
57630
|
+
lonLat,
|
|
57631
|
+
country: region.country,
|
|
57632
|
+
state: region.state,
|
|
57633
|
+
nearestCity: city,
|
|
57634
|
+
tokens: buildTokens(lonLat, region, city)
|
|
57635
|
+
};
|
|
57636
|
+
};
|
|
57637
|
+
const cities = (extent2) => {
|
|
57638
|
+
const sorted = [...gazetteer.cities].sort((a, b) => b[3] - a[3]);
|
|
57639
|
+
const out = [];
|
|
57640
|
+
for (const c of sorted) {
|
|
57641
|
+
const [lat, lon, iso, pop, name, sub] = c;
|
|
57642
|
+
if (extent2) {
|
|
57643
|
+
const [[w, s], [e, n]] = extent2;
|
|
57644
|
+
if (lon < w || lon > e || lat < s || lat > n) continue;
|
|
57645
|
+
}
|
|
57646
|
+
const p = project([lon, lat]);
|
|
57647
|
+
if (!p) continue;
|
|
57648
|
+
if (p[0] < 0 || p[0] > width || p[1] < 0 || p[1] > height) continue;
|
|
57649
|
+
out.push({
|
|
57650
|
+
name,
|
|
57651
|
+
iso,
|
|
57652
|
+
...sub !== void 0 && { sub },
|
|
57653
|
+
lon,
|
|
57654
|
+
lat,
|
|
57655
|
+
px: p[0],
|
|
57656
|
+
py: p[1],
|
|
57657
|
+
pop
|
|
57658
|
+
});
|
|
57659
|
+
if (out.length >= MAX_CITY_DOTS) break;
|
|
57660
|
+
}
|
|
57661
|
+
return out;
|
|
57662
|
+
};
|
|
57663
|
+
return { invert, project, locate, cities };
|
|
57664
|
+
}
|
|
57665
|
+
|
|
57093
57666
|
// src/map/completion.ts
|
|
57094
57667
|
var fold2 = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
57095
57668
|
var groupThousands = (n) => String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
@@ -58212,7 +58785,7 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
58212
58785
|
[
|
|
58213
58786
|
"map",
|
|
58214
58787
|
// Geographic map directives (§24B.2/.7). `poi`/`route` are content
|
|
58215
|
-
// keywords, not directives; metadata keys (
|
|
58788
|
+
// keywords, not directives; metadata keys (value/label/style) live in the
|
|
58216
58789
|
// reserved-key registry.
|
|
58217
58790
|
withGlobals({
|
|
58218
58791
|
region: {
|
|
@@ -58223,9 +58796,14 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
58223
58796
|
description: "Override the auto projection",
|
|
58224
58797
|
values: ["equirectangular", "natural-earth", "albers-usa", "mercator"]
|
|
58225
58798
|
},
|
|
58226
|
-
metric: { description: "Label for the region
|
|
58227
|
-
"
|
|
58228
|
-
|
|
58799
|
+
"region-metric": { description: "Label for the region value ramp" },
|
|
58800
|
+
"poi-metric": {
|
|
58801
|
+
description: "Label for the POI value (marker size) channel"
|
|
58802
|
+
},
|
|
58803
|
+
"flow-metric": {
|
|
58804
|
+
description: "Label for the edge/leg value (thickness) channel"
|
|
58805
|
+
},
|
|
58806
|
+
scale: { description: "Override value ramp anchors: scale <min> <max>" },
|
|
58229
58807
|
"region-labels": {
|
|
58230
58808
|
description: "Subdivision name labels",
|
|
58231
58809
|
values: ["full", "abbrev", "off"]
|
|
@@ -58237,6 +58815,7 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
58237
58815
|
"default-country": { description: "ISO scope for bare city resolution" },
|
|
58238
58816
|
"default-state": { description: "ISO subdivision scope" },
|
|
58239
58817
|
"no-legend": { description: "Suppress the legend" },
|
|
58818
|
+
relief: { description: "Subtle mountain-range relief shading" },
|
|
58240
58819
|
subtitle: { description: "Subtitle line" },
|
|
58241
58820
|
caption: { description: "Caption line" }
|
|
58242
58821
|
})
|
|
@@ -59747,6 +60326,7 @@ export {
|
|
|
59747
60326
|
computeTimeTicks,
|
|
59748
60327
|
contrastText,
|
|
59749
60328
|
controlsGroupCapsuleWidth,
|
|
60329
|
+
createMapGeoQuery,
|
|
59750
60330
|
decodeDiagramUrl,
|
|
59751
60331
|
decodeViewState,
|
|
59752
60332
|
displayName,
|