@chrtco/sdk 0.10.44 → 0.10.46
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/CHANGELOG.md +13 -0
- package/dist/atlas/browser.cjs +139 -10
- package/dist/atlas/browser.cjs.map +1 -1
- package/dist/atlas/browser.d.cts +7 -2
- package/dist/atlas/browser.d.ts +7 -2
- package/dist/atlas/browser.js +139 -10
- package/dist/atlas/browser.js.map +1 -1
- package/dist/index.cjs +115 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +155 -1
- package/dist/index.d.ts +155 -1
- package/dist/index.js +108 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/atlas/browser.d.cts
CHANGED
|
@@ -42,7 +42,7 @@ interface SymbolImageSpec {
|
|
|
42
42
|
*/
|
|
43
43
|
declare const BASE_PATTERN_GLYPHS: readonly string[];
|
|
44
44
|
|
|
45
|
-
/** The two world hatches, in this palette. */
|
|
45
|
+
/** The two world hatches, in this palette (coloured by `basePatternSvg`). */
|
|
46
46
|
declare function basePatternImageSpecs(palette: ColorTableName): SymbolImageSpec[];
|
|
47
47
|
/** The CHRT house glyphs (not the hatches, which `basePatternImageSpecs` owns). */
|
|
48
48
|
declare function chrtImageSpecs(palette: ColorTableName): SymbolImageSpec[];
|
|
@@ -217,7 +217,7 @@ declare function reloadS101SymbolImages(map: maplibregl.Map, colorTable: ColorTa
|
|
|
217
217
|
* NOTHING with no error anywhere (the crosshatch silently absent from the
|
|
218
218
|
* whole world map). Two images, loaded beside every family's loader.
|
|
219
219
|
*
|
|
220
|
-
* Themed per palette (`
|
|
220
|
+
* Themed per palette (`basePatternSvg`): the hatches cover the whole uncharted
|
|
221
221
|
* world, and at NIGHT they were the one grey-blue texture on a dark chart.
|
|
222
222
|
*/
|
|
223
223
|
declare function loadBasePatternImages(map: maplibregl.Map, colorTable?: ColorTableName): Promise<void>;
|
|
@@ -343,6 +343,8 @@ interface RethemeResult {
|
|
|
343
343
|
/**
|
|
344
344
|
* Register every spec the map does not already hold. A first load, so there is
|
|
345
345
|
* nothing to update in place; images the map already has are left alone.
|
|
346
|
+
*
|
|
347
|
+
* A map removed while a decode was out is left alone too — see `isMapLive`.
|
|
346
348
|
*/
|
|
347
349
|
declare function loadSymbolImageSpecs(map: maplibregl.Map, specs: readonly SymbolImageSpec[]): Promise<void>;
|
|
348
350
|
/**
|
|
@@ -352,6 +354,9 @@ declare function loadSymbolImageSpecs(map: maplibregl.Map, specs: readonly Symbo
|
|
|
352
354
|
* reload). One it does not hold, or holds at another size, is added — the
|
|
353
355
|
* slow path, which only a first load or a drifted spec should ever take, and
|
|
354
356
|
* `RethemeResult.added` says how often it did.
|
|
357
|
+
*
|
|
358
|
+
* A map removed part-way (`isMapLive`) ends the re-theme as `aborted`: there is
|
|
359
|
+
* nothing left to draw on, and whoever removed it is building the next one.
|
|
355
360
|
*/
|
|
356
361
|
declare function rethemeSymbolImages(map: maplibregl.Map, specs: readonly SymbolImageSpec[], opts?: RethemeOptions): Promise<RethemeResult>;
|
|
357
362
|
|
package/dist/atlas/browser.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ interface SymbolImageSpec {
|
|
|
42
42
|
*/
|
|
43
43
|
declare const BASE_PATTERN_GLYPHS: readonly string[];
|
|
44
44
|
|
|
45
|
-
/** The two world hatches, in this palette. */
|
|
45
|
+
/** The two world hatches, in this palette (coloured by `basePatternSvg`). */
|
|
46
46
|
declare function basePatternImageSpecs(palette: ColorTableName): SymbolImageSpec[];
|
|
47
47
|
/** The CHRT house glyphs (not the hatches, which `basePatternImageSpecs` owns). */
|
|
48
48
|
declare function chrtImageSpecs(palette: ColorTableName): SymbolImageSpec[];
|
|
@@ -217,7 +217,7 @@ declare function reloadS101SymbolImages(map: maplibregl.Map, colorTable: ColorTa
|
|
|
217
217
|
* NOTHING with no error anywhere (the crosshatch silently absent from the
|
|
218
218
|
* whole world map). Two images, loaded beside every family's loader.
|
|
219
219
|
*
|
|
220
|
-
* Themed per palette (`
|
|
220
|
+
* Themed per palette (`basePatternSvg`): the hatches cover the whole uncharted
|
|
221
221
|
* world, and at NIGHT they were the one grey-blue texture on a dark chart.
|
|
222
222
|
*/
|
|
223
223
|
declare function loadBasePatternImages(map: maplibregl.Map, colorTable?: ColorTableName): Promise<void>;
|
|
@@ -343,6 +343,8 @@ interface RethemeResult {
|
|
|
343
343
|
/**
|
|
344
344
|
* Register every spec the map does not already hold. A first load, so there is
|
|
345
345
|
* nothing to update in place; images the map already has are left alone.
|
|
346
|
+
*
|
|
347
|
+
* A map removed while a decode was out is left alone too — see `isMapLive`.
|
|
346
348
|
*/
|
|
347
349
|
declare function loadSymbolImageSpecs(map: maplibregl.Map, specs: readonly SymbolImageSpec[]): Promise<void>;
|
|
348
350
|
/**
|
|
@@ -352,6 +354,9 @@ declare function loadSymbolImageSpecs(map: maplibregl.Map, specs: readonly Symbo
|
|
|
352
354
|
* reload). One it does not hold, or holds at another size, is added — the
|
|
353
355
|
* slow path, which only a first load or a drifted spec should ever take, and
|
|
354
356
|
* `RethemeResult.added` says how often it did.
|
|
357
|
+
*
|
|
358
|
+
* A map removed part-way (`isMapLive`) ends the re-theme as `aborted`: there is
|
|
359
|
+
* nothing left to draw on, and whoever removed it is building the next one.
|
|
355
360
|
*/
|
|
356
361
|
declare function rethemeSymbolImages(map: maplibregl.Map, specs: readonly SymbolImageSpec[], opts?: RethemeOptions): Promise<RethemeResult>;
|
|
357
362
|
|
package/dist/atlas/browser.js
CHANGED
|
@@ -1112,6 +1112,11 @@ function applyStrokeBoost(svgString, multiplier) {
|
|
|
1112
1112
|
}
|
|
1113
1113
|
var S52_STROKE_BOOST = 1;
|
|
1114
1114
|
|
|
1115
|
+
// src/atlas/map-live.ts
|
|
1116
|
+
function isMapLive(map) {
|
|
1117
|
+
return map._removed !== true;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1115
1120
|
// src/atlas/symbol-images-browser.ts
|
|
1116
1121
|
function dataUrl(svg2) {
|
|
1117
1122
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg2)}`;
|
|
@@ -1252,9 +1257,9 @@ function existingSize(map, id) {
|
|
|
1252
1257
|
async function loadSymbolImageSpecs(map, specs) {
|
|
1253
1258
|
await Promise.all(
|
|
1254
1259
|
specs.map(async (spec) => {
|
|
1255
|
-
if (map.hasImage(spec.id)) return;
|
|
1260
|
+
if (!isMapLive(map) || map.hasImage(spec.id)) return;
|
|
1256
1261
|
const img = await decode(spec);
|
|
1257
|
-
if (!img || map.hasImage(spec.id)) return;
|
|
1262
|
+
if (!img || !isMapLive(map) || map.hasImage(spec.id)) return;
|
|
1258
1263
|
map.addImage(spec.id, img, { sdf: spec.sdf, pixelRatio: spec.pixelRatio });
|
|
1259
1264
|
})
|
|
1260
1265
|
);
|
|
@@ -1278,7 +1283,7 @@ async function rethemeSymbolImages(map, specs, opts = {}) {
|
|
|
1278
1283
|
}
|
|
1279
1284
|
const sources = await sourcesFor(unit, decoded[u]);
|
|
1280
1285
|
for (let i = 0; i < unitSpecs.length; i++) {
|
|
1281
|
-
if (opts.signal?.aborted) {
|
|
1286
|
+
if (opts.signal?.aborted || !isMapLive(map)) {
|
|
1282
1287
|
result.aborted = true;
|
|
1283
1288
|
break outer;
|
|
1284
1289
|
}
|
|
@@ -1312,6 +1317,10 @@ async function rethemeSymbolImages(map, specs, opts = {}) {
|
|
|
1312
1317
|
}
|
|
1313
1318
|
}
|
|
1314
1319
|
}
|
|
1320
|
+
if (!isMapLive(map)) {
|
|
1321
|
+
result.aborted = true;
|
|
1322
|
+
return result;
|
|
1323
|
+
}
|
|
1315
1324
|
map.triggerRepaint();
|
|
1316
1325
|
opts.onProgress?.({ done, total });
|
|
1317
1326
|
return result;
|
|
@@ -1488,7 +1497,7 @@ async function imageToBitmap(img, size) {
|
|
|
1488
1497
|
}
|
|
1489
1498
|
}
|
|
1490
1499
|
function addImageToMap(map, name, image) {
|
|
1491
|
-
if (map.hasImage(name)) return;
|
|
1500
|
+
if (!isMapLive(map) || map.hasImage(name)) return;
|
|
1492
1501
|
try {
|
|
1493
1502
|
map.addImage(name, image, {
|
|
1494
1503
|
sdf: SDF_SYMBOLS2.has(name),
|
|
@@ -1515,6 +1524,7 @@ async function loadS52SymbolImagesCached(map, colorTable = "DAY", opts = {}) {
|
|
|
1515
1524
|
cached = /* @__PURE__ */ new Map();
|
|
1516
1525
|
}
|
|
1517
1526
|
}
|
|
1527
|
+
if (!isMapLive(map)) return;
|
|
1518
1528
|
for (const [name, bitmap] of cached) {
|
|
1519
1529
|
addImageToMap(map, name, bitmap);
|
|
1520
1530
|
}
|
|
@@ -1528,7 +1538,7 @@ async function loadS52SymbolImagesCached(map, colorTable = "DAY", opts = {}) {
|
|
|
1528
1538
|
const size = rasterSize2(name, themed);
|
|
1529
1539
|
const img = await decodeSvgToImage(themed, size);
|
|
1530
1540
|
if (!img) return;
|
|
1531
|
-
addImageToMap(map, name, img);
|
|
1541
|
+
if (isMapLive(map)) addImageToMap(map, name, img);
|
|
1532
1542
|
try {
|
|
1533
1543
|
const bitmap = await imageToBitmap(img, size);
|
|
1534
1544
|
if (!bitmap) return;
|
|
@@ -15543,7 +15553,7 @@ async function loadSymbolImages(map) {
|
|
|
15543
15553
|
const svgStr = sym.getSvg();
|
|
15544
15554
|
const img = new Image(SIZE2, SIZE2);
|
|
15545
15555
|
img.onload = () => {
|
|
15546
|
-
if (!map.hasImage(sym.id)) {
|
|
15556
|
+
if (isMapLive(map) && !map.hasImage(sym.id)) {
|
|
15547
15557
|
map.addImage(sym.id, img, { sdf: false });
|
|
15548
15558
|
}
|
|
15549
15559
|
resolve();
|
|
@@ -15573,7 +15583,7 @@ async function loadThemedBridgeImages(map, colorTable) {
|
|
|
15573
15583
|
const svgStr = sym.getThemedSvg(chblk, trfcd);
|
|
15574
15584
|
const img = new Image(SIZE2, SIZE2);
|
|
15575
15585
|
img.onload = () => {
|
|
15576
|
-
if (!map.hasImage(sym.id)) {
|
|
15586
|
+
if (isMapLive(map) && !map.hasImage(sym.id)) {
|
|
15577
15587
|
map.addImage(sym.id, img, { sdf: false });
|
|
15578
15588
|
}
|
|
15579
15589
|
resolve();
|
|
@@ -15691,6 +15701,126 @@ function themeChrtGlyph(svg2, palette = "DAY") {
|
|
|
15691
15701
|
);
|
|
15692
15702
|
}
|
|
15693
15703
|
|
|
15704
|
+
// src/atlas/base-layers.ts
|
|
15705
|
+
var UNCHARTED_PATTERN = "chrt:hatch-uncharted";
|
|
15706
|
+
function inlandHatchColor(palette) {
|
|
15707
|
+
return (BASE_THEMES[palette] ?? BASE_THEMES.DAY).inlandHatch;
|
|
15708
|
+
}
|
|
15709
|
+
function basePatternSvg(name, palette) {
|
|
15710
|
+
const raw = CHRT_GLYPH_SVGS[name];
|
|
15711
|
+
if (!raw) return null;
|
|
15712
|
+
if (`${CHRT_ICON_PREFIX}${name}` === UNCHARTED_PATTERN) {
|
|
15713
|
+
return raw.replace(/stroke="#[0-9a-fA-F]{3,6}"/g, `stroke="${inlandHatchColor(palette)}"`);
|
|
15714
|
+
}
|
|
15715
|
+
return themeChrtGlyph(raw, palette);
|
|
15716
|
+
}
|
|
15717
|
+
var BASE_THEMES = {
|
|
15718
|
+
DAY: {
|
|
15719
|
+
// ── `earth` is the jurisdiction tan DIMMED (~0.55), not a blue-grey ──
|
|
15720
|
+
// Outside the jurisdiction the map still owes the reader "what is land".
|
|
15721
|
+
// State 3 in the header is "the geography, under a crosshatch", and until
|
|
15722
|
+
// 2026-08-31 that geography was unreadable: earth #2A3439 against sea
|
|
15723
|
+
// #1B2328 measured 1.25:1, so Hispaniola showed charted boxes with tan
|
|
15724
|
+
// land inside and nothing recognisable around them (owner report: "no
|
|
15725
|
+
// land painting down near the DR at some zooms"). Land is warm and sea is
|
|
15726
|
+
// cool because that is what land and sea are; dimming the JURISDICTION
|
|
15727
|
+
// tan rather than inventing a colour says the true thing — this is the
|
|
15728
|
+
// same land, we simply do not carry charts for it. Held against BOTH
|
|
15729
|
+
// neighbours: legible over sea, and never mistakable for the full tan of
|
|
15730
|
+
// a country we do carry. DAY 3.59:1 vs sea, 3.17:1 vs tan.
|
|
15731
|
+
earth: "#807761",
|
|
15732
|
+
water: "#1B2328",
|
|
15733
|
+
river: "#24313A",
|
|
15734
|
+
boundary: "#4A575E",
|
|
15735
|
+
jurisdiction: "#D4C69D",
|
|
15736
|
+
// CHRTland's own tan — one land colour
|
|
15737
|
+
inlandWater: "#B9CFDD",
|
|
15738
|
+
// muted, unmistakably not a charted blue
|
|
15739
|
+
// The uncharted hatch's stripe, held to 2.3:1 against `inlandWater` in
|
|
15740
|
+
// every palette (`inland-hatch-contrast.test.ts`) — the hatch says "we have
|
|
15741
|
+
// not charted this water", and stripes the eye cannot find say nothing.
|
|
15742
|
+
// DAY 3.08:1, darker than its ground. Also the colour the artwork file
|
|
15743
|
+
// itself is drawn in.
|
|
15744
|
+
inlandHatch: "#5B7383",
|
|
15745
|
+
// State furniture. These three were referenced by the layers but missing
|
|
15746
|
+
// from this table (and its type — the long-standing TS2339 trio), so the
|
|
15747
|
+
// lines shipped on MapLibre's DEFAULT black. Now deliberate: a hairline
|
|
15748
|
+
// a shade deeper than the tan, quiet caps, tan halo.
|
|
15749
|
+
stateLine: "#B1A077",
|
|
15750
|
+
stateLabel: "#8E8468",
|
|
15751
|
+
stateHalo: "#D4C69D",
|
|
15752
|
+
// Rough-lake furniture (owner ask 2026-08-28: "the lakes need labels,
|
|
15753
|
+
// and shorelines drawn"): a shoreline a shade deeper than the rough
|
|
15754
|
+
// water, and a name in the water's own voice, haloed by the water.
|
|
15755
|
+
inlandShore: "#8FA9BA",
|
|
15756
|
+
inlandLabel: "#54707F",
|
|
15757
|
+
inlandHalo: "#B9CFDD"
|
|
15758
|
+
},
|
|
15759
|
+
DUSK: {
|
|
15760
|
+
// ── Re-derived 2026-09-01: the basemap sits UNDER the chart ──────────
|
|
15761
|
+
// These were the DAY tones scaled by a constant, never measured against
|
|
15762
|
+
// the DUSK chart — so `jurisdiction` came out at L=0.506 against a chart
|
|
15763
|
+
// whose own land (LANDA #8a7d5e) is L=0.209, i.e. the context layer was
|
|
15764
|
+
// 2.4x brighter than the data layer. Now capped at the chart's own land.
|
|
15765
|
+
// The rest of the block rides the same 0.666 channel factor so every
|
|
15766
|
+
// relationship the palette already chose is preserved, only moved down.
|
|
15767
|
+
// `water` is deliberately NOT scaled: it is the reference the land/sea
|
|
15768
|
+
// floor is measured against.
|
|
15769
|
+
earth: "#544E3E",
|
|
15770
|
+
water: "#161D21",
|
|
15771
|
+
river: "#141B20",
|
|
15772
|
+
boundary: "#293135",
|
|
15773
|
+
jurisdiction: "#867D64",
|
|
15774
|
+
inlandWater: "#62717A",
|
|
15775
|
+
// Owner's choice, 2026-10-04: dark stripes, 2.37:1. The DAY stripe here
|
|
15776
|
+
// was 1.02:1 — invisible, so an uncharted lake read as plain water.
|
|
15777
|
+
inlandHatch: "#2E383F",
|
|
15778
|
+
// Label stays DARK here — the halo is still mid-toned, so 3:1 is reachable
|
|
15779
|
+
// downward and a bright label would be a new light source at dusk.
|
|
15780
|
+
stateLine: "#B5A987",
|
|
15781
|
+
stateLabel: "#38342A",
|
|
15782
|
+
stateHalo: "#867D64",
|
|
15783
|
+
inlandShore: "#4D5B67",
|
|
15784
|
+
inlandLabel: "#212629",
|
|
15785
|
+
inlandHalo: "#62717A"
|
|
15786
|
+
},
|
|
15787
|
+
NIGHT: {
|
|
15788
|
+
// ── Re-derived 2026-09-01 — the owner-reported night defect ──────────
|
|
15789
|
+
// `jurisdiction` was L=0.240 against a chart whose own land (LANDA
|
|
15790
|
+
// #3a3020) is L=0.031: the world basemap was 7.7x BRIGHTER than the chart
|
|
15791
|
+
// it sits under, so at z<11 the uncharted interior read as a pale
|
|
15792
|
+
// continent-sized slab on a night chart. Capped at the chart's own land.
|
|
15793
|
+
//
|
|
15794
|
+
// ⚠ `earth` AND `jurisdiction` CONVERGE HERE, and that is forced, not
|
|
15795
|
+
// sloppy. Holding earth 2:1 above the ocean AND 2:1 below the jurisdiction
|
|
15796
|
+
// tan requires jurisdiction >= L 0.174 — 5.6x the chart's own land. At
|
|
15797
|
+
// night the range between the ocean (L 0.006) and the cap (L 0.031) is too
|
|
15798
|
+
// compressed to carry two land tones. COVERAGE IS STILL SAID, by the
|
|
15799
|
+
// `chrt:hatch-nocoverage` crosshatch, which is a stronger signal than tone
|
|
15800
|
+
// and is the one thing that cannot be lost to palette compression.
|
|
15801
|
+
//
|
|
15802
|
+
// Labels invert to light-on-dark: 3:1 downward is unreachable off a halo
|
|
15803
|
+
// this close to black, and CHRTland's own night town labels already sit at
|
|
15804
|
+
// L=0.177 for exactly this reason.
|
|
15805
|
+
earth: "#333026",
|
|
15806
|
+
water: "#10161A",
|
|
15807
|
+
river: "#090D0F",
|
|
15808
|
+
boundary: "#131719",
|
|
15809
|
+
jurisdiction: "#353128",
|
|
15810
|
+
inlandWater: "#232A30",
|
|
15811
|
+
// The DAY stripe, lighter than this ground: 2.92:1, and L 0.16, under the
|
|
15812
|
+
// NIGHT muted-ink ceiling (`night-luminance.test.ts`). Red night draws the
|
|
15813
|
+
// NIGHT chart, so this is its stripe too.
|
|
15814
|
+
inlandHatch: "#5B7383",
|
|
15815
|
+
stateLine: "#484236",
|
|
15816
|
+
stateLabel: "#837963",
|
|
15817
|
+
stateHalo: "#353128",
|
|
15818
|
+
inlandShore: "#1C2227",
|
|
15819
|
+
inlandLabel: "#617484",
|
|
15820
|
+
inlandHalo: "#232A30"
|
|
15821
|
+
}
|
|
15822
|
+
};
|
|
15823
|
+
|
|
15694
15824
|
// src/atlas/chrtraster-svgs-generated.ts
|
|
15695
15825
|
var CHRTRASTER_SVGS = {
|
|
15696
15826
|
"BCNGEN05": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M 11.6 26.8 L 11.6 1.0 L 20.0 1.0 L 20.0 27.2 L 19.4 25.8 L 19.3 24.7 L 18.9 24.3 L 17.6 23.7 L 16.5 23.4 L 16.2 23.2 L 15.1 23.4 L 14.5 23.4 L 13.8 23.7 L 13.3 24.5 L 12.7 25.3 L 12.0 25.8 L 11.6 26.6 Z" fill="CHWHT" /><path d="M 11.6 26.8 L 11.6 1.0 L 20.0 1.0 L 20.0 27.2 L 19.4 25.8 L 19.3 24.7 L 18.9 24.3 L 17.6 23.7 L 16.5 23.4 L 16.2 23.2 L 15.1 23.4 L 14.5 23.4 L 13.8 23.7 L 13.3 24.5 L 12.7 25.3 L 12.0 25.8 L 11.6 26.6 Z" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linejoin="round" /><circle cx="16.00" cy="27.21" r="3.79" fill="none" stroke="CHBLK" stroke-width="1.2" /><path d="M 7.3 27.2 L 12.2 27.2" fill="none" stroke="CHBLK" stroke-width="1.2" /><path d="M 19.8 27.2 L 24.7 27.2" fill="none" stroke="CHBLK" stroke-width="1.2" /></svg>',
|
|
@@ -16290,10 +16420,9 @@ function declared(id, svg2) {
|
|
|
16290
16420
|
}
|
|
16291
16421
|
function basePatternImageSpecs(palette) {
|
|
16292
16422
|
return BASE_PATTERN_GLYPHS.flatMap((name) => {
|
|
16293
|
-
const
|
|
16294
|
-
if (!
|
|
16423
|
+
const svg2 = basePatternSvg(name, palette);
|
|
16424
|
+
if (!svg2) return [];
|
|
16295
16425
|
const id = `${CHRT_ICON_PREFIX}${name}`;
|
|
16296
|
-
const svg2 = themeChrtGlyph(raw, palette);
|
|
16297
16426
|
return [{ id, svg: svg2, ...declared(id, svg2), pixelRatio: 1, sdf: false }];
|
|
16298
16427
|
});
|
|
16299
16428
|
}
|