@chrtco/sdk 0.10.46 → 0.10.47
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 +22 -0
- package/README.md +29 -6
- package/dist/atlas/browser.cjs +339 -5
- package/dist/atlas/browser.cjs.map +1 -1
- package/dist/atlas/browser.d.cts +1 -1
- package/dist/atlas/browser.d.ts +1 -1
- package/dist/atlas/browser.js +339 -5
- package/dist/atlas/browser.js.map +1 -1
- package/dist/index.cjs +2344 -1748
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1236 -1163
- package/dist/index.d.ts +1236 -1163
- package/dist/index.js +2332 -1748
- package/dist/index.js.map +1 -1
- package/dist/symbol-families-De7sN-p5.d.cts +93 -0
- package/dist/symbol-families-De7sN-p5.d.ts +93 -0
- package/package.json +1 -1
- package/dist/symbol-families-D2Kx20HJ.d.cts +0 -47
- package/dist/symbol-families-D2Kx20HJ.d.ts +0 -47
package/dist/index.js
CHANGED
|
@@ -2057,6 +2057,19 @@ function s57AbbrTable(acronym) {
|
|
|
2057
2057
|
}
|
|
2058
2058
|
|
|
2059
2059
|
// src/atlas/s52-colors.ts
|
|
2060
|
+
var EINK_COLOR_TABLES = { color: "EINK_COLOR", mono: "EINK_MONO", night: "EINK_NIGHT" };
|
|
2061
|
+
function isEinkColorTable(ct) {
|
|
2062
|
+
return ct === "EINK_COLOR" || ct === "EINK_MONO" || ct === "EINK_NIGHT";
|
|
2063
|
+
}
|
|
2064
|
+
function isEinkGreyTable(ct) {
|
|
2065
|
+
return ct === "EINK_MONO" || ct === "EINK_NIGHT";
|
|
2066
|
+
}
|
|
2067
|
+
var EINK_MONO_GREYS = {
|
|
2068
|
+
INK: "#000000",
|
|
2069
|
+
DARK: "#555555",
|
|
2070
|
+
MID: "#aaaaaa",
|
|
2071
|
+
PAPER: "#ffffff"
|
|
2072
|
+
};
|
|
2060
2073
|
var S52_DAY = {
|
|
2061
2074
|
// Depth
|
|
2062
2075
|
NODTA: "#a4a4a4",
|
|
@@ -2337,11 +2350,235 @@ var S52_NIGHT = {
|
|
|
2337
2350
|
RES02: "#383028",
|
|
2338
2351
|
RES03: "#383028"
|
|
2339
2352
|
};
|
|
2353
|
+
var S52_EINK_COLOR = {
|
|
2354
|
+
NODTA: "#b4b4b4",
|
|
2355
|
+
DEPIT: "#4f8f3a",
|
|
2356
|
+
DEPVS: "#74ade0",
|
|
2357
|
+
DEPMS: "#bad6ef",
|
|
2358
|
+
DEPMD: "#ffffff",
|
|
2359
|
+
DEPDW: "#ffffff",
|
|
2360
|
+
LANDA: "#f2e2b0",
|
|
2361
|
+
LANDF: "#c49a4a",
|
|
2362
|
+
CHBRN: "#8b5a2b",
|
|
2363
|
+
CHGRF: "#9a9a9a",
|
|
2364
|
+
CHGRD: "#444444",
|
|
2365
|
+
CHBLK: "#000000",
|
|
2366
|
+
CSTLN: "#000000",
|
|
2367
|
+
OUTLW: "#000000",
|
|
2368
|
+
BKAJ1: "#333333",
|
|
2369
|
+
TRFCD: "#c800c8",
|
|
2370
|
+
TRFCF: "#c800c8",
|
|
2371
|
+
RESBL: "#0050c8",
|
|
2372
|
+
APTS1: "#c800c8",
|
|
2373
|
+
DNGHL: "#e00000",
|
|
2374
|
+
ISHDG: "#e00000",
|
|
2375
|
+
LITRD: "#e00000",
|
|
2376
|
+
LITGN: "#00a000",
|
|
2377
|
+
LITYW: "#f0c000",
|
|
2378
|
+
LITWT: "#ffffff",
|
|
2379
|
+
LITBL: "#0050c8",
|
|
2380
|
+
LITOR: "#f07000",
|
|
2381
|
+
RADHI: "#00a000",
|
|
2382
|
+
RADLO: "#006000",
|
|
2383
|
+
PLRTE: "#e00000",
|
|
2384
|
+
ARPAT: "#008040",
|
|
2385
|
+
ISDNG: "#c800c8",
|
|
2386
|
+
CHRED: "#e00000",
|
|
2387
|
+
CHGRN: "#00a000",
|
|
2388
|
+
CHYLW: "#f0c000",
|
|
2389
|
+
CHMGD: "#c800c8",
|
|
2390
|
+
CHMGF: "#c800c8",
|
|
2391
|
+
CHWHT: "#ffffff",
|
|
2392
|
+
CHCOR: "#f07000",
|
|
2393
|
+
// Deeper-than-safety soundings: dark grey, the one secondary ink. Shoal
|
|
2394
|
+
// soundings are black — the louder numeral, as in every other table.
|
|
2395
|
+
SNDG1: "#555555",
|
|
2396
|
+
SNDG2: "#000000",
|
|
2397
|
+
DEPSC: "#000000",
|
|
2398
|
+
DEPCN: "#555555",
|
|
2399
|
+
UINFD: "#000000",
|
|
2400
|
+
UINFF: "#555555",
|
|
2401
|
+
UINFR: "#e00000",
|
|
2402
|
+
UINFG: "#00a000",
|
|
2403
|
+
UINFO: "#f07000",
|
|
2404
|
+
UINFB: "#0050c8",
|
|
2405
|
+
UINFM: "#c800c8",
|
|
2406
|
+
UIBCK: "#ffffff",
|
|
2407
|
+
UIBDR: "#555555",
|
|
2408
|
+
UIAFD: "#74ade0",
|
|
2409
|
+
UIAFF: "#c49a4a",
|
|
2410
|
+
PIPLN: "#008000",
|
|
2411
|
+
OUTLL: "#c49a4a",
|
|
2412
|
+
SCLBR: "#f07000",
|
|
2413
|
+
NINFO: "#f07000",
|
|
2414
|
+
ADINF: "#b08800",
|
|
2415
|
+
RESGR: "#555555",
|
|
2416
|
+
SHIPS: "#000000",
|
|
2417
|
+
PSTRK: "#000000",
|
|
2418
|
+
SYTRK: "#555555",
|
|
2419
|
+
APLRT: "#f07000",
|
|
2420
|
+
CURSR: "#f07000",
|
|
2421
|
+
BKAJ2: "#000000",
|
|
2422
|
+
RES01: "#808080",
|
|
2423
|
+
RES02: "#808080",
|
|
2424
|
+
RES03: "#808080"
|
|
2425
|
+
};
|
|
2426
|
+
var M = EINK_MONO_GREYS;
|
|
2427
|
+
var S52_EINK_MONO = {
|
|
2428
|
+
// No data is DARK, never the land tone: a no-data edge in the land tone
|
|
2429
|
+
// reads as a coastline (seen on the Boston render, 2026-10-05).
|
|
2430
|
+
NODTA: M.DARK,
|
|
2431
|
+
DEPIT: M.PAPER,
|
|
2432
|
+
DEPVS: M.PAPER,
|
|
2433
|
+
DEPMS: M.PAPER,
|
|
2434
|
+
DEPMD: M.PAPER,
|
|
2435
|
+
DEPDW: M.PAPER,
|
|
2436
|
+
LANDA: M.MID,
|
|
2437
|
+
LANDF: M.DARK,
|
|
2438
|
+
CHBRN: M.DARK,
|
|
2439
|
+
CHGRF: M.MID,
|
|
2440
|
+
CHGRD: M.DARK,
|
|
2441
|
+
CHBLK: M.INK,
|
|
2442
|
+
CSTLN: M.INK,
|
|
2443
|
+
OUTLW: M.INK,
|
|
2444
|
+
BKAJ1: M.DARK,
|
|
2445
|
+
TRFCD: M.INK,
|
|
2446
|
+
TRFCF: M.INK,
|
|
2447
|
+
RESBL: M.INK,
|
|
2448
|
+
APTS1: M.INK,
|
|
2449
|
+
DNGHL: M.INK,
|
|
2450
|
+
ISHDG: M.INK,
|
|
2451
|
+
LITRD: M.INK,
|
|
2452
|
+
LITGN: M.INK,
|
|
2453
|
+
LITYW: M.INK,
|
|
2454
|
+
LITWT: M.PAPER,
|
|
2455
|
+
LITBL: M.INK,
|
|
2456
|
+
LITOR: M.INK,
|
|
2457
|
+
RADHI: M.INK,
|
|
2458
|
+
RADLO: M.DARK,
|
|
2459
|
+
PLRTE: M.INK,
|
|
2460
|
+
ARPAT: M.INK,
|
|
2461
|
+
ISDNG: M.INK,
|
|
2462
|
+
CHRED: M.DARK,
|
|
2463
|
+
CHGRN: M.MID,
|
|
2464
|
+
CHYLW: M.MID,
|
|
2465
|
+
CHMGD: M.INK,
|
|
2466
|
+
CHMGF: M.INK,
|
|
2467
|
+
CHWHT: M.PAPER,
|
|
2468
|
+
CHCOR: M.MID,
|
|
2469
|
+
SNDG1: M.DARK,
|
|
2470
|
+
SNDG2: M.INK,
|
|
2471
|
+
DEPSC: M.INK,
|
|
2472
|
+
DEPCN: M.DARK,
|
|
2473
|
+
UINFD: M.INK,
|
|
2474
|
+
UINFF: M.DARK,
|
|
2475
|
+
UINFR: M.INK,
|
|
2476
|
+
UINFG: M.INK,
|
|
2477
|
+
UINFO: M.INK,
|
|
2478
|
+
UINFB: M.INK,
|
|
2479
|
+
UINFM: M.INK,
|
|
2480
|
+
UIBCK: M.PAPER,
|
|
2481
|
+
UIBDR: M.DARK,
|
|
2482
|
+
UIAFD: M.MID,
|
|
2483
|
+
UIAFF: M.MID,
|
|
2484
|
+
PIPLN: M.INK,
|
|
2485
|
+
OUTLL: M.DARK,
|
|
2486
|
+
SCLBR: M.INK,
|
|
2487
|
+
NINFO: M.INK,
|
|
2488
|
+
ADINF: M.DARK,
|
|
2489
|
+
RESGR: M.DARK,
|
|
2490
|
+
SHIPS: M.INK,
|
|
2491
|
+
PSTRK: M.INK,
|
|
2492
|
+
SYTRK: M.DARK,
|
|
2493
|
+
APLRT: M.INK,
|
|
2494
|
+
CURSR: M.INK,
|
|
2495
|
+
BKAJ2: M.INK,
|
|
2496
|
+
RES01: M.DARK,
|
|
2497
|
+
RES02: M.DARK,
|
|
2498
|
+
RES03: M.DARK
|
|
2499
|
+
};
|
|
2500
|
+
var N = { GROUND: M.INK, DIM: M.DARK, LINE: M.MID, BRIGHT: M.PAPER };
|
|
2501
|
+
var S52_EINK_NIGHT = {
|
|
2502
|
+
NODTA: N.GROUND,
|
|
2503
|
+
DEPIT: N.GROUND,
|
|
2504
|
+
DEPVS: N.GROUND,
|
|
2505
|
+
DEPMS: N.GROUND,
|
|
2506
|
+
DEPMD: N.GROUND,
|
|
2507
|
+
DEPDW: N.GROUND,
|
|
2508
|
+
LANDA: N.DIM,
|
|
2509
|
+
LANDF: N.LINE,
|
|
2510
|
+
CHBRN: N.LINE,
|
|
2511
|
+
CHGRF: N.DIM,
|
|
2512
|
+
CHGRD: N.LINE,
|
|
2513
|
+
CHBLK: N.LINE,
|
|
2514
|
+
CSTLN: N.LINE,
|
|
2515
|
+
OUTLW: N.LINE,
|
|
2516
|
+
BKAJ1: N.DIM,
|
|
2517
|
+
TRFCD: N.LINE,
|
|
2518
|
+
TRFCF: N.LINE,
|
|
2519
|
+
RESBL: N.LINE,
|
|
2520
|
+
APTS1: N.LINE,
|
|
2521
|
+
DNGHL: N.BRIGHT,
|
|
2522
|
+
ISHDG: N.BRIGHT,
|
|
2523
|
+
LITRD: N.BRIGHT,
|
|
2524
|
+
LITGN: N.BRIGHT,
|
|
2525
|
+
LITYW: N.BRIGHT,
|
|
2526
|
+
LITWT: N.BRIGHT,
|
|
2527
|
+
LITBL: N.BRIGHT,
|
|
2528
|
+
LITOR: N.BRIGHT,
|
|
2529
|
+
RADHI: N.LINE,
|
|
2530
|
+
RADLO: N.DIM,
|
|
2531
|
+
PLRTE: N.LINE,
|
|
2532
|
+
ARPAT: N.LINE,
|
|
2533
|
+
ISDNG: N.BRIGHT,
|
|
2534
|
+
// Mark bodies by tone, as in mono, so they stay apart from each other and
|
|
2535
|
+
// from the black water; shape still says which side.
|
|
2536
|
+
CHRED: N.DIM,
|
|
2537
|
+
CHGRN: N.LINE,
|
|
2538
|
+
CHYLW: N.LINE,
|
|
2539
|
+
CHMGD: N.LINE,
|
|
2540
|
+
CHMGF: N.LINE,
|
|
2541
|
+
CHWHT: N.BRIGHT,
|
|
2542
|
+
CHCOR: N.LINE,
|
|
2543
|
+
SNDG1: N.LINE,
|
|
2544
|
+
SNDG2: N.BRIGHT,
|
|
2545
|
+
DEPSC: N.BRIGHT,
|
|
2546
|
+
DEPCN: N.LINE,
|
|
2547
|
+
UINFD: N.LINE,
|
|
2548
|
+
UINFF: N.DIM,
|
|
2549
|
+
UINFR: N.BRIGHT,
|
|
2550
|
+
UINFG: N.LINE,
|
|
2551
|
+
UINFO: N.LINE,
|
|
2552
|
+
UINFB: N.LINE,
|
|
2553
|
+
UINFM: N.LINE,
|
|
2554
|
+
UIBCK: N.GROUND,
|
|
2555
|
+
UIBDR: N.DIM,
|
|
2556
|
+
UIAFD: N.DIM,
|
|
2557
|
+
UIAFF: N.DIM,
|
|
2558
|
+
PIPLN: N.LINE,
|
|
2559
|
+
OUTLL: N.DIM,
|
|
2560
|
+
SCLBR: N.LINE,
|
|
2561
|
+
NINFO: N.LINE,
|
|
2562
|
+
ADINF: N.DIM,
|
|
2563
|
+
RESGR: N.DIM,
|
|
2564
|
+
SHIPS: N.BRIGHT,
|
|
2565
|
+
PSTRK: N.LINE,
|
|
2566
|
+
SYTRK: N.DIM,
|
|
2567
|
+
APLRT: N.BRIGHT,
|
|
2568
|
+
CURSR: N.BRIGHT,
|
|
2569
|
+
BKAJ2: N.GROUND,
|
|
2570
|
+
RES01: N.DIM,
|
|
2571
|
+
RES02: N.DIM,
|
|
2572
|
+
RES03: N.DIM
|
|
2573
|
+
};
|
|
2340
2574
|
var S52_COLORS = S52_DAY;
|
|
2341
2575
|
var COLOR_TABLES = {
|
|
2342
2576
|
DAY: S52_DAY,
|
|
2343
2577
|
DUSK: S52_DUSK,
|
|
2344
|
-
NIGHT: S52_NIGHT
|
|
2578
|
+
NIGHT: S52_NIGHT,
|
|
2579
|
+
EINK_COLOR: S52_EINK_COLOR,
|
|
2580
|
+
EINK_MONO: S52_EINK_MONO,
|
|
2581
|
+
EINK_NIGHT: S52_EINK_NIGHT
|
|
2345
2582
|
};
|
|
2346
2583
|
function getColorTable(name) {
|
|
2347
2584
|
return COLOR_TABLES[name];
|
|
@@ -4988,6 +5225,254 @@ var InteractClient = class {
|
|
|
4988
5225
|
}
|
|
4989
5226
|
};
|
|
4990
5227
|
|
|
5228
|
+
// src/atlas/chrt-svgs-generated.ts
|
|
5229
|
+
var CHRT_GLYPH_SVGS = {
|
|
5230
|
+
"badge-radar": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="19" r="2.6" fill="#D200D2"/><path d="M9 19a7 7 0 0 1 14 0M5 19a11 11 0 0 1 22 0" stroke="#D200D2" stroke-width="2.4" fill="none" stroke-linecap="round" stroke-dasharray="4 3"/></svg>',
|
|
5231
|
+
"badge-sound": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="7" cy="16" r="2.2" fill="#D200D2"/><path d="M12 10a9 9 0 0 1 0 12M16.5 6.5a15 15 0 0 1 0 19M21 3a21 21 0 0 1 0 26" stroke="#D200D2" stroke-width="2.4" fill="none" stroke-linecap="round"/></svg>',
|
|
5232
|
+
"beacon-cairn": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="11" r="4" fill="#fff"/><circle cx="11.5" cy="19" r="4.6" fill="#fff"/><circle cx="20.5" cy="19" r="4.6" fill="#fff"/><path d="M7 28h18" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5233
|
+
"beacon-generic": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 25V12" stroke="#fff" stroke-width="2.6" stroke-linecap="round"/><path d="M16 4l6 8H10Z" fill="#fff"/><path d="M8 28h16M11 25h10" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5234
|
+
"beacon-lattice": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M11 25 13 6h6l2 19M12 20h8M12.6 13h6.8M11 25l9-12M21 25l-9-12" stroke="#fff" stroke-width="1.8" stroke-linecap="round" fill="none"/><path d="M8 28h16" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5235
|
+
"beacon-stake": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 25V6" stroke="#fff" stroke-width="2.8" stroke-linecap="round"/><path d="M9 28h14" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5236
|
+
"beacon-tower": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M12 6h8l1.6 19H10.4Z" fill="#fff"/><path d="M10 6h12" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/><path d="M8 28h16" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5237
|
+
"buoy-barrel": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><rect x="7" y="13" width="18" height="11" rx="5.5" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5238
|
+
"buoy-can": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M9 12h14v11a2 2 0 0 1-2 2H11a2 2 0 0 1-2-2Z" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5239
|
+
"buoy-conical": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 8 24.5 25H7.5Z" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5240
|
+
"buoy-pillar": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M13 6h6l1.4 19H11.6Z" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5241
|
+
"buoy-spar": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M14.5 5h3l1 20h-5Z" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5242
|
+
"buoy-spherical": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="17.5" r="8.5" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5243
|
+
"buoy-super": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M7 17h18l-2.5 8h-13Z" fill="#fff"/><path d="M16 17V8" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/><circle cx="16" cy="6.5" r="2" fill="#fff"/><path d="M5 28h22" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5244
|
+
"cardinal-e": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 1.5 20 6h-8Z" fill="#101418"/><path d="M16 11 12 6.5h8Z" fill="#101418"/><path d="M13 12h6l1 13H12Z" fill="#FFC805"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5245
|
+
"cardinal-n": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 1.5 20 6h-8Z" fill="#101418"/><path d="M16 6.5 20 11h-8Z" fill="#101418"/><path d="M13 12h6l1 13H12Z" fill="#FFC805"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5246
|
+
"cardinal-s": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 11 12 6.5h8Z" fill="#101418"/><path d="M16 6 12 1.5h8Z" fill="#101418"/><path d="M13 12h6l1 13H12Z" fill="#FFC805"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5247
|
+
"cardinal-w": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 6 12 1.5h8Z" fill="#101418"/><path d="M16 6.5 20 11h-8Z" fill="#101418"/><path d="M13 12h6l1 13H12Z" fill="#FFC805"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5248
|
+
"daymark-square": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><rect x="6" y="6" width="20" height="20" rx="1.5" fill="#fff"/></svg>',
|
|
5249
|
+
"daymark-triangle": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 5 28 26H4Z" fill="#fff"/></svg>',
|
|
5250
|
+
"eink-danger": '<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8"><path d="M-2 2 L2 -2 M0 8 L8 0 M6 10 L10 6" stroke="#000000" stroke-width="1" fill="none"/><path d="M-2 6 L2 10 M0 0 L8 8 M6 -2 L10 2" stroke="#000000" stroke-width="1" fill="none"/></svg>',
|
|
5251
|
+
"eink-dots": '<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10"><circle cx="2.5" cy="2.5" r="0.9" fill="#000000"/><circle cx="7.5" cy="7.5" r="0.9" fill="#000000"/></svg>',
|
|
5252
|
+
"eink-hatch": '<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8"><path d="M-2 2 L2 -2 M0 8 L8 0 M6 10 L10 6" stroke="#000000" stroke-width="0.9" fill="none"/></svg>',
|
|
5253
|
+
"hatch-nocoverage": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M-3 9 L9 -3 M-3 21 L21 -3 M3 27 L27 3 M15 27 L27 15" stroke="#8A97A0" stroke-width="0.8" fill="none"/><path d="M-3 15 L15 33 M-3 3 L21 27 M3 -3 L27 21 M15 -3 L27 9" stroke="#8A97A0" stroke-width="0.8" fill="none"/></svg>',
|
|
5254
|
+
"hatch-uncharted": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M-3 9 L9 -3 M-3 21 L21 -3 M3 27 L27 3 M15 27 L27 15" stroke="#5B7383" stroke-width="0.65" fill="none"/></svg>',
|
|
5255
|
+
"isolated-danger": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="3.5" r="2.4" fill="#101418"/><circle cx="16" cy="9.5" r="2.4" fill="#101418"/><path d="M13 13h6l1 12H12Z" fill="#101418"/><rect x="12.4" y="17.5" width="7.2" height="3.4" fill="#E5484D"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5256
|
+
"light-flare": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="11" cy="11" r="3.2" fill="#fff"/><path d="M13.4 13.4 24 19.5a2.6 2.6 0 0 1-4.5 4.5L13.4 13.4Z" fill="#fff"/></svg>',
|
|
5257
|
+
"lightship": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M6 20l3-5h14l3 5-3.5 4h-13Z" fill="#fff"/><path d="M16 15V8" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/><circle cx="16" cy="6" r="2.2" fill="#fff"/><path d="M5 28h22" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
5258
|
+
"safe-water": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="6" r="2.4" fill="#E5484D"/><circle cx="16" cy="17.5" r="8" fill="#F8FAFC"/><path d="M12.2 10.5a8 8 0 0 0 0 14M19.8 10.5a8 8 0 0 1 0 14" stroke="#E5484D" stroke-width="3" fill="none"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>'
|
|
5259
|
+
};
|
|
5260
|
+
|
|
5261
|
+
// src/atlas/s52-pattern.ts
|
|
5262
|
+
var S52_PATTERN_SPRITE_PREFIX = "AP:";
|
|
5263
|
+
function patternSpriteId(patternName) {
|
|
5264
|
+
return `${S52_PATTERN_SPRITE_PREFIX}${patternName}`;
|
|
5265
|
+
}
|
|
5266
|
+
|
|
5267
|
+
// src/atlas/s52-conditional.ts
|
|
5268
|
+
var DEFAULT_SAFETY_CONTOUR_M = 10;
|
|
5269
|
+
var DEPARE_DEEP_CUT_M = 18.2;
|
|
5270
|
+
var DEPARE_SHALLOW_CUT_M = 2;
|
|
5271
|
+
function effectiveSafetyContour(safetyContourM) {
|
|
5272
|
+
if (!Number.isFinite(safetyContourM)) return DEFAULT_SAFETY_CONTOUR_M;
|
|
5273
|
+
return Math.min(Math.max(safetyContourM, DEPARE_SHALLOW_CUT_M), DEPARE_DEEP_CUT_M);
|
|
5274
|
+
}
|
|
5275
|
+
function depareColor(props, ct = "DAY", safetyContourM = DEFAULT_SAFETY_CONTOUR_M) {
|
|
5276
|
+
const drval1 = Number(props.DRVAL1 ?? props.drval1 ?? -1);
|
|
5277
|
+
const drval2 = Number(props.DRVAL2 ?? props.drval2 ?? drval1);
|
|
5278
|
+
const safety = effectiveSafetyContour(safetyContourM);
|
|
5279
|
+
if (drval1 < 0 && drval2 <= 0) return resolveColor("DEPIT", ct);
|
|
5280
|
+
if (drval1 < DEPARE_SHALLOW_CUT_M) return resolveColor("DEPVS", ct);
|
|
5281
|
+
if (drval1 < safety) return resolveColor("DEPMS", ct);
|
|
5282
|
+
if (drval1 < DEPARE_DEEP_CUT_M) return resolveColor("DEPMD", ct);
|
|
5283
|
+
return resolveColor("DEPDW", ct);
|
|
5284
|
+
}
|
|
5285
|
+
var DEPARE_FILL_BRANCH_TOKENS = ["DEPIT", "DEPVS", "DEPMS", "DEPMD"];
|
|
5286
|
+
var DEPARE_FILL_FALLBACK_TOKEN = "DEPDW";
|
|
5287
|
+
function depareFillExpression(ct = "DAY", safetyContourM = DEFAULT_SAFETY_CONTOUR_M) {
|
|
5288
|
+
const safety = effectiveSafetyContour(safetyContourM);
|
|
5289
|
+
const [it, vs, ms, md] = DEPARE_FILL_BRANCH_TOKENS;
|
|
5290
|
+
return [
|
|
5291
|
+
"case",
|
|
5292
|
+
[
|
|
5293
|
+
"all",
|
|
5294
|
+
["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], 0],
|
|
5295
|
+
["<=", ["coalesce", ["get", "DRVAL2"], ["get", "drval2"], 0], 0]
|
|
5296
|
+
],
|
|
5297
|
+
resolveColor(it, ct),
|
|
5298
|
+
["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], DEPARE_SHALLOW_CUT_M],
|
|
5299
|
+
resolveColor(vs, ct),
|
|
5300
|
+
["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], safety],
|
|
5301
|
+
resolveColor(ms, ct),
|
|
5302
|
+
["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], DEPARE_DEEP_CUT_M],
|
|
5303
|
+
resolveColor(md, ct),
|
|
5304
|
+
resolveColor(DEPARE_FILL_FALLBACK_TOKEN, ct)
|
|
5305
|
+
];
|
|
5306
|
+
}
|
|
5307
|
+
function listAttrString(attr) {
|
|
5308
|
+
return ["to-string", ["coalesce", ["get", attr], ["get", attr.toLowerCase()], ""]];
|
|
5309
|
+
}
|
|
5310
|
+
function listAttrCase(attr, cases, fallback) {
|
|
5311
|
+
const attrStr = listAttrString(attr);
|
|
5312
|
+
const expr = ["case"];
|
|
5313
|
+
for (const [code, value] of cases) {
|
|
5314
|
+
expr.push([">=", ["index-of", `"${code}"`, attrStr], 0], value);
|
|
5315
|
+
}
|
|
5316
|
+
for (const [code, value] of cases) {
|
|
5317
|
+
expr.push(["==", attrStr, code], value);
|
|
5318
|
+
}
|
|
5319
|
+
for (const [code, value] of cases) {
|
|
5320
|
+
expr.push(["==", attrStr, `[${code}]`], value);
|
|
5321
|
+
}
|
|
5322
|
+
expr.push(fallback);
|
|
5323
|
+
return expr;
|
|
5324
|
+
}
|
|
5325
|
+
function listAttrHas(attr, codes) {
|
|
5326
|
+
const attrStr = listAttrString(attr);
|
|
5327
|
+
const clauses = [];
|
|
5328
|
+
for (const code of codes) {
|
|
5329
|
+
clauses.push([">=", ["index-of", `"${code}"`, attrStr], 0]);
|
|
5330
|
+
clauses.push(["==", attrStr, code]);
|
|
5331
|
+
clauses.push(["==", attrStr, `[${code}]`]);
|
|
5332
|
+
}
|
|
5333
|
+
return ["any", ...clauses];
|
|
5334
|
+
}
|
|
5335
|
+
function colourCodeCase(cases, fallback) {
|
|
5336
|
+
return listAttrCase("COLOUR", cases, fallback);
|
|
5337
|
+
}
|
|
5338
|
+
function lightColor(props, ct = "DAY") {
|
|
5339
|
+
const raw = props.COLOUR ?? props.colour;
|
|
5340
|
+
const code = Array.isArray(raw) ? Number(raw[0]) : typeof raw === "string" && raw.startsWith("[") ? Number(JSON.parse(raw)[0]) : Number(raw ?? 0);
|
|
5341
|
+
switch (code) {
|
|
5342
|
+
case 1:
|
|
5343
|
+
return resolveColor("LITWT", ct);
|
|
5344
|
+
case 3:
|
|
5345
|
+
return resolveColor("LITRD", ct);
|
|
5346
|
+
case 4:
|
|
5347
|
+
return resolveColor("LITGN", ct);
|
|
5348
|
+
case 5:
|
|
5349
|
+
return resolveColor("LITBL", ct);
|
|
5350
|
+
case 6:
|
|
5351
|
+
return resolveColor("LITYW", ct);
|
|
5352
|
+
case 11:
|
|
5353
|
+
return resolveColor("LITOR", ct);
|
|
5354
|
+
default:
|
|
5355
|
+
return resolveColor("LITYW", ct);
|
|
5356
|
+
}
|
|
5357
|
+
}
|
|
5358
|
+
function lightFillExpression(ct = "DAY") {
|
|
5359
|
+
return colourCodeCase(
|
|
5360
|
+
[
|
|
5361
|
+
["3", resolveColor("LITRD", ct)],
|
|
5362
|
+
["4", resolveColor("LITGN", ct)],
|
|
5363
|
+
["6", resolveColor("LITYW", ct)],
|
|
5364
|
+
["11", resolveColor("LITOR", ct)],
|
|
5365
|
+
["5", resolveColor("LITBL", ct)],
|
|
5366
|
+
["1", resolveColor("LITWT", ct)]
|
|
5367
|
+
],
|
|
5368
|
+
resolveColor("LITYW", ct)
|
|
5369
|
+
);
|
|
5370
|
+
}
|
|
5371
|
+
function lateralColor(props, ct = "DAY") {
|
|
5372
|
+
const catlam = Number(props.CATLAM ?? props.catlam ?? 0);
|
|
5373
|
+
if (catlam === 1) return resolveColor("LITRD", ct);
|
|
5374
|
+
if (catlam === 2) return resolveColor("LITGN", ct);
|
|
5375
|
+
return resolveColor("LITYW", ct);
|
|
5376
|
+
}
|
|
5377
|
+
function lateralFillExpression(ct = "DAY") {
|
|
5378
|
+
return [
|
|
5379
|
+
"match",
|
|
5380
|
+
["coalesce", ["get", "CATLAM"], ["get", "catlam"], 0],
|
|
5381
|
+
1,
|
|
5382
|
+
resolveColor("LITRD", ct),
|
|
5383
|
+
2,
|
|
5384
|
+
resolveColor("LITGN", ct),
|
|
5385
|
+
resolveColor("LITYW", ct)
|
|
5386
|
+
];
|
|
5387
|
+
}
|
|
5388
|
+
function hazardColor(props, ct = "DAY") {
|
|
5389
|
+
const watlev = Number(props.WATLEV ?? props.watlev ?? 0);
|
|
5390
|
+
const valsou = props.VALSOU ?? props.valsou;
|
|
5391
|
+
if (watlev === 1 || watlev === 2) return resolveColor("DNGHL", ct);
|
|
5392
|
+
if (valsou != null && Number(valsou) < 2) return resolveColor("DNGHL", ct);
|
|
5393
|
+
return resolveColor("RESBL", ct);
|
|
5394
|
+
}
|
|
5395
|
+
function hazardFillExpression(ct = "DAY") {
|
|
5396
|
+
return [
|
|
5397
|
+
"case",
|
|
5398
|
+
[
|
|
5399
|
+
"any",
|
|
5400
|
+
["==", ["coalesce", ["get", "WATLEV"], ["get", "watlev"], 0], 1],
|
|
5401
|
+
["==", ["coalesce", ["get", "WATLEV"], ["get", "watlev"], 0], 2]
|
|
5402
|
+
],
|
|
5403
|
+
resolveColor("DNGHL", ct),
|
|
5404
|
+
[
|
|
5405
|
+
"all",
|
|
5406
|
+
["has", "VALSOU"],
|
|
5407
|
+
["<", ["get", "VALSOU"], 2]
|
|
5408
|
+
],
|
|
5409
|
+
resolveColor("DNGHL", ct),
|
|
5410
|
+
resolveColor("RESBL", ct)
|
|
5411
|
+
];
|
|
5412
|
+
}
|
|
5413
|
+
function vegatnPatternExpression() {
|
|
5414
|
+
return [
|
|
5415
|
+
"match",
|
|
5416
|
+
["coalesce", ["get", "CATVEG"], ["get", "catveg"], 0],
|
|
5417
|
+
1,
|
|
5418
|
+
patternSpriteId("VEGATN03"),
|
|
5419
|
+
// grass
|
|
5420
|
+
3,
|
|
5421
|
+
patternSpriteId("VEGATN03"),
|
|
5422
|
+
// bush
|
|
5423
|
+
4,
|
|
5424
|
+
patternSpriteId("VEGATN04"),
|
|
5425
|
+
// deciduous wood
|
|
5426
|
+
5,
|
|
5427
|
+
patternSpriteId("VEGATN04"),
|
|
5428
|
+
// coniferous wood
|
|
5429
|
+
6,
|
|
5430
|
+
patternSpriteId("VEGATN04"),
|
|
5431
|
+
// wood (mixed)
|
|
5432
|
+
7,
|
|
5433
|
+
patternSpriteId("MARSHES1"),
|
|
5434
|
+
// mangroves
|
|
5435
|
+
10,
|
|
5436
|
+
patternSpriteId("VEGATN03"),
|
|
5437
|
+
// scrub
|
|
5438
|
+
11,
|
|
5439
|
+
patternSpriteId("VEGATN04"),
|
|
5440
|
+
// tree
|
|
5441
|
+
12,
|
|
5442
|
+
patternSpriteId("VEGATN04"),
|
|
5443
|
+
// evergreen
|
|
5444
|
+
16,
|
|
5445
|
+
patternSpriteId("MARSHES1"),
|
|
5446
|
+
// swamp
|
|
5447
|
+
17,
|
|
5448
|
+
patternSpriteId("MARSHES1"),
|
|
5449
|
+
// marsh
|
|
5450
|
+
21,
|
|
5451
|
+
patternSpriteId("VEGATN04"),
|
|
5452
|
+
// savannah
|
|
5453
|
+
patternSpriteId("VEGATN03")
|
|
5454
|
+
// default: grass pattern
|
|
5455
|
+
];
|
|
5456
|
+
}
|
|
5457
|
+
function daymarkColor(props, ct = "DAY") {
|
|
5458
|
+
const raw = props.COLOUR ?? props.colour;
|
|
5459
|
+
const code = Array.isArray(raw) ? Number(raw[0]) : typeof raw === "string" && raw.startsWith("[") ? Number(JSON.parse(raw)[0]) : Number(raw ?? 0);
|
|
5460
|
+
switch (code) {
|
|
5461
|
+
case 1:
|
|
5462
|
+
return resolveColor("LITWT", ct);
|
|
5463
|
+
case 3:
|
|
5464
|
+
return resolveColor("LITRD", ct);
|
|
5465
|
+
case 4:
|
|
5466
|
+
return resolveColor("LITGN", ct);
|
|
5467
|
+
case 6:
|
|
5468
|
+
return resolveColor("LITYW", ct);
|
|
5469
|
+
case 11:
|
|
5470
|
+
return resolveColor("LITOR", ct);
|
|
5471
|
+
default:
|
|
5472
|
+
return resolveColor("LITGN", ct);
|
|
5473
|
+
}
|
|
5474
|
+
}
|
|
5475
|
+
|
|
4991
5476
|
// src/atlas/palette-light.ts
|
|
4992
5477
|
var HEX6 = /^#?([0-9a-f]{6})$/i;
|
|
4993
5478
|
function channels(hex) {
|
|
@@ -5026,8 +5511,966 @@ function capLuminance(hex, ceiling) {
|
|
|
5026
5511
|
}
|
|
5027
5512
|
var NIGHT_INK = S52_NIGHT.CHBLK;
|
|
5028
5513
|
var NIGHT_MUTED_INK = scaleLinearLight(S52_NIGHT.CHBLK, 0.43);
|
|
5029
|
-
|
|
5030
|
-
|
|
5514
|
+
function einkMonoGrey(hex) {
|
|
5515
|
+
const l = relativeLuminance(hex);
|
|
5516
|
+
const g2 = EINK_MONO_GREYS;
|
|
5517
|
+
const steps = [g2.INK, g2.DARK, g2.MID, g2.PAPER].map((c) => [c, relativeLuminance(c)]);
|
|
5518
|
+
let best = steps[0];
|
|
5519
|
+
for (const step of steps) if (Math.abs(step[1] - l) < Math.abs(best[1] - l)) best = step;
|
|
5520
|
+
return best[0];
|
|
5521
|
+
}
|
|
5522
|
+
function einkNightGrey(hex) {
|
|
5523
|
+
const l = relativeLuminance(hex);
|
|
5524
|
+
const g2 = EINK_MONO_GREYS;
|
|
5525
|
+
const steps = [g2.DARK, g2.MID, g2.PAPER].map((c) => [c, relativeLuminance(c)]);
|
|
5526
|
+
let best = steps[0];
|
|
5527
|
+
for (const step of steps) if (Math.abs(step[1] - l) < Math.abs(best[1] - l)) best = step;
|
|
5528
|
+
return best[0];
|
|
5529
|
+
}
|
|
5530
|
+
|
|
5531
|
+
// src/atlas/chrt-style.ts
|
|
5532
|
+
var CHRT_ICON_PREFIX = "chrt:";
|
|
5533
|
+
var CHRT_SDF_GLYPHS = /* @__PURE__ */ new Set([
|
|
5534
|
+
"buoy-can",
|
|
5535
|
+
"buoy-conical",
|
|
5536
|
+
"buoy-spherical",
|
|
5537
|
+
"buoy-pillar",
|
|
5538
|
+
"buoy-spar",
|
|
5539
|
+
"buoy-barrel",
|
|
5540
|
+
"buoy-super",
|
|
5541
|
+
"beacon-generic",
|
|
5542
|
+
"beacon-tower",
|
|
5543
|
+
"beacon-lattice",
|
|
5544
|
+
"beacon-stake",
|
|
5545
|
+
"beacon-cairn",
|
|
5546
|
+
"light-flare",
|
|
5547
|
+
"lightship",
|
|
5548
|
+
"daymark-triangle",
|
|
5549
|
+
"daymark-square"
|
|
5550
|
+
]);
|
|
5551
|
+
var CHRT_GLYPH_NAMES = new Set(Object.keys(CHRT_GLYPH_SVGS));
|
|
5552
|
+
var CHRT_ATON_COLORS = {
|
|
5553
|
+
"1": "#F8FAFC",
|
|
5554
|
+
// white
|
|
5555
|
+
"2": "#101418",
|
|
5556
|
+
// black
|
|
5557
|
+
"3": "#E5484D",
|
|
5558
|
+
// red
|
|
5559
|
+
"4": "#30A46C",
|
|
5560
|
+
// green
|
|
5561
|
+
"5": "#3E63DD",
|
|
5562
|
+
// blue
|
|
5563
|
+
"6": "#FFC805",
|
|
5564
|
+
// yellow
|
|
5565
|
+
"7": "#8B9298",
|
|
5566
|
+
// grey
|
|
5567
|
+
"8": "#A66B3A",
|
|
5568
|
+
// brown
|
|
5569
|
+
"9": "#FFB224",
|
|
5570
|
+
// amber
|
|
5571
|
+
"10": "#7E4CCB",
|
|
5572
|
+
// violet
|
|
5573
|
+
"11": "#F76B15",
|
|
5574
|
+
// orange
|
|
5575
|
+
"12": "#D671C1"
|
|
5576
|
+
// pink (magenta-ish)
|
|
5577
|
+
};
|
|
5578
|
+
var CHRT_UNKNOWN_TINT = "#8B9298";
|
|
5579
|
+
var HOUSE_BLACK = "#101418";
|
|
5580
|
+
function chrtHouseColor(dayHex, palette = "DAY") {
|
|
5581
|
+
if (palette === "DAY" || palette === "EINK_COLOR") return dayHex;
|
|
5582
|
+
if (palette === "EINK_MONO") return einkMonoGrey(dayHex);
|
|
5583
|
+
if (palette === "EINK_NIGHT") return dayHex.toLowerCase() === HOUSE_BLACK.toLowerCase() || dayHex.toLowerCase() === "#000000" ? "#aaaaaa" : einkNightGrey(dayHex);
|
|
5584
|
+
const isBlack = dayHex.toLowerCase() === HOUSE_BLACK.toLowerCase();
|
|
5585
|
+
if (palette === "DUSK") {
|
|
5586
|
+
return isBlack ? dayHex : capLuminance(dayHex, relativeLuminance(resolveColor("CHBLK", "DUSK")));
|
|
5587
|
+
}
|
|
5588
|
+
return isBlack ? NIGHT_INK : capLuminance(dayHex, relativeLuminance(NIGHT_MUTED_INK));
|
|
5589
|
+
}
|
|
5590
|
+
function themeChrtGlyph(svg3, palette = "DAY") {
|
|
5591
|
+
if (palette === "DAY" || palette === "EINK_COLOR") return svg3;
|
|
5592
|
+
return svg3.replace(
|
|
5593
|
+
/(fill|stroke)="(#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6})"/g,
|
|
5594
|
+
(_m, attr, hex) => {
|
|
5595
|
+
const six = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
|
|
5596
|
+
return `${attr}="${chrtHouseColor(six, palette)}"`;
|
|
5597
|
+
}
|
|
5598
|
+
);
|
|
5599
|
+
}
|
|
5600
|
+
function chrtAtonTintExpression(palette = "DAY") {
|
|
5601
|
+
const c = (code) => chrtHouseColor(CHRT_ATON_COLORS[code], palette);
|
|
5602
|
+
return colourCodeCase(
|
|
5603
|
+
[
|
|
5604
|
+
["3", c("3")],
|
|
5605
|
+
["4", c("4")],
|
|
5606
|
+
["6", c("6")],
|
|
5607
|
+
["11", c("11")],
|
|
5608
|
+
["9", c("9")],
|
|
5609
|
+
["5", c("5")],
|
|
5610
|
+
["1", c("1")],
|
|
5611
|
+
["2", c("2")],
|
|
5612
|
+
["8", c("8")],
|
|
5613
|
+
["10", c("10")],
|
|
5614
|
+
["12", c("12")],
|
|
5615
|
+
["7", c("7")]
|
|
5616
|
+
],
|
|
5617
|
+
chrtHouseColor(CHRT_UNKNOWN_TINT, palette)
|
|
5618
|
+
);
|
|
5619
|
+
}
|
|
5620
|
+
function chrtLightTintExpression(palette = "DAY") {
|
|
5621
|
+
const c = (code) => chrtHouseColor(CHRT_ATON_COLORS[code], palette);
|
|
5622
|
+
return colourCodeCase(
|
|
5623
|
+
[
|
|
5624
|
+
["3", c("3")],
|
|
5625
|
+
["4", c("4")],
|
|
5626
|
+
["6", c("6")],
|
|
5627
|
+
["11", c("11")],
|
|
5628
|
+
["9", c("9")],
|
|
5629
|
+
["5", c("5")],
|
|
5630
|
+
["1", c("1")]
|
|
5631
|
+
],
|
|
5632
|
+
c("1")
|
|
5633
|
+
);
|
|
5634
|
+
}
|
|
5635
|
+
function scalar(attr) {
|
|
5636
|
+
return ["coalesce", ["get", attr], ["get", attr.toLowerCase()], 0];
|
|
5637
|
+
}
|
|
5638
|
+
var g = (name) => `${CHRT_ICON_PREFIX}${name}`;
|
|
5639
|
+
function buoyBodyExpression() {
|
|
5640
|
+
return [
|
|
5641
|
+
"match",
|
|
5642
|
+
scalar("BOYSHP"),
|
|
5643
|
+
1,
|
|
5644
|
+
g("buoy-conical"),
|
|
5645
|
+
2,
|
|
5646
|
+
g("buoy-can"),
|
|
5647
|
+
3,
|
|
5648
|
+
g("buoy-spherical"),
|
|
5649
|
+
4,
|
|
5650
|
+
g("buoy-pillar"),
|
|
5651
|
+
5,
|
|
5652
|
+
g("buoy-spar"),
|
|
5653
|
+
6,
|
|
5654
|
+
g("buoy-barrel"),
|
|
5655
|
+
7,
|
|
5656
|
+
g("buoy-super"),
|
|
5657
|
+
8,
|
|
5658
|
+
g("buoy-super"),
|
|
5659
|
+
g("buoy-pillar")
|
|
5660
|
+
];
|
|
5661
|
+
}
|
|
5662
|
+
function beaconBodyExpression() {
|
|
5663
|
+
return [
|
|
5664
|
+
"match",
|
|
5665
|
+
scalar("BCNSHP"),
|
|
5666
|
+
1,
|
|
5667
|
+
g("beacon-stake"),
|
|
5668
|
+
2,
|
|
5669
|
+
g("beacon-stake"),
|
|
5670
|
+
3,
|
|
5671
|
+
g("beacon-tower"),
|
|
5672
|
+
4,
|
|
5673
|
+
g("beacon-lattice"),
|
|
5674
|
+
5,
|
|
5675
|
+
g("beacon-stake"),
|
|
5676
|
+
6,
|
|
5677
|
+
g("beacon-cairn"),
|
|
5678
|
+
g("beacon-generic")
|
|
5679
|
+
];
|
|
5680
|
+
}
|
|
5681
|
+
function cardinalExpression() {
|
|
5682
|
+
return [
|
|
5683
|
+
"match",
|
|
5684
|
+
scalar("CATCAM"),
|
|
5685
|
+
1,
|
|
5686
|
+
g("cardinal-n"),
|
|
5687
|
+
2,
|
|
5688
|
+
g("cardinal-e"),
|
|
5689
|
+
3,
|
|
5690
|
+
g("cardinal-s"),
|
|
5691
|
+
4,
|
|
5692
|
+
g("cardinal-w"),
|
|
5693
|
+
g("cardinal-n")
|
|
5694
|
+
];
|
|
5695
|
+
}
|
|
5696
|
+
var CHRT_ICON_EXPRESSIONS = {
|
|
5697
|
+
BOYLAT: buoyBodyExpression,
|
|
5698
|
+
BOYSPP: buoyBodyExpression,
|
|
5699
|
+
BOYINB: buoyBodyExpression,
|
|
5700
|
+
BOYCAR: cardinalExpression,
|
|
5701
|
+
BOYISD: () => g("isolated-danger"),
|
|
5702
|
+
BOYSAW: () => g("safe-water"),
|
|
5703
|
+
BCNLAT: beaconBodyExpression,
|
|
5704
|
+
BCNSPP: beaconBodyExpression,
|
|
5705
|
+
BCNCAR: cardinalExpression,
|
|
5706
|
+
BCNISD: () => g("isolated-danger"),
|
|
5707
|
+
BCNSAW: () => g("safe-water"),
|
|
5708
|
+
LIGHTS: () => g("light-flare"),
|
|
5709
|
+
LITFLT: () => g("lightship"),
|
|
5710
|
+
LITVES: () => g("lightship"),
|
|
5711
|
+
FOGSIG: () => g("badge-sound"),
|
|
5712
|
+
RTPBCN: () => g("badge-radar"),
|
|
5713
|
+
RDOSTA: () => g("badge-radar"),
|
|
5714
|
+
DAYMAR: () => [
|
|
5715
|
+
"match",
|
|
5716
|
+
scalar("TOPSHP"),
|
|
5717
|
+
1,
|
|
5718
|
+
g("daymark-triangle"),
|
|
5719
|
+
2,
|
|
5720
|
+
g("daymark-triangle"),
|
|
5721
|
+
5,
|
|
5722
|
+
g("daymark-triangle"),
|
|
5723
|
+
g("daymark-square")
|
|
5724
|
+
]
|
|
5725
|
+
};
|
|
5726
|
+
var TINTED_CLASSES = /* @__PURE__ */ new Set([
|
|
5727
|
+
"BOYLAT",
|
|
5728
|
+
"BOYSPP",
|
|
5729
|
+
"BOYINB",
|
|
5730
|
+
"BCNLAT",
|
|
5731
|
+
"BCNSPP",
|
|
5732
|
+
"DAYMAR"
|
|
5733
|
+
]);
|
|
5734
|
+
var CHRT_HALO = { color: HOUSE_BLACK, width: 1 };
|
|
5735
|
+
var CHRT_LINE_DASH = {
|
|
5736
|
+
CBLSUB: { color: "CHMGD", width: 0.8, dash: [6, 3] },
|
|
5737
|
+
PIPSOL: { color: "PIPLN", width: 0.8, dash: [6, 3] }
|
|
5738
|
+
};
|
|
5739
|
+
function applyChrtSymbolSet(style, palette = "DAY") {
|
|
5740
|
+
for (const layer of style.layers) {
|
|
5741
|
+
if (layer.type === "line") {
|
|
5742
|
+
const cls = layer.metadata?.["s52:objectClass"];
|
|
5743
|
+
const dash = cls ? CHRT_LINE_DASH[cls] : void 0;
|
|
5744
|
+
const paint2 = layer.paint ?? {};
|
|
5745
|
+
if (dash && paint2["line-pattern"] != null) {
|
|
5746
|
+
delete paint2["line-pattern"];
|
|
5747
|
+
paint2["line-color"] = resolveColor(dash.color, palette);
|
|
5748
|
+
paint2["line-width"] = dash.width;
|
|
5749
|
+
paint2["line-dasharray"] = dash.dash;
|
|
5750
|
+
layer.paint = paint2;
|
|
5751
|
+
}
|
|
5752
|
+
continue;
|
|
5753
|
+
}
|
|
5754
|
+
if (layer.type !== "symbol") continue;
|
|
5755
|
+
const objectClass2 = layer.metadata?.["s52:objectClass"];
|
|
5756
|
+
if (!objectClass2 || !CHRT_ICON_EXPRESSIONS[objectClass2]) continue;
|
|
5757
|
+
const layout = layer.layout;
|
|
5758
|
+
if (!layout || layout["icon-image"] == null) continue;
|
|
5759
|
+
layout["icon-image"] = CHRT_ICON_EXPRESSIONS[objectClass2]();
|
|
5760
|
+
const paint = layer.paint ?? {};
|
|
5761
|
+
const haloColor = palette === "EINK_MONO" ? chrtHouseColor(HOUSE_BLACK, palette) : palette === "EINK_NIGHT" ? "#000000" : CHRT_HALO.color;
|
|
5762
|
+
if (TINTED_CLASSES.has(objectClass2)) {
|
|
5763
|
+
paint["icon-color"] = chrtAtonTintExpression(palette);
|
|
5764
|
+
paint["icon-halo-color"] = haloColor;
|
|
5765
|
+
paint["icon-halo-width"] = CHRT_HALO.width;
|
|
5766
|
+
} else if (objectClass2 === "LIGHTS") {
|
|
5767
|
+
paint["icon-color"] = chrtLightTintExpression(palette);
|
|
5768
|
+
paint["icon-halo-color"] = haloColor;
|
|
5769
|
+
paint["icon-halo-width"] = CHRT_HALO.width;
|
|
5770
|
+
}
|
|
5771
|
+
layer.paint = paint;
|
|
5772
|
+
}
|
|
5773
|
+
const metadata = style.metadata;
|
|
5774
|
+
metadata["chrt:symbol-set"] = "chrt";
|
|
5775
|
+
return style;
|
|
5776
|
+
}
|
|
5777
|
+
|
|
5778
|
+
// src/atlas/base-layers.ts
|
|
5779
|
+
var NOCOVERAGE_PATTERN = "chrt:hatch-nocoverage";
|
|
5780
|
+
var UNCHARTED_PATTERN = "chrt:hatch-uncharted";
|
|
5781
|
+
function inlandWaterColor(palette) {
|
|
5782
|
+
return (BASE_THEMES[palette] ?? BASE_THEMES.DAY).inlandWater;
|
|
5783
|
+
}
|
|
5784
|
+
var BASE_THEMES = {
|
|
5785
|
+
DAY: {
|
|
5786
|
+
// ── `earth` is the jurisdiction tan DIMMED (~0.55), not a blue-grey ──
|
|
5787
|
+
// Outside the jurisdiction the map still owes the reader "what is land".
|
|
5788
|
+
// State 3 in the header is "the geography, under a crosshatch", and until
|
|
5789
|
+
// 2026-08-31 that geography was unreadable: earth #2A3439 against sea
|
|
5790
|
+
// #1B2328 measured 1.25:1, so Hispaniola showed charted boxes with tan
|
|
5791
|
+
// land inside and nothing recognisable around them (owner report: "no
|
|
5792
|
+
// land painting down near the DR at some zooms"). Land is warm and sea is
|
|
5793
|
+
// cool because that is what land and sea are; dimming the JURISDICTION
|
|
5794
|
+
// tan rather than inventing a colour says the true thing — this is the
|
|
5795
|
+
// same land, we simply do not carry charts for it. Held against BOTH
|
|
5796
|
+
// neighbours: legible over sea, and never mistakable for the full tan of
|
|
5797
|
+
// a country we do carry. DAY 3.59:1 vs sea, 3.17:1 vs tan.
|
|
5798
|
+
earth: "#807761",
|
|
5799
|
+
water: "#1B2328",
|
|
5800
|
+
river: "#24313A",
|
|
5801
|
+
boundary: "#4A575E",
|
|
5802
|
+
jurisdiction: "#D4C69D",
|
|
5803
|
+
// CHRTland's own tan — one land colour
|
|
5804
|
+
inlandWater: "#B9CFDD",
|
|
5805
|
+
// muted, unmistakably not a charted blue
|
|
5806
|
+
// The uncharted hatch's stripe, held to 2.3:1 against `inlandWater` in
|
|
5807
|
+
// every palette (`inland-hatch-contrast.test.ts`) — the hatch says "we have
|
|
5808
|
+
// not charted this water", and stripes the eye cannot find say nothing.
|
|
5809
|
+
// DAY 3.08:1, darker than its ground. Also the colour the artwork file
|
|
5810
|
+
// itself is drawn in.
|
|
5811
|
+
inlandHatch: "#5B7383",
|
|
5812
|
+
// State furniture. These three were referenced by the layers but missing
|
|
5813
|
+
// from this table (and its type — the long-standing TS2339 trio), so the
|
|
5814
|
+
// lines shipped on MapLibre's DEFAULT black. Now deliberate: a hairline
|
|
5815
|
+
// a shade deeper than the tan, quiet caps, tan halo.
|
|
5816
|
+
stateLine: "#B1A077",
|
|
5817
|
+
stateLabel: "#8E8468",
|
|
5818
|
+
stateHalo: "#D4C69D",
|
|
5819
|
+
// Rough-lake furniture (owner ask 2026-08-28: "the lakes need labels,
|
|
5820
|
+
// and shorelines drawn"): a shoreline a shade deeper than the rough
|
|
5821
|
+
// water, and a name in the water's own voice, haloed by the water.
|
|
5822
|
+
inlandShore: "#8FA9BA",
|
|
5823
|
+
inlandLabel: "#54707F",
|
|
5824
|
+
inlandHalo: "#B9CFDD"
|
|
5825
|
+
},
|
|
5826
|
+
DUSK: {
|
|
5827
|
+
// ── Re-derived 2026-09-01: the basemap sits UNDER the chart ──────────
|
|
5828
|
+
// These were the DAY tones scaled by a constant, never measured against
|
|
5829
|
+
// the DUSK chart — so `jurisdiction` came out at L=0.506 against a chart
|
|
5830
|
+
// whose own land (LANDA #8a7d5e) is L=0.209, i.e. the context layer was
|
|
5831
|
+
// 2.4x brighter than the data layer. Now capped at the chart's own land.
|
|
5832
|
+
// The rest of the block rides the same 0.666 channel factor so every
|
|
5833
|
+
// relationship the palette already chose is preserved, only moved down.
|
|
5834
|
+
// `water` is deliberately NOT scaled: it is the reference the land/sea
|
|
5835
|
+
// floor is measured against.
|
|
5836
|
+
earth: "#544E3E",
|
|
5837
|
+
water: "#161D21",
|
|
5838
|
+
river: "#141B20",
|
|
5839
|
+
boundary: "#293135",
|
|
5840
|
+
jurisdiction: "#867D64",
|
|
5841
|
+
inlandWater: "#62717A",
|
|
5842
|
+
// Owner's choice, 2026-10-04: dark stripes, 2.37:1. The DAY stripe here
|
|
5843
|
+
// was 1.02:1 — invisible, so an uncharted lake read as plain water.
|
|
5844
|
+
inlandHatch: "#2E383F",
|
|
5845
|
+
// Label stays DARK here — the halo is still mid-toned, so 3:1 is reachable
|
|
5846
|
+
// downward and a bright label would be a new light source at dusk.
|
|
5847
|
+
stateLine: "#B5A987",
|
|
5848
|
+
stateLabel: "#38342A",
|
|
5849
|
+
stateHalo: "#867D64",
|
|
5850
|
+
inlandShore: "#4D5B67",
|
|
5851
|
+
inlandLabel: "#212629",
|
|
5852
|
+
inlandHalo: "#62717A"
|
|
5853
|
+
},
|
|
5854
|
+
NIGHT: {
|
|
5855
|
+
// ── Re-derived 2026-09-01 — the owner-reported night defect ──────────
|
|
5856
|
+
// `jurisdiction` was L=0.240 against a chart whose own land (LANDA
|
|
5857
|
+
// #3a3020) is L=0.031: the world basemap was 7.7x BRIGHTER than the chart
|
|
5858
|
+
// it sits under, so at z<11 the uncharted interior read as a pale
|
|
5859
|
+
// continent-sized slab on a night chart. Capped at the chart's own land.
|
|
5860
|
+
//
|
|
5861
|
+
// ⚠ `earth` AND `jurisdiction` CONVERGE HERE, and that is forced, not
|
|
5862
|
+
// sloppy. Holding earth 2:1 above the ocean AND 2:1 below the jurisdiction
|
|
5863
|
+
// tan requires jurisdiction >= L 0.174 — 5.6x the chart's own land. At
|
|
5864
|
+
// night the range between the ocean (L 0.006) and the cap (L 0.031) is too
|
|
5865
|
+
// compressed to carry two land tones. COVERAGE IS STILL SAID, by the
|
|
5866
|
+
// `chrt:hatch-nocoverage` crosshatch, which is a stronger signal than tone
|
|
5867
|
+
// and is the one thing that cannot be lost to palette compression.
|
|
5868
|
+
//
|
|
5869
|
+
// Labels invert to light-on-dark: 3:1 downward is unreachable off a halo
|
|
5870
|
+
// this close to black, and CHRTland's own night town labels already sit at
|
|
5871
|
+
// L=0.177 for exactly this reason.
|
|
5872
|
+
earth: "#333026",
|
|
5873
|
+
water: "#10161A",
|
|
5874
|
+
river: "#090D0F",
|
|
5875
|
+
boundary: "#131719",
|
|
5876
|
+
jurisdiction: "#353128",
|
|
5877
|
+
inlandWater: "#232A30",
|
|
5878
|
+
// The DAY stripe, lighter than this ground: 2.92:1, and L 0.16, under the
|
|
5879
|
+
// NIGHT muted-ink ceiling (`night-luminance.test.ts`). Red night draws the
|
|
5880
|
+
// NIGHT chart, so this is its stripe too.
|
|
5881
|
+
inlandHatch: "#5B7383",
|
|
5882
|
+
stateLine: "#484236",
|
|
5883
|
+
stateLabel: "#837963",
|
|
5884
|
+
stateHalo: "#353128",
|
|
5885
|
+
inlandShore: "#1C2227",
|
|
5886
|
+
inlandLabel: "#617484",
|
|
5887
|
+
inlandHalo: "#232A30"
|
|
5888
|
+
},
|
|
5889
|
+
// ── E-ink: uncharted is DARK, never paper ─────────────────────────────
|
|
5890
|
+
// On an e-ink chart, charted safe water is paper. Water outside coverage
|
|
5891
|
+
// must never read as that, so it is the darkest fill on the page — the
|
|
5892
|
+
// e-ink twin of DAY's dark carto — with the no-coverage crosshatch over it
|
|
5893
|
+
// (invariant 5: the coverage portrayal survives). Land outside coverage
|
|
5894
|
+
// keeps the chart's own land tone.
|
|
5895
|
+
EINK_COLOR: {
|
|
5896
|
+
earth: "#d8ccb0",
|
|
5897
|
+
water: "#4f5a62",
|
|
5898
|
+
river: "#4f5a62",
|
|
5899
|
+
boundary: "#000000",
|
|
5900
|
+
jurisdiction: "#f2e2b0",
|
|
5901
|
+
inlandWater: "#c8d6e0",
|
|
5902
|
+
// The house stripe, 3.4:1 on this rough water — strong enough for the
|
|
5903
|
+
// 150 ppi colour layer.
|
|
5904
|
+
inlandHatch: "#5B7383",
|
|
5905
|
+
stateLine: "#555555",
|
|
5906
|
+
stateLabel: "#000000",
|
|
5907
|
+
stateHalo: "#ffffff",
|
|
5908
|
+
inlandShore: "#555555",
|
|
5909
|
+
inlandLabel: "#000000",
|
|
5910
|
+
inlandHalo: "#ffffff"
|
|
5911
|
+
},
|
|
5912
|
+
// Mono: the same rule in the four greys. Uncharted water DARK under a MID
|
|
5913
|
+
// crosshatch; land MID; rough inland water PAPER under the uncharted hatch.
|
|
5914
|
+
EINK_MONO: {
|
|
5915
|
+
earth: "#aaaaaa",
|
|
5916
|
+
water: "#555555",
|
|
5917
|
+
river: "#555555",
|
|
5918
|
+
boundary: "#000000",
|
|
5919
|
+
jurisdiction: "#aaaaaa",
|
|
5920
|
+
inlandWater: "#ffffff",
|
|
5921
|
+
inlandHatch: "#555555",
|
|
5922
|
+
stateLine: "#555555",
|
|
5923
|
+
stateLabel: "#000000",
|
|
5924
|
+
stateHalo: "#ffffff",
|
|
5925
|
+
inlandShore: "#555555",
|
|
5926
|
+
inlandLabel: "#000000",
|
|
5927
|
+
inlandHalo: "#ffffff"
|
|
5928
|
+
},
|
|
5929
|
+
// Night: the inverse. Water outside coverage is the black ground UNDER the
|
|
5930
|
+
// light crosshatch — charted safe water is plain black, so the hatch is what
|
|
5931
|
+
// tells them apart, here as everywhere. Land the DIM grey; labels the line
|
|
5932
|
+
// grey on black.
|
|
5933
|
+
EINK_NIGHT: {
|
|
5934
|
+
earth: "#555555",
|
|
5935
|
+
water: "#000000",
|
|
5936
|
+
river: "#000000",
|
|
5937
|
+
boundary: "#aaaaaa",
|
|
5938
|
+
jurisdiction: "#555555",
|
|
5939
|
+
inlandWater: "#000000",
|
|
5940
|
+
inlandHatch: "#aaaaaa",
|
|
5941
|
+
stateLine: "#aaaaaa",
|
|
5942
|
+
stateLabel: "#aaaaaa",
|
|
5943
|
+
stateHalo: "#000000",
|
|
5944
|
+
inlandShore: "#aaaaaa",
|
|
5945
|
+
inlandLabel: "#aaaaaa",
|
|
5946
|
+
inlandHalo: "#000000"
|
|
5947
|
+
}
|
|
5948
|
+
};
|
|
5949
|
+
function baseLayers(opts = {}) {
|
|
5950
|
+
const palette = opts.palette ?? "DAY";
|
|
5951
|
+
const T = BASE_THEMES[palette] ?? BASE_THEMES.DAY;
|
|
5952
|
+
const src = opts.sourceId ?? BASE_REGION;
|
|
5953
|
+
const L = (o) => o;
|
|
5954
|
+
return [
|
|
5955
|
+
// 1. Geography — the world as it is, in the quiet dark voice. The OCEAN
|
|
5956
|
+
// is a background, not a polygon: the archive ships land and lakes,
|
|
5957
|
+
// and "everything else is sea" is exactly what a background expresses
|
|
5958
|
+
// — geometry-free, gap-free at every antimeridian and pole. Without
|
|
5959
|
+
// it the sea outside coverage was bare S-52 NODTA, a light grey that
|
|
5960
|
+
// read as "charted ground" with a hatch on it.
|
|
5961
|
+
L({
|
|
5962
|
+
id: "chrtbase-ocean",
|
|
5963
|
+
type: "background",
|
|
5964
|
+
paint: { "background-color": T.water }
|
|
5965
|
+
}),
|
|
5966
|
+
L({
|
|
5967
|
+
id: "chrtbase-earth",
|
|
5968
|
+
type: "fill",
|
|
5969
|
+
source: src,
|
|
5970
|
+
"source-layer": "base_earth",
|
|
5971
|
+
paint: { "fill-color": T.earth }
|
|
5972
|
+
}),
|
|
5973
|
+
L({
|
|
5974
|
+
id: "chrtbase-water",
|
|
5975
|
+
type: "fill",
|
|
5976
|
+
source: src,
|
|
5977
|
+
"source-layer": "base_water",
|
|
5978
|
+
paint: { "fill-color": T.water }
|
|
5979
|
+
}),
|
|
5980
|
+
L({
|
|
5981
|
+
id: "chrtbase-river",
|
|
5982
|
+
type: "line",
|
|
5983
|
+
source: src,
|
|
5984
|
+
"source-layer": "base_river",
|
|
5985
|
+
minzoom: 9,
|
|
5986
|
+
paint: {
|
|
5987
|
+
"line-color": T.river,
|
|
5988
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 9, 0.6, 14, 1.6]
|
|
5989
|
+
}
|
|
5990
|
+
}),
|
|
5991
|
+
L({
|
|
5992
|
+
id: "chrtbase-boundary",
|
|
5993
|
+
type: "line",
|
|
5994
|
+
source: src,
|
|
5995
|
+
"source-layer": "base_boundary",
|
|
5996
|
+
paint: { "line-color": T.boundary, "line-width": 0.6, "line-opacity": 0.8 }
|
|
5997
|
+
}),
|
|
5998
|
+
// 2. THE DEFAULT: no coverage, everywhere, as a geometry-free background.
|
|
5999
|
+
// Constant opacity by design — see the header. What kills it is being
|
|
6000
|
+
// painted OVER, never fading.
|
|
6001
|
+
L({
|
|
6002
|
+
id: "chrtbase-nocoverage",
|
|
6003
|
+
type: "background",
|
|
6004
|
+
paint: { "background-pattern": NOCOVERAGE_PATTERN, "background-opacity": 0.55 }
|
|
6005
|
+
}),
|
|
6006
|
+
// 3. The jurisdiction: countries whose charts CHRT carries go tan — the
|
|
6007
|
+
// same tan as CHRTland, so "land in our world" is ONE colour. Opaque,
|
|
6008
|
+
// so it takes the crosshatch off its ground entirely.
|
|
6009
|
+
L({
|
|
6010
|
+
id: "chrtbase-jurisdiction",
|
|
6011
|
+
type: "fill",
|
|
6012
|
+
source: src,
|
|
6013
|
+
"source-layer": "jurisdiction",
|
|
6014
|
+
paint: { "fill-color": T.jurisdiction }
|
|
6015
|
+
}),
|
|
6016
|
+
// 4. States — internal boundaries and names, inside the jurisdiction
|
|
6017
|
+
// only (owner decision 2026-08-28). A hairline a shade deeper than the
|
|
6018
|
+
// tan, and quiet letter-spaced caps that fade as harbour detail takes
|
|
6019
|
+
// over. The one deliberate exception to no-names-on-the-basemap:
|
|
6020
|
+
// ADMIN furniture, nothing else — see the fence test.
|
|
6021
|
+
L({
|
|
6022
|
+
id: "chrtbase-state-boundary",
|
|
6023
|
+
type: "line",
|
|
6024
|
+
source: src,
|
|
6025
|
+
"source-layer": "state_boundary",
|
|
6026
|
+
minzoom: 4,
|
|
6027
|
+
paint: {
|
|
6028
|
+
"line-color": T.stateLine,
|
|
6029
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 4, 0.5, 10, 1],
|
|
6030
|
+
"line-dasharray": [3, 2],
|
|
6031
|
+
"line-opacity": 0.8
|
|
6032
|
+
}
|
|
6033
|
+
}),
|
|
6034
|
+
// 5. Country borders, drawn to be HOISTED above the whole chart by the
|
|
6035
|
+
// generator (owner, 2026-08-31: "where there is charted land, can we
|
|
6036
|
+
// add country borders on top of everything? I want it clear where
|
|
6037
|
+
// there is a boarder."). Sourced from NE boundary_lines_land — land
|
|
6038
|
+
// borders only, never coastline — so riding on top cannot stroke a
|
|
6039
|
+
// coast. Dashed so it reads as an administrative line, not chart
|
|
6040
|
+
// linework.
|
|
6041
|
+
L({
|
|
6042
|
+
id: "chrtbase-country-boundary",
|
|
6043
|
+
type: "line",
|
|
6044
|
+
source: src,
|
|
6045
|
+
"source-layer": "country_boundary",
|
|
6046
|
+
paint: {
|
|
6047
|
+
"line-color": T.boundary,
|
|
6048
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 3, 0.8, 8, 1.4, 12, 2.2],
|
|
6049
|
+
"line-dasharray": [4, 2],
|
|
6050
|
+
"line-opacity": 0.9
|
|
6051
|
+
}
|
|
6052
|
+
}),
|
|
6053
|
+
L({
|
|
6054
|
+
id: "chrtbase-state-label",
|
|
6055
|
+
type: "symbol",
|
|
6056
|
+
source: src,
|
|
6057
|
+
"source-layer": "state_label",
|
|
6058
|
+
minzoom: 4,
|
|
6059
|
+
maxzoom: 10,
|
|
6060
|
+
layout: {
|
|
6061
|
+
"text-field": ["upcase", ["get", "name"]],
|
|
6062
|
+
"text-font": ["Open Sans Regular"],
|
|
6063
|
+
"text-size": ["interpolate", ["linear"], ["zoom"], 4, 9, 8, 12],
|
|
6064
|
+
"text-letter-spacing": 0.25,
|
|
6065
|
+
"text-allow-overlap": false,
|
|
6066
|
+
"text-padding": 8
|
|
6067
|
+
},
|
|
6068
|
+
paint: {
|
|
6069
|
+
"text-color": T.stateLabel,
|
|
6070
|
+
"text-halo-color": T.stateHalo,
|
|
6071
|
+
"text-halo-width": 1.2,
|
|
6072
|
+
"text-opacity": ["interpolate", ["linear"], ["zoom"], 4, 0.7, 8, 0.85, 10, 0.4]
|
|
6073
|
+
}
|
|
6074
|
+
})
|
|
6075
|
+
];
|
|
6076
|
+
}
|
|
6077
|
+
function baseInlandWaterLayers(opts = {}) {
|
|
6078
|
+
const palette = opts.palette ?? "DAY";
|
|
6079
|
+
const T = BASE_THEMES[palette] ?? BASE_THEMES.DAY;
|
|
6080
|
+
const src = opts.sourceId ?? BASE_REGION;
|
|
6081
|
+
const L = (o) => o;
|
|
6082
|
+
const NE_TIER = ["!", ["has", "kind"]];
|
|
6083
|
+
const PLANET_TIER = ["has", "kind"];
|
|
6084
|
+
const HANDOVER = 9;
|
|
6085
|
+
return [
|
|
6086
|
+
// ── The fill pair, SPLIT BY TIER at the handover ────────────────────────
|
|
6087
|
+
//
|
|
6088
|
+
// Both tiers share `inland_water` (tile-join concatenates the same layer
|
|
6089
|
+
// name), and an unsplit fill draws BOTH — which means the NE polygon is
|
|
6090
|
+
// painted over the planet one at every zoom. That is not a cosmetic
|
|
6091
|
+
// double-draw: NE 10m carries no interior rings, so its blob has no
|
|
6092
|
+
// ISLANDS in it, and painting it over the planet's holed polygons buries
|
|
6093
|
+
// every island in the lake under "uncharted water". Owner-reported at
|
|
6094
|
+
// Winnipesaukee z11.7 ("there is land (and islands) being covered by the
|
|
6095
|
+
// 'no chart here' boundary"), and measured: rendering the planet tier
|
|
6096
|
+
// alone brings back the whole archipelago — Rattlesnake, Bear, Long
|
|
6097
|
+
// Island, Diamond, the Barndoors — while the NE tier alone is a faceted
|
|
6098
|
+
// blob whose edges bear no relation to the shoreline drawn beneath it.
|
|
6099
|
+
//
|
|
6100
|
+
// So each tier owns its own zoom range, the same handover the shoreline
|
|
6101
|
+
// below uses. Known residue, measured over the whole archive: of the 141
|
|
6102
|
+
// NE lakes we still carry, 138 have planet water beneath them; the
|
|
6103
|
+
// exceptions are two unnamed western-Alaska tundra lakes and a 2e-5 deg²
|
|
6104
|
+
// Lake Michigan sliver, which lose their rough fill above z9 because the
|
|
6105
|
+
// planet has no `water` polygon there at all (checked against the raw
|
|
6106
|
+
// pre-clip NDJSON — not a clip artefact).
|
|
6107
|
+
L({
|
|
6108
|
+
id: "chrtbase-inland-water",
|
|
6109
|
+
type: "fill",
|
|
6110
|
+
source: src,
|
|
6111
|
+
"source-layer": "inland_water",
|
|
6112
|
+
filter: NE_TIER,
|
|
6113
|
+
maxzoom: HANDOVER,
|
|
6114
|
+
paint: { "fill-color": T.inlandWater }
|
|
6115
|
+
}),
|
|
6116
|
+
L({
|
|
6117
|
+
id: "chrtbase-inland-hatch",
|
|
6118
|
+
type: "fill",
|
|
6119
|
+
source: src,
|
|
6120
|
+
"source-layer": "inland_water",
|
|
6121
|
+
filter: NE_TIER,
|
|
6122
|
+
maxzoom: HANDOVER,
|
|
6123
|
+
paint: { "fill-pattern": UNCHARTED_PATTERN, "fill-opacity": 0.7 }
|
|
6124
|
+
}),
|
|
6125
|
+
L({
|
|
6126
|
+
id: "chrtbase-inland-water-detail",
|
|
6127
|
+
type: "fill",
|
|
6128
|
+
source: src,
|
|
6129
|
+
"source-layer": "inland_water",
|
|
6130
|
+
filter: PLANET_TIER,
|
|
6131
|
+
minzoom: HANDOVER,
|
|
6132
|
+
paint: { "fill-color": T.inlandWater }
|
|
6133
|
+
}),
|
|
6134
|
+
L({
|
|
6135
|
+
id: "chrtbase-inland-hatch-detail",
|
|
6136
|
+
type: "fill",
|
|
6137
|
+
source: src,
|
|
6138
|
+
"source-layer": "inland_water",
|
|
6139
|
+
filter: PLANET_TIER,
|
|
6140
|
+
minzoom: HANDOVER,
|
|
6141
|
+
paint: { "fill-pattern": UNCHARTED_PATTERN, "fill-opacity": 0.7 }
|
|
6142
|
+
}),
|
|
6143
|
+
// The rough shoreline (owner ask 2026-08-28). Drawn ABOVE the hatch so
|
|
6144
|
+
// the edge stays crisp through the texture, and BELOW the charted-water
|
|
6145
|
+
// repaint clones the generator splices in after it — so wherever the
|
|
6146
|
+
// chart repaints its own water, the rough NE10m line yields to the
|
|
6147
|
+
// chart's COALNE instead of double-striking it.
|
|
6148
|
+
//
|
|
6149
|
+
// NE-tier geometry ONLY (`kind` absent): the planet detail tier joins
|
|
6150
|
+
// the same source-layer from z9 as MANY polygons whose chunk-clip seams
|
|
6151
|
+
// rejoin invisibly as FILLS — but a line layer strokes every seam, and
|
|
6152
|
+
// Winnipesaukee rendered as a mesh of internal edges. Planet features
|
|
6153
|
+
// carry `kind` (the INLAND_KINDS filter's own field); NE's carry only
|
|
6154
|
+
// `name`, so the absence of `kind` IS the tier discriminator.
|
|
6155
|
+
L({
|
|
6156
|
+
id: "chrtbase-inland-shore",
|
|
6157
|
+
type: "line",
|
|
6158
|
+
source: src,
|
|
6159
|
+
"source-layer": "inland_water",
|
|
6160
|
+
filter: NE_TIER,
|
|
6161
|
+
// Hands the shoreline over to the planet tier at ITS floor. Both
|
|
6162
|
+
// tiers live in `inland_water` from z9 up (tile-join concatenates the
|
|
6163
|
+
// same layer name), and their FILLS merge invisibly — but two
|
|
6164
|
+
// outlines do not: NE 10m generalises Winnipesaukee's shape, so its
|
|
6165
|
+
// outline ran straight across the middle of the lake the planet had
|
|
6166
|
+
// drawn correctly around. The coarse line is right only while it is
|
|
6167
|
+
// the only shape we have.
|
|
6168
|
+
maxzoom: HANDOVER,
|
|
6169
|
+
paint: {
|
|
6170
|
+
"line-color": T.inlandShore,
|
|
6171
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 4, 0.5, 10, 1.1, 14, 1.6],
|
|
6172
|
+
"line-opacity": 0.9
|
|
6173
|
+
}
|
|
6174
|
+
}),
|
|
6175
|
+
// The PLANET tier's shoreline (owner ask 2026-08-31: "uncharted small
|
|
6176
|
+
// lakes render with no outline"). It reads its own `inland_shore` layer,
|
|
6177
|
+
// NOT `inland_water`, and that indirection is the whole fix: the mesh
|
|
6178
|
+
// that forced the `!has kind` fence above is a CLIP artefact — an MVT
|
|
6179
|
+
// feature arrives already cut to its own z10 tile, so stroking the
|
|
6180
|
+
// polygon strokes every tile boundary it crosses. The build now walks
|
|
6181
|
+
// those rings, drops the axis-aligned runs that sit on the read zoom's
|
|
6182
|
+
// tile grid, and emits what is left as lines (measured on one New
|
|
6183
|
+
// England chunk: 61 long axis-aligned mesh edges → 5, and the 5 survivors
|
|
6184
|
+
// are 0.02–0.5 tiles off the grid, i.e. real straight water edges).
|
|
6185
|
+
//
|
|
6186
|
+
// Thinner and quieter than the NE line: this is finer geometry describing
|
|
6187
|
+
// water nobody has surveyed, and approximate data should look
|
|
6188
|
+
// approximate.
|
|
6189
|
+
L({
|
|
6190
|
+
id: "chrtbase-inland-shore-detail",
|
|
6191
|
+
type: "line",
|
|
6192
|
+
source: src,
|
|
6193
|
+
"source-layer": "inland_shore",
|
|
6194
|
+
minzoom: HANDOVER,
|
|
6195
|
+
paint: {
|
|
6196
|
+
"line-color": T.inlandShore,
|
|
6197
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 9, 0.5, 12, 0.9, 15, 1.2],
|
|
6198
|
+
"line-opacity": 0.85
|
|
6199
|
+
}
|
|
6200
|
+
}),
|
|
6201
|
+
// The lake's name (owner ask 2026-08-28) — the second scoped exception
|
|
6202
|
+
// to no-names-on-the-basemap, after the states: WATER-BODY names only.
|
|
6203
|
+
// No maxzoom: an uncharted lake keeps its name at every zoom; over
|
|
6204
|
+
// charted lakes the chart's own SEAARE label takes over at detail zooms
|
|
6205
|
+
// and collision culls the echo.
|
|
6206
|
+
//
|
|
6207
|
+
// The archive's `inland_water_label` anchors (v3+). v3 shipped ONE
|
|
6208
|
+
// PointOnSurface anchor per lake, and a big lake's single anchor pans
|
|
6209
|
+
// off-viewport — Winnipesaukee at z11.7 read nameless with its name two
|
|
6210
|
+
// tiles west of the screen (owner-reported). Labelling the polygons
|
|
6211
|
+
// instead is NOT the fix: tippecanoe's coalescing drops the NE polygon
|
|
6212
|
+
// from some z11 tiles (measured: 11/619/747 carries only planet pieces),
|
|
6213
|
+
// so a polygon-sourced label vanishes tile by tile. v4 therefore bakes a
|
|
6214
|
+
// deterministic anchor GRID into big lakes — the paper-chart convention
|
|
6215
|
+
// of repeating a name along a large water body — and this one layer
|
|
6216
|
+
// renders however many anchors are in view; collision culls the rest.
|
|
6217
|
+
// Planet-tier water-body NAMES (owner ask 2026-08-31: NE 10m names only
|
|
6218
|
+
// 113 US lakes). Emitted BELOW the NE layer on purpose — MapLibre places
|
|
6219
|
+
// symbols topmost-layer-first, so the big NE lake wins collision against
|
|
6220
|
+
// the pond beside it, and both lose to the chart's own labels (every ENC
|
|
6221
|
+
// class is emitted after this pair).
|
|
6222
|
+
//
|
|
6223
|
+
// The size threshold is OSM's own `min_zoom`, carried through the build:
|
|
6224
|
+
// Lake Winnipesaukee reads 10, Squam Lake 12, so a pond simply is not in
|
|
6225
|
+
// the filter until the user is close enough for it to be the answer to
|
|
6226
|
+
// "what is that water". `["zoom"]` in a filter evaluates at integer zoom
|
|
6227
|
+
// levels and removes the feature from placement entirely — verified
|
|
6228
|
+
// against maplibre-gl-native rather than assumed, because a text-size-0
|
|
6229
|
+
// gate would still claim a collision slot.
|
|
6230
|
+
//
|
|
6231
|
+
// The tiers are separate LAYERS, not a filtered split of one — see the
|
|
6232
|
+
// builder for why: an archive that a not-yet-deployed style would
|
|
6233
|
+
// mis-render cannot be promoted first, and this one has to be.
|
|
6234
|
+
L({
|
|
6235
|
+
id: "chrtbase-inland-label-detail",
|
|
6236
|
+
type: "symbol",
|
|
6237
|
+
source: src,
|
|
6238
|
+
"source-layer": "inland_water_label_detail",
|
|
6239
|
+
minzoom: HANDOVER,
|
|
6240
|
+
filter: [">=", ["zoom"], ["get", "min_zoom"]],
|
|
6241
|
+
layout: {
|
|
6242
|
+
"text-field": ["get", "name"],
|
|
6243
|
+
"text-font": ["Open Sans Regular"],
|
|
6244
|
+
"text-size": ["interpolate", ["linear"], ["zoom"], 9, 9, 12, 10.5, 15, 11],
|
|
6245
|
+
"text-max-width": 8,
|
|
6246
|
+
"text-allow-overlap": false,
|
|
6247
|
+
"text-padding": 6,
|
|
6248
|
+
// Bigger water first within the tier — min_zoom IS the size rank.
|
|
6249
|
+
"symbol-sort-key": ["get", "min_zoom"]
|
|
6250
|
+
},
|
|
6251
|
+
paint: {
|
|
6252
|
+
"text-color": T.inlandLabel,
|
|
6253
|
+
"text-halo-color": T.inlandHalo,
|
|
6254
|
+
"text-halo-width": 1,
|
|
6255
|
+
"text-opacity": 0.9
|
|
6256
|
+
}
|
|
6257
|
+
}),
|
|
6258
|
+
L({
|
|
6259
|
+
id: "chrtbase-inland-label",
|
|
6260
|
+
type: "symbol",
|
|
6261
|
+
source: src,
|
|
6262
|
+
"source-layer": "inland_water_label",
|
|
6263
|
+
minzoom: 5,
|
|
6264
|
+
layout: {
|
|
6265
|
+
"text-field": ["get", "name"],
|
|
6266
|
+
"text-font": ["Open Sans Regular"],
|
|
6267
|
+
"text-size": ["interpolate", ["linear"], ["zoom"], 5, 9.5, 10, 12],
|
|
6268
|
+
"text-max-width": 7,
|
|
6269
|
+
"text-allow-overlap": false,
|
|
6270
|
+
// Zoom-scaled spacing for the anchor GRID: at z8.9 the 0.08-deg
|
|
6271
|
+
// anchors sit ~54 px apart and a flat padding let six copies of
|
|
6272
|
+
// "Lake Ontario" crowd one screen (owner-reported 2026-08-30).
|
|
6273
|
+
// Wide collision boxes at low zoom thin the grid to the repeat-
|
|
6274
|
+
// by-convention cadence; by z12 the anchors are ~850 px apart and
|
|
6275
|
+
// the padding relaxes to normal.
|
|
6276
|
+
"text-padding": ["interpolate", ["linear"], ["zoom"], 5, 80, 9, 64, 12, 16]
|
|
6277
|
+
},
|
|
6278
|
+
paint: {
|
|
6279
|
+
"text-color": T.inlandLabel,
|
|
6280
|
+
"text-halo-color": T.inlandHalo,
|
|
6281
|
+
"text-halo-width": 1.1
|
|
6282
|
+
}
|
|
6283
|
+
})
|
|
6284
|
+
];
|
|
6285
|
+
}
|
|
6286
|
+
|
|
6287
|
+
// src/atlas/eink-portrayal.ts
|
|
6288
|
+
var EINK_DOTS_PATTERN = `${CHRT_ICON_PREFIX}eink-dots`;
|
|
6289
|
+
var EINK_HATCH_PATTERN = `${CHRT_ICON_PREFIX}eink-hatch`;
|
|
6290
|
+
var EINK_DANGER_PATTERN = `${CHRT_ICON_PREFIX}eink-danger`;
|
|
6291
|
+
var EINK_LINE_SCALE = 1.5;
|
|
6292
|
+
var EINK_LINE_MIN_PX = 1;
|
|
6293
|
+
var EINK_TEXT_SCALE = 1.15;
|
|
6294
|
+
var EINK_HALO_MIN_PX = 1.5;
|
|
6295
|
+
var EINK_DANGER_ICON_SCALE = 1.35;
|
|
6296
|
+
var EINK_WASH_CUTOFF = 0.3;
|
|
6297
|
+
var EINK_SAFETY_CONTOUR_WIDTH = [2, 3.5];
|
|
6298
|
+
var EINK_DANGER_CLASSES = /* @__PURE__ */ new Set(["OBSTRN", "WRECKS", "UWTROC"]);
|
|
6299
|
+
var METRIC_CONTOUR_LADDER_M = [0, 2, 5, 10, 15, 20, 30, 50, 100, 200, 500, 1e3];
|
|
6300
|
+
var IMPERIAL_CONTOUR_LADDER_M = [
|
|
6301
|
+
1.8,
|
|
6302
|
+
3.6,
|
|
6303
|
+
5.4,
|
|
6304
|
+
9.1,
|
|
6305
|
+
18.2,
|
|
6306
|
+
27.4,
|
|
6307
|
+
36.5,
|
|
6308
|
+
54.8,
|
|
6309
|
+
91.4,
|
|
6310
|
+
182.8,
|
|
6311
|
+
365.7,
|
|
6312
|
+
914.4
|
|
6313
|
+
];
|
|
6314
|
+
function snapToLadder(safetyM, ladder) {
|
|
6315
|
+
for (const rung of ladder) if (rung >= safetyM - 1e-6) return rung;
|
|
6316
|
+
return null;
|
|
6317
|
+
}
|
|
6318
|
+
function safetyContourValues(safetyContourM) {
|
|
6319
|
+
const s = effectiveSafetyContour(safetyContourM);
|
|
6320
|
+
const out = [snapToLadder(s, METRIC_CONTOUR_LADDER_M), snapToLadder(s, IMPERIAL_CONTOUR_LADDER_M)];
|
|
6321
|
+
return [...new Set(out.filter((v) => v !== null))];
|
|
6322
|
+
}
|
|
6323
|
+
function isExpr(v) {
|
|
6324
|
+
return Array.isArray(v) && typeof v[0] === "string";
|
|
6325
|
+
}
|
|
6326
|
+
function scaleNumeric(v, k, min = 0) {
|
|
6327
|
+
if (typeof v === "number") return Math.max(v * k, v > 0 ? min : 0);
|
|
6328
|
+
if (!isExpr(v)) return v;
|
|
6329
|
+
const op = v[0];
|
|
6330
|
+
if (op === "interpolate" || op === "interpolate-hcl" || op === "interpolate-lab") {
|
|
6331
|
+
const out = v.slice(0, 3);
|
|
6332
|
+
for (let i = 3; i < v.length; i += 2) out.push(v[i], scaleNumeric(v[i + 1], k, min));
|
|
6333
|
+
return out;
|
|
6334
|
+
}
|
|
6335
|
+
if (op === "step") {
|
|
6336
|
+
const out = [op, v[1], scaleNumeric(v[2], k, min)];
|
|
6337
|
+
for (let i = 3; i < v.length; i += 2) out.push(v[i], scaleNumeric(v[i + 1], k, min));
|
|
6338
|
+
return out;
|
|
6339
|
+
}
|
|
6340
|
+
if (op === "literal") return v;
|
|
6341
|
+
return ["max", ["*", v, k], min];
|
|
6342
|
+
}
|
|
6343
|
+
function objectClass(layer) {
|
|
6344
|
+
const md = layer.metadata;
|
|
6345
|
+
const c = md?.["s52:objectClass"];
|
|
6346
|
+
return typeof c === "string" ? c : null;
|
|
6347
|
+
}
|
|
6348
|
+
function scaffoldId(prefix, baseId) {
|
|
6349
|
+
return `${prefix}${baseId.replace(/-band(\d)/g, "-b$1")}`;
|
|
6350
|
+
}
|
|
6351
|
+
var DRVAL1 = ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1];
|
|
6352
|
+
var DRVAL2 = ["coalesce", ["get", "DRVAL2"], ["get", "drval2"], 0];
|
|
6353
|
+
var VALDCO = ["to-number", ["coalesce", ["get", "VALDCO"], ["get", "valdco"], -1], -1];
|
|
6354
|
+
function withFilter(base, extra) {
|
|
6355
|
+
return base === void 0 ? extra : ["all", base, extra];
|
|
6356
|
+
}
|
|
6357
|
+
function applyEinkPortrayal(style, palette, opts = {}) {
|
|
6358
|
+
if (palette !== "EINK_COLOR" && palette !== "EINK_MONO" && palette !== "EINK_NIGHT") return style;
|
|
6359
|
+
const mono = isEinkGreyTable(palette);
|
|
6360
|
+
const night = palette === "EINK_NIGHT";
|
|
6361
|
+
const safetyInk = resolveColor("DEPSC", palette);
|
|
6362
|
+
const groundInk = resolveColor("UIBCK", palette);
|
|
6363
|
+
const safety = effectiveSafetyContour(opts.safetyContour ?? DEFAULT_SAFETY_CONTOUR_M);
|
|
6364
|
+
const safetyValues = safetyContourValues(safety);
|
|
6365
|
+
const out = [];
|
|
6366
|
+
for (const original of style.layers) {
|
|
6367
|
+
const id = original.id;
|
|
6368
|
+
const type = original.type;
|
|
6369
|
+
if (type === "hillshade" || id.startsWith("chrtland-fade-")) continue;
|
|
6370
|
+
const layer = structuredClone(original);
|
|
6371
|
+
const paint = layer.paint ??= {};
|
|
6372
|
+
const layout = layer.layout;
|
|
6373
|
+
const cls = objectClass(layer);
|
|
6374
|
+
if (type === "line") {
|
|
6375
|
+
if (paint["line-width"] !== void 0) {
|
|
6376
|
+
paint["line-width"] = scaleNumeric(paint["line-width"], EINK_LINE_SCALE, EINK_LINE_MIN_PX);
|
|
6377
|
+
} else {
|
|
6378
|
+
paint["line-width"] = EINK_LINE_SCALE;
|
|
6379
|
+
}
|
|
6380
|
+
const o = paint["line-opacity"];
|
|
6381
|
+
if (typeof o === "number" && o > 0 && o < 1) paint["line-opacity"] = 1;
|
|
6382
|
+
if (paint["line-blur"] !== void 0) paint["line-blur"] = 0;
|
|
6383
|
+
}
|
|
6384
|
+
if (type === "fill") {
|
|
6385
|
+
const o = paint["fill-opacity"];
|
|
6386
|
+
if (typeof o === "number" && o > 0 && o < 1) {
|
|
6387
|
+
if (cls && EINK_DANGER_CLASSES.has(cls)) {
|
|
6388
|
+
paint["fill-pattern"] = EINK_DANGER_PATTERN;
|
|
6389
|
+
paint["fill-opacity"] = 1;
|
|
6390
|
+
} else {
|
|
6391
|
+
paint["fill-opacity"] = o < EINK_WASH_CUTOFF ? 0 : 1;
|
|
6392
|
+
}
|
|
6393
|
+
}
|
|
6394
|
+
if (paint["fill-antialias"] === void 0) paint["fill-antialias"] = true;
|
|
6395
|
+
}
|
|
6396
|
+
if (type === "background" && night && id === "chrt-background") {
|
|
6397
|
+
paint["background-pattern"] = NOCOVERAGE_PATTERN;
|
|
6398
|
+
}
|
|
6399
|
+
if (type === "background") {
|
|
6400
|
+
const o = paint["background-opacity"];
|
|
6401
|
+
if (typeof o === "number" && o > 0 && o < 1) paint["background-opacity"] = 1;
|
|
6402
|
+
}
|
|
6403
|
+
if (type === "circle") {
|
|
6404
|
+
const blur = paint["circle-blur"];
|
|
6405
|
+
if (typeof blur === "number" && blur >= 0.5) {
|
|
6406
|
+
paint["circle-opacity"] = 0;
|
|
6407
|
+
} else {
|
|
6408
|
+
if (blur !== void 0) paint["circle-blur"] = 0;
|
|
6409
|
+
const o = paint["circle-opacity"];
|
|
6410
|
+
if (typeof o === "number" && o > 0 && o < 1) paint["circle-opacity"] = 1;
|
|
6411
|
+
}
|
|
6412
|
+
}
|
|
6413
|
+
if (type === "symbol") {
|
|
6414
|
+
if (layout?.["text-field"] !== void 0) {
|
|
6415
|
+
if (layout["text-size"] !== void 0) {
|
|
6416
|
+
layout["text-size"] = scaleNumeric(layout["text-size"], EINK_TEXT_SCALE);
|
|
6417
|
+
}
|
|
6418
|
+
if (paint["text-opacity"] !== void 0) paint["text-opacity"] = 1;
|
|
6419
|
+
if (typeof paint["text-halo-color"] === "string") paint["text-halo-color"] = groundInk;
|
|
6420
|
+
const hw = paint["text-halo-width"];
|
|
6421
|
+
paint["text-halo-width"] = typeof hw === "number" ? Math.max(hw, EINK_HALO_MIN_PX) : hw ?? EINK_HALO_MIN_PX;
|
|
6422
|
+
if (paint["text-halo-blur"] !== void 0) paint["text-halo-blur"] = 0;
|
|
6423
|
+
}
|
|
6424
|
+
const io = paint["icon-opacity"];
|
|
6425
|
+
if (typeof io === "number" && io > 0 && io < 1) paint["icon-opacity"] = 1;
|
|
6426
|
+
if (cls && EINK_DANGER_CLASSES.has(cls) && layout?.["icon-image"] !== void 0) {
|
|
6427
|
+
layout["icon-size"] = scaleNumeric(layout["icon-size"] ?? 1, EINK_DANGER_ICON_SCALE);
|
|
6428
|
+
}
|
|
6429
|
+
}
|
|
6430
|
+
out.push(layer);
|
|
6431
|
+
if (type === "fill" && cls === "DEPARE" && mono) {
|
|
6432
|
+
const drying = ["all", ["<", DRVAL1, 0], ["<=", DRVAL2, 0]];
|
|
6433
|
+
out.push({
|
|
6434
|
+
...structuredClone(original),
|
|
6435
|
+
id: scaffoldId("chrt-eink-depth-of-", id),
|
|
6436
|
+
filter: withFilter(original.filter, ["<", DRVAL1, safety]),
|
|
6437
|
+
paint: {
|
|
6438
|
+
"fill-pattern": ["case", drying, EINK_HATCH_PATTERN, EINK_DOTS_PATTERN]
|
|
6439
|
+
}
|
|
6440
|
+
});
|
|
6441
|
+
}
|
|
6442
|
+
if (type === "line" && cls === "DEPCNT") {
|
|
6443
|
+
const isSafety = ["any", ...safetyValues.map((v) => ["<", ["abs", ["-", VALDCO, v]], 0.05])];
|
|
6444
|
+
out.push({
|
|
6445
|
+
...structuredClone(original),
|
|
6446
|
+
id: scaffoldId("chrt-eink-safety-of-", id),
|
|
6447
|
+
filter: withFilter(original.filter, isSafety),
|
|
6448
|
+
paint: {
|
|
6449
|
+
"line-color": safetyInk,
|
|
6450
|
+
"line-width": [
|
|
6451
|
+
"interpolate",
|
|
6452
|
+
["linear"],
|
|
6453
|
+
["zoom"],
|
|
6454
|
+
8,
|
|
6455
|
+
EINK_SAFETY_CONTOUR_WIDTH[0],
|
|
6456
|
+
14,
|
|
6457
|
+
EINK_SAFETY_CONTOUR_WIDTH[1]
|
|
6458
|
+
]
|
|
6459
|
+
},
|
|
6460
|
+
layout: { "line-join": "round", "line-cap": "round" }
|
|
6461
|
+
});
|
|
6462
|
+
}
|
|
6463
|
+
}
|
|
6464
|
+
return {
|
|
6465
|
+
...style,
|
|
6466
|
+
// No transitions: a property change is one repaint, never an animation.
|
|
6467
|
+
...{ transition: { duration: 0, delay: 0 } },
|
|
6468
|
+
metadata: { ...style.metadata, "chrt:eink": night ? "night" : mono ? "mono" : "color" },
|
|
6469
|
+
layers: out
|
|
6470
|
+
};
|
|
6471
|
+
}
|
|
6472
|
+
|
|
6473
|
+
// src/atlas/map-live.ts
|
|
5031
6474
|
function isMapLive(map) {
|
|
5032
6475
|
return map._removed !== true;
|
|
5033
6476
|
}
|
|
@@ -5662,248 +7105,33 @@ function lineSpriteId(lineStyleName) {
|
|
|
5662
7105
|
}
|
|
5663
7106
|
function lineStylePaint(name) {
|
|
5664
7107
|
const meta = S52_LINESTYLES[name];
|
|
5665
|
-
if (!meta) {
|
|
5666
|
-
throw new Error(
|
|
5667
|
-
`Unknown S-52 linestyle "${name}". Known: ${Object.keys(S52_LINESTYLES).length} styles (regenerate with: bun run scripts/extract-opencpn-linestyles.ts)`
|
|
5668
|
-
);
|
|
5669
|
-
}
|
|
5670
|
-
return {
|
|
5671
|
-
"line-pattern": lineSpriteId(meta.name),
|
|
5672
|
-
"line-width": houseWidth(meta)
|
|
5673
|
-
};
|
|
5674
|
-
}
|
|
5675
|
-
function lineStylePaintCase(cases, fallback) {
|
|
5676
|
-
const resolve = (name) => {
|
|
5677
|
-
const meta = S52_LINESTYLES[name];
|
|
5678
|
-
if (!meta) throw new Error(`Unknown S-52 linestyle "${name}"`);
|
|
5679
|
-
return meta;
|
|
5680
|
-
};
|
|
5681
|
-
const fallbackMeta = resolve(fallback);
|
|
5682
|
-
const pattern = ["case"];
|
|
5683
|
-
const width = ["case"];
|
|
5684
|
-
for (const [condition, name] of cases) {
|
|
5685
|
-
const meta = resolve(name);
|
|
5686
|
-
pattern.push(condition, lineSpriteId(meta.name));
|
|
5687
|
-
width.push(condition, houseWidth(meta));
|
|
5688
|
-
}
|
|
5689
|
-
pattern.push(lineSpriteId(fallbackMeta.name));
|
|
5690
|
-
width.push(houseWidth(fallbackMeta));
|
|
5691
|
-
return { "line-pattern": pattern, "line-width": width };
|
|
5692
|
-
}
|
|
5693
|
-
|
|
5694
|
-
// src/atlas/s52-pattern.ts
|
|
5695
|
-
var S52_PATTERN_SPRITE_PREFIX = "AP:";
|
|
5696
|
-
function patternSpriteId(patternName) {
|
|
5697
|
-
return `${S52_PATTERN_SPRITE_PREFIX}${patternName}`;
|
|
5698
|
-
}
|
|
5699
|
-
|
|
5700
|
-
// src/atlas/s52-conditional.ts
|
|
5701
|
-
var DEFAULT_SAFETY_CONTOUR_M = 10;
|
|
5702
|
-
var DEPARE_DEEP_CUT_M = 18.2;
|
|
5703
|
-
var DEPARE_SHALLOW_CUT_M = 2;
|
|
5704
|
-
function effectiveSafetyContour(safetyContourM) {
|
|
5705
|
-
if (!Number.isFinite(safetyContourM)) return DEFAULT_SAFETY_CONTOUR_M;
|
|
5706
|
-
return Math.min(Math.max(safetyContourM, DEPARE_SHALLOW_CUT_M), DEPARE_DEEP_CUT_M);
|
|
5707
|
-
}
|
|
5708
|
-
function depareColor(props, ct = "DAY", safetyContourM = DEFAULT_SAFETY_CONTOUR_M) {
|
|
5709
|
-
const drval1 = Number(props.DRVAL1 ?? props.drval1 ?? -1);
|
|
5710
|
-
const drval2 = Number(props.DRVAL2 ?? props.drval2 ?? drval1);
|
|
5711
|
-
const safety = effectiveSafetyContour(safetyContourM);
|
|
5712
|
-
if (drval1 < 0 && drval2 <= 0) return resolveColor("DEPIT", ct);
|
|
5713
|
-
if (drval1 < DEPARE_SHALLOW_CUT_M) return resolveColor("DEPVS", ct);
|
|
5714
|
-
if (drval1 < safety) return resolveColor("DEPMS", ct);
|
|
5715
|
-
if (drval1 < DEPARE_DEEP_CUT_M) return resolveColor("DEPMD", ct);
|
|
5716
|
-
return resolveColor("DEPDW", ct);
|
|
5717
|
-
}
|
|
5718
|
-
var DEPARE_FILL_BRANCH_TOKENS = ["DEPIT", "DEPVS", "DEPMS", "DEPMD"];
|
|
5719
|
-
var DEPARE_FILL_FALLBACK_TOKEN = "DEPDW";
|
|
5720
|
-
function depareFillExpression(ct = "DAY", safetyContourM = DEFAULT_SAFETY_CONTOUR_M) {
|
|
5721
|
-
const safety = effectiveSafetyContour(safetyContourM);
|
|
5722
|
-
const [it, vs, ms, md] = DEPARE_FILL_BRANCH_TOKENS;
|
|
5723
|
-
return [
|
|
5724
|
-
"case",
|
|
5725
|
-
[
|
|
5726
|
-
"all",
|
|
5727
|
-
["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], 0],
|
|
5728
|
-
["<=", ["coalesce", ["get", "DRVAL2"], ["get", "drval2"], 0], 0]
|
|
5729
|
-
],
|
|
5730
|
-
resolveColor(it, ct),
|
|
5731
|
-
["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], DEPARE_SHALLOW_CUT_M],
|
|
5732
|
-
resolveColor(vs, ct),
|
|
5733
|
-
["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], safety],
|
|
5734
|
-
resolveColor(ms, ct),
|
|
5735
|
-
["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], DEPARE_DEEP_CUT_M],
|
|
5736
|
-
resolveColor(md, ct),
|
|
5737
|
-
resolveColor(DEPARE_FILL_FALLBACK_TOKEN, ct)
|
|
5738
|
-
];
|
|
5739
|
-
}
|
|
5740
|
-
function listAttrString(attr) {
|
|
5741
|
-
return ["to-string", ["coalesce", ["get", attr], ["get", attr.toLowerCase()], ""]];
|
|
5742
|
-
}
|
|
5743
|
-
function listAttrCase(attr, cases, fallback) {
|
|
5744
|
-
const attrStr = listAttrString(attr);
|
|
5745
|
-
const expr = ["case"];
|
|
5746
|
-
for (const [code, value] of cases) {
|
|
5747
|
-
expr.push([">=", ["index-of", `"${code}"`, attrStr], 0], value);
|
|
5748
|
-
}
|
|
5749
|
-
for (const [code, value] of cases) {
|
|
5750
|
-
expr.push(["==", attrStr, code], value);
|
|
5751
|
-
}
|
|
5752
|
-
for (const [code, value] of cases) {
|
|
5753
|
-
expr.push(["==", attrStr, `[${code}]`], value);
|
|
5754
|
-
}
|
|
5755
|
-
expr.push(fallback);
|
|
5756
|
-
return expr;
|
|
5757
|
-
}
|
|
5758
|
-
function listAttrHas(attr, codes) {
|
|
5759
|
-
const attrStr = listAttrString(attr);
|
|
5760
|
-
const clauses = [];
|
|
5761
|
-
for (const code of codes) {
|
|
5762
|
-
clauses.push([">=", ["index-of", `"${code}"`, attrStr], 0]);
|
|
5763
|
-
clauses.push(["==", attrStr, code]);
|
|
5764
|
-
clauses.push(["==", attrStr, `[${code}]`]);
|
|
5765
|
-
}
|
|
5766
|
-
return ["any", ...clauses];
|
|
5767
|
-
}
|
|
5768
|
-
function colourCodeCase(cases, fallback) {
|
|
5769
|
-
return listAttrCase("COLOUR", cases, fallback);
|
|
5770
|
-
}
|
|
5771
|
-
function lightColor(props, ct = "DAY") {
|
|
5772
|
-
const raw = props.COLOUR ?? props.colour;
|
|
5773
|
-
const code = Array.isArray(raw) ? Number(raw[0]) : typeof raw === "string" && raw.startsWith("[") ? Number(JSON.parse(raw)[0]) : Number(raw ?? 0);
|
|
5774
|
-
switch (code) {
|
|
5775
|
-
case 1:
|
|
5776
|
-
return resolveColor("LITWT", ct);
|
|
5777
|
-
case 3:
|
|
5778
|
-
return resolveColor("LITRD", ct);
|
|
5779
|
-
case 4:
|
|
5780
|
-
return resolveColor("LITGN", ct);
|
|
5781
|
-
case 5:
|
|
5782
|
-
return resolveColor("LITBL", ct);
|
|
5783
|
-
case 6:
|
|
5784
|
-
return resolveColor("LITYW", ct);
|
|
5785
|
-
case 11:
|
|
5786
|
-
return resolveColor("LITOR", ct);
|
|
5787
|
-
default:
|
|
5788
|
-
return resolveColor("LITYW", ct);
|
|
5789
|
-
}
|
|
5790
|
-
}
|
|
5791
|
-
function lightFillExpression(ct = "DAY") {
|
|
5792
|
-
return colourCodeCase(
|
|
5793
|
-
[
|
|
5794
|
-
["3", resolveColor("LITRD", ct)],
|
|
5795
|
-
["4", resolveColor("LITGN", ct)],
|
|
5796
|
-
["6", resolveColor("LITYW", ct)],
|
|
5797
|
-
["11", resolveColor("LITOR", ct)],
|
|
5798
|
-
["5", resolveColor("LITBL", ct)],
|
|
5799
|
-
["1", resolveColor("LITWT", ct)]
|
|
5800
|
-
],
|
|
5801
|
-
resolveColor("LITYW", ct)
|
|
5802
|
-
);
|
|
5803
|
-
}
|
|
5804
|
-
function lateralColor(props, ct = "DAY") {
|
|
5805
|
-
const catlam = Number(props.CATLAM ?? props.catlam ?? 0);
|
|
5806
|
-
if (catlam === 1) return resolveColor("LITRD", ct);
|
|
5807
|
-
if (catlam === 2) return resolveColor("LITGN", ct);
|
|
5808
|
-
return resolveColor("LITYW", ct);
|
|
5809
|
-
}
|
|
5810
|
-
function lateralFillExpression(ct = "DAY") {
|
|
5811
|
-
return [
|
|
5812
|
-
"match",
|
|
5813
|
-
["coalesce", ["get", "CATLAM"], ["get", "catlam"], 0],
|
|
5814
|
-
1,
|
|
5815
|
-
resolveColor("LITRD", ct),
|
|
5816
|
-
2,
|
|
5817
|
-
resolveColor("LITGN", ct),
|
|
5818
|
-
resolveColor("LITYW", ct)
|
|
5819
|
-
];
|
|
5820
|
-
}
|
|
5821
|
-
function hazardColor(props, ct = "DAY") {
|
|
5822
|
-
const watlev = Number(props.WATLEV ?? props.watlev ?? 0);
|
|
5823
|
-
const valsou = props.VALSOU ?? props.valsou;
|
|
5824
|
-
if (watlev === 1 || watlev === 2) return resolveColor("DNGHL", ct);
|
|
5825
|
-
if (valsou != null && Number(valsou) < 2) return resolveColor("DNGHL", ct);
|
|
5826
|
-
return resolveColor("RESBL", ct);
|
|
5827
|
-
}
|
|
5828
|
-
function hazardFillExpression(ct = "DAY") {
|
|
5829
|
-
return [
|
|
5830
|
-
"case",
|
|
5831
|
-
[
|
|
5832
|
-
"any",
|
|
5833
|
-
["==", ["coalesce", ["get", "WATLEV"], ["get", "watlev"], 0], 1],
|
|
5834
|
-
["==", ["coalesce", ["get", "WATLEV"], ["get", "watlev"], 0], 2]
|
|
5835
|
-
],
|
|
5836
|
-
resolveColor("DNGHL", ct),
|
|
5837
|
-
[
|
|
5838
|
-
"all",
|
|
5839
|
-
["has", "VALSOU"],
|
|
5840
|
-
["<", ["get", "VALSOU"], 2]
|
|
5841
|
-
],
|
|
5842
|
-
resolveColor("DNGHL", ct),
|
|
5843
|
-
resolveColor("RESBL", ct)
|
|
5844
|
-
];
|
|
5845
|
-
}
|
|
5846
|
-
function vegatnPatternExpression() {
|
|
5847
|
-
return [
|
|
5848
|
-
"match",
|
|
5849
|
-
["coalesce", ["get", "CATVEG"], ["get", "catveg"], 0],
|
|
5850
|
-
1,
|
|
5851
|
-
patternSpriteId("VEGATN03"),
|
|
5852
|
-
// grass
|
|
5853
|
-
3,
|
|
5854
|
-
patternSpriteId("VEGATN03"),
|
|
5855
|
-
// bush
|
|
5856
|
-
4,
|
|
5857
|
-
patternSpriteId("VEGATN04"),
|
|
5858
|
-
// deciduous wood
|
|
5859
|
-
5,
|
|
5860
|
-
patternSpriteId("VEGATN04"),
|
|
5861
|
-
// coniferous wood
|
|
5862
|
-
6,
|
|
5863
|
-
patternSpriteId("VEGATN04"),
|
|
5864
|
-
// wood (mixed)
|
|
5865
|
-
7,
|
|
5866
|
-
patternSpriteId("MARSHES1"),
|
|
5867
|
-
// mangroves
|
|
5868
|
-
10,
|
|
5869
|
-
patternSpriteId("VEGATN03"),
|
|
5870
|
-
// scrub
|
|
5871
|
-
11,
|
|
5872
|
-
patternSpriteId("VEGATN04"),
|
|
5873
|
-
// tree
|
|
5874
|
-
12,
|
|
5875
|
-
patternSpriteId("VEGATN04"),
|
|
5876
|
-
// evergreen
|
|
5877
|
-
16,
|
|
5878
|
-
patternSpriteId("MARSHES1"),
|
|
5879
|
-
// swamp
|
|
5880
|
-
17,
|
|
5881
|
-
patternSpriteId("MARSHES1"),
|
|
5882
|
-
// marsh
|
|
5883
|
-
21,
|
|
5884
|
-
patternSpriteId("VEGATN04"),
|
|
5885
|
-
// savannah
|
|
5886
|
-
patternSpriteId("VEGATN03")
|
|
5887
|
-
// default: grass pattern
|
|
5888
|
-
];
|
|
5889
|
-
}
|
|
5890
|
-
function daymarkColor(props, ct = "DAY") {
|
|
5891
|
-
const raw = props.COLOUR ?? props.colour;
|
|
5892
|
-
const code = Array.isArray(raw) ? Number(raw[0]) : typeof raw === "string" && raw.startsWith("[") ? Number(JSON.parse(raw)[0]) : Number(raw ?? 0);
|
|
5893
|
-
switch (code) {
|
|
5894
|
-
case 1:
|
|
5895
|
-
return resolveColor("LITWT", ct);
|
|
5896
|
-
case 3:
|
|
5897
|
-
return resolveColor("LITRD", ct);
|
|
5898
|
-
case 4:
|
|
5899
|
-
return resolveColor("LITGN", ct);
|
|
5900
|
-
case 6:
|
|
5901
|
-
return resolveColor("LITYW", ct);
|
|
5902
|
-
case 11:
|
|
5903
|
-
return resolveColor("LITOR", ct);
|
|
5904
|
-
default:
|
|
5905
|
-
return resolveColor("LITGN", ct);
|
|
7108
|
+
if (!meta) {
|
|
7109
|
+
throw new Error(
|
|
7110
|
+
`Unknown S-52 linestyle "${name}". Known: ${Object.keys(S52_LINESTYLES).length} styles (regenerate with: bun run scripts/extract-opencpn-linestyles.ts)`
|
|
7111
|
+
);
|
|
7112
|
+
}
|
|
7113
|
+
return {
|
|
7114
|
+
"line-pattern": lineSpriteId(meta.name),
|
|
7115
|
+
"line-width": houseWidth(meta)
|
|
7116
|
+
};
|
|
7117
|
+
}
|
|
7118
|
+
function lineStylePaintCase(cases, fallback) {
|
|
7119
|
+
const resolve = (name) => {
|
|
7120
|
+
const meta = S52_LINESTYLES[name];
|
|
7121
|
+
if (!meta) throw new Error(`Unknown S-52 linestyle "${name}"`);
|
|
7122
|
+
return meta;
|
|
7123
|
+
};
|
|
7124
|
+
const fallbackMeta = resolve(fallback);
|
|
7125
|
+
const pattern = ["case"];
|
|
7126
|
+
const width = ["case"];
|
|
7127
|
+
for (const [condition, name] of cases) {
|
|
7128
|
+
const meta = resolve(name);
|
|
7129
|
+
pattern.push(condition, lineSpriteId(meta.name));
|
|
7130
|
+
width.push(condition, houseWidth(meta));
|
|
5906
7131
|
}
|
|
7132
|
+
pattern.push(lineSpriteId(fallbackMeta.name));
|
|
7133
|
+
width.push(houseWidth(fallbackMeta));
|
|
7134
|
+
return { "line-pattern": pattern, "line-width": width };
|
|
5907
7135
|
}
|
|
5908
7136
|
|
|
5909
7137
|
// src/atlas/s52-lookup.ts
|
|
@@ -19796,9 +21024,9 @@ function compileAtonExpression(lookup, mapSymbol = (name) => name) {
|
|
|
19796
21024
|
expr.push(fallback);
|
|
19797
21025
|
return expr;
|
|
19798
21026
|
}
|
|
19799
|
-
function atonIconExpression(
|
|
19800
|
-
const lookup = S52_ATON_LOOKUPS[
|
|
19801
|
-
if (!lookup) throw new Error(`s52-aton-expressions: no generated lookup for ${
|
|
21027
|
+
function atonIconExpression(objectClass2) {
|
|
21028
|
+
const lookup = S52_ATON_LOOKUPS[objectClass2];
|
|
21029
|
+
if (!lookup) throw new Error(`s52-aton-expressions: no generated lookup for ${objectClass2}`);
|
|
19802
21030
|
return compileAtonExpression(lookup);
|
|
19803
21031
|
}
|
|
19804
21032
|
function lightsIconExpression() {
|
|
@@ -22883,7 +24111,9 @@ var LABEL_TINT = {
|
|
|
22883
24111
|
};
|
|
22884
24112
|
function tintFor(tint, ct) {
|
|
22885
24113
|
const day = LABEL_TINT[tint].day;
|
|
22886
|
-
if (ct === "DAY") return day;
|
|
24114
|
+
if (ct === "DAY" || ct === "EINK_COLOR") return day;
|
|
24115
|
+
if (ct === "EINK_MONO") return einkMonoGrey(day);
|
|
24116
|
+
if (ct === "EINK_NIGHT") return einkNightGrey(day);
|
|
22887
24117
|
return capLuminance(day, relativeLuminance(resolveColor("CHBLK", ct)));
|
|
22888
24118
|
}
|
|
22889
24119
|
function nightText(tint) {
|
|
@@ -22894,10 +24124,14 @@ function nightText(tint) {
|
|
|
22894
24124
|
}
|
|
22895
24125
|
function onHalo(tint, ct) {
|
|
22896
24126
|
if (ct === "NIGHT") return { textColor: nightText(tint), textHaloColor: NIGHT_KNOCKOUT };
|
|
24127
|
+
if (ct === "EINK_NIGHT") return { textColor: EINK_MONO_GREYS.MID, textHaloColor: EINK_MONO_GREYS.INK };
|
|
24128
|
+
if (isEinkColorTable(ct)) return { textColor: EINK_MONO_GREYS.INK, textHaloColor: EINK_MONO_GREYS.PAPER };
|
|
22897
24129
|
return { textColor: DARK_BG, textHaloColor: tintFor(tint, ct) };
|
|
22898
24130
|
}
|
|
22899
24131
|
function onKnockout(tint, ct) {
|
|
22900
24132
|
if (ct === "NIGHT") return { textColor: nightText(tint), textHaloColor: NIGHT_KNOCKOUT };
|
|
24133
|
+
if (ct === "EINK_NIGHT") return { textColor: EINK_MONO_GREYS.MID, textHaloColor: EINK_MONO_GREYS.INK };
|
|
24134
|
+
if (isEinkColorTable(ct)) return { textColor: EINK_MONO_GREYS.INK, textHaloColor: EINK_MONO_GREYS.PAPER };
|
|
22901
24135
|
return { textColor: tintFor(tint, ct), textHaloColor: DARK_BG };
|
|
22902
24136
|
}
|
|
22903
24137
|
var NAV_AID_LABEL_TEXT_SIZE = [
|
|
@@ -27114,10 +28348,20 @@ var S101_NO_OFFICIAL_COUNTERPART = /* @__PURE__ */ new Set([
|
|
|
27114
28348
|
"SISTAT02",
|
|
27115
28349
|
"WATTUR01"
|
|
27116
28350
|
]);
|
|
28351
|
+
function s101EinkTable(einkS52, fallback) {
|
|
28352
|
+
const out = {};
|
|
28353
|
+
for (const [token, dayHex] of Object.entries(S101_DAY)) {
|
|
28354
|
+
out[token] = einkS52[token] ?? fallback(dayHex);
|
|
28355
|
+
}
|
|
28356
|
+
return out;
|
|
28357
|
+
}
|
|
27117
28358
|
var S101_TABLES = {
|
|
27118
28359
|
DAY: S101_DAY,
|
|
27119
28360
|
DUSK: S101_DUSK,
|
|
27120
|
-
NIGHT: S101_NIGHT
|
|
28361
|
+
NIGHT: S101_NIGHT,
|
|
28362
|
+
EINK_COLOR: s101EinkTable(S52_EINK_COLOR, (hex) => hex),
|
|
28363
|
+
EINK_MONO: s101EinkTable(S52_EINK_MONO, einkMonoGrey),
|
|
28364
|
+
EINK_NIGHT: s101EinkTable(S52_EINK_NIGHT, einkNightGrey)
|
|
27121
28365
|
};
|
|
27122
28366
|
var warnedTokens = /* @__PURE__ */ new Set();
|
|
27123
28367
|
function reportUnresolvedToken(token, table) {
|
|
@@ -27164,328 +28408,54 @@ function rewritePatternToS101(node, available) {
|
|
|
27164
28408
|
if (typeof node === "string") {
|
|
27165
28409
|
return available.has(node) ? `${S101_ICON_PREFIX}${node}` : node;
|
|
27166
28410
|
}
|
|
27167
|
-
if (Array.isArray(node)) return node.map((n) => rewritePatternToS101(n, available));
|
|
27168
|
-
return node;
|
|
27169
|
-
}
|
|
27170
|
-
function collectLiterals(node, out) {
|
|
27171
|
-
if (typeof node === "string") {
|
|
27172
|
-
out.add(node);
|
|
27173
|
-
return;
|
|
27174
|
-
}
|
|
27175
|
-
if (Array.isArray(node)) for (const n of node) collectLiterals(n, out);
|
|
27176
|
-
}
|
|
27177
|
-
function applyS101SymbolSet(style) {
|
|
27178
|
-
const seen = { icon: /* @__PURE__ */ new Set(), fill: /* @__PURE__ */ new Set(), line: /* @__PURE__ */ new Set() };
|
|
27179
|
-
for (const layer of style.layers) {
|
|
27180
|
-
const layout = layer.layout;
|
|
27181
|
-
const paint = layer.paint;
|
|
27182
|
-
if (layer.type === "symbol" && layout && layout["icon-image"] != null) {
|
|
27183
|
-
layout["icon-image"] = rewriteIconToS101(layout["icon-image"]);
|
|
27184
|
-
collectLiterals(layout["icon-image"], seen.icon);
|
|
27185
|
-
}
|
|
27186
|
-
for (const bag of [layout, paint]) {
|
|
27187
|
-
if (!bag) continue;
|
|
27188
|
-
if (bag["fill-pattern"] != null) {
|
|
27189
|
-
bag["fill-pattern"] = rewritePatternToS101(bag["fill-pattern"], S101_AREA_FILL_NAMES);
|
|
27190
|
-
collectLiterals(bag["fill-pattern"], seen.fill);
|
|
27191
|
-
}
|
|
27192
|
-
if (bag["line-pattern"] != null) {
|
|
27193
|
-
bag["line-pattern"] = rewritePatternToS101(bag["line-pattern"], S101_LINE_STYLE_NAMES);
|
|
27194
|
-
collectLiterals(bag["line-pattern"], seen.line);
|
|
27195
|
-
}
|
|
27196
|
-
}
|
|
27197
|
-
}
|
|
27198
|
-
const official = (names) => [...names].filter((n) => n.startsWith(S101_ICON_PREFIX)).length;
|
|
27199
|
-
const iconSubs = [...seen.icon].filter((n) => S101_NO_OFFICIAL_COUNTERPART.has(n)).length;
|
|
27200
|
-
const patternSubs = (names) => [...names].filter((n) => /^(AP|LC):/.test(n)).length;
|
|
27201
|
-
const coverage = {
|
|
27202
|
-
pointSymbols: { official: official(seen.icon), s52Substitute: iconSubs },
|
|
27203
|
-
areaFills: { official: official(seen.fill), s52Substitute: patternSubs(seen.fill) },
|
|
27204
|
-
lineStyles: { official: official(seen.line), s52Substitute: patternSubs(seen.line) }
|
|
27205
|
-
};
|
|
27206
|
-
const metadata = style.metadata;
|
|
27207
|
-
metadata["chrt:symbol-set"] = "s101";
|
|
27208
|
-
metadata["chrt:s101-source-commit"] = S101_SOURCE_COMMIT;
|
|
27209
|
-
metadata["chrt:s101-coverage"] = {
|
|
27210
|
-
...coverage,
|
|
27211
|
-
/** True only when NOTHING in this document is an S-52 substitute. A
|
|
27212
|
-
* consumer that wants "S-101 or nothing" branches on this one boolean. */
|
|
27213
|
-
complete: Object.values(coverage).every((c) => c.s52Substitute === 0)
|
|
27214
|
-
};
|
|
27215
|
-
return style;
|
|
27216
|
-
}
|
|
27217
|
-
|
|
27218
|
-
// src/atlas/chrt-svgs-generated.ts
|
|
27219
|
-
var CHRT_GLYPH_SVGS = {
|
|
27220
|
-
"badge-radar": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="19" r="2.6" fill="#D200D2"/><path d="M9 19a7 7 0 0 1 14 0M5 19a11 11 0 0 1 22 0" stroke="#D200D2" stroke-width="2.4" fill="none" stroke-linecap="round" stroke-dasharray="4 3"/></svg>',
|
|
27221
|
-
"badge-sound": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="7" cy="16" r="2.2" fill="#D200D2"/><path d="M12 10a9 9 0 0 1 0 12M16.5 6.5a15 15 0 0 1 0 19M21 3a21 21 0 0 1 0 26" stroke="#D200D2" stroke-width="2.4" fill="none" stroke-linecap="round"/></svg>',
|
|
27222
|
-
"beacon-cairn": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="11" r="4" fill="#fff"/><circle cx="11.5" cy="19" r="4.6" fill="#fff"/><circle cx="20.5" cy="19" r="4.6" fill="#fff"/><path d="M7 28h18" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27223
|
-
"beacon-generic": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 25V12" stroke="#fff" stroke-width="2.6" stroke-linecap="round"/><path d="M16 4l6 8H10Z" fill="#fff"/><path d="M8 28h16M11 25h10" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27224
|
-
"beacon-lattice": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M11 25 13 6h6l2 19M12 20h8M12.6 13h6.8M11 25l9-12M21 25l-9-12" stroke="#fff" stroke-width="1.8" stroke-linecap="round" fill="none"/><path d="M8 28h16" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27225
|
-
"beacon-stake": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 25V6" stroke="#fff" stroke-width="2.8" stroke-linecap="round"/><path d="M9 28h14" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27226
|
-
"beacon-tower": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M12 6h8l1.6 19H10.4Z" fill="#fff"/><path d="M10 6h12" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/><path d="M8 28h16" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27227
|
-
"buoy-barrel": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><rect x="7" y="13" width="18" height="11" rx="5.5" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27228
|
-
"buoy-can": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M9 12h14v11a2 2 0 0 1-2 2H11a2 2 0 0 1-2-2Z" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27229
|
-
"buoy-conical": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 8 24.5 25H7.5Z" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27230
|
-
"buoy-pillar": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M13 6h6l1.4 19H11.6Z" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27231
|
-
"buoy-spar": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M14.5 5h3l1 20h-5Z" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27232
|
-
"buoy-spherical": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="17.5" r="8.5" fill="#fff"/><path d="M6 28h20" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27233
|
-
"buoy-super": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M7 17h18l-2.5 8h-13Z" fill="#fff"/><path d="M16 17V8" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/><circle cx="16" cy="6.5" r="2" fill="#fff"/><path d="M5 28h22" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27234
|
-
"cardinal-e": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 1.5 20 6h-8Z" fill="#101418"/><path d="M16 11 12 6.5h8Z" fill="#101418"/><path d="M13 12h6l1 13H12Z" fill="#FFC805"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27235
|
-
"cardinal-n": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 1.5 20 6h-8Z" fill="#101418"/><path d="M16 6.5 20 11h-8Z" fill="#101418"/><path d="M13 12h6l1 13H12Z" fill="#FFC805"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27236
|
-
"cardinal-s": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 11 12 6.5h8Z" fill="#101418"/><path d="M16 6 12 1.5h8Z" fill="#101418"/><path d="M13 12h6l1 13H12Z" fill="#FFC805"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27237
|
-
"cardinal-w": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 6 12 1.5h8Z" fill="#101418"/><path d="M16 6.5 20 11h-8Z" fill="#101418"/><path d="M13 12h6l1 13H12Z" fill="#FFC805"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27238
|
-
"daymark-square": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><rect x="6" y="6" width="20" height="20" rx="1.5" fill="#fff"/></svg>',
|
|
27239
|
-
"daymark-triangle": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 5 28 26H4Z" fill="#fff"/></svg>',
|
|
27240
|
-
"hatch-nocoverage": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M-3 9 L9 -3 M-3 21 L21 -3 M3 27 L27 3 M15 27 L27 15" stroke="#8A97A0" stroke-width="0.8" fill="none"/><path d="M-3 15 L15 33 M-3 3 L21 27 M3 -3 L27 21 M15 -3 L27 9" stroke="#8A97A0" stroke-width="0.8" fill="none"/></svg>',
|
|
27241
|
-
"hatch-uncharted": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M-3 9 L9 -3 M-3 21 L21 -3 M3 27 L27 3 M15 27 L27 15" stroke="#5B7383" stroke-width="0.65" fill="none"/></svg>',
|
|
27242
|
-
"isolated-danger": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="3.5" r="2.4" fill="#101418"/><circle cx="16" cy="9.5" r="2.4" fill="#101418"/><path d="M13 13h6l1 12H12Z" fill="#101418"/><rect x="12.4" y="17.5" width="7.2" height="3.4" fill="#E5484D"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27243
|
-
"light-flare": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="11" cy="11" r="3.2" fill="#fff"/><path d="M13.4 13.4 24 19.5a2.6 2.6 0 0 1-4.5 4.5L13.4 13.4Z" fill="#fff"/></svg>',
|
|
27244
|
-
"lightship": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M6 20l3-5h14l3 5-3.5 4h-13Z" fill="#fff"/><path d="M16 15V8" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/><circle cx="16" cy="6" r="2.2" fill="#fff"/><path d="M5 28h22" stroke="#fff" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
27245
|
-
"safe-water": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="6" r="2.4" fill="#E5484D"/><circle cx="16" cy="17.5" r="8" fill="#F8FAFC"/><path d="M12.2 10.5a8 8 0 0 0 0 14M19.8 10.5a8 8 0 0 1 0 14" stroke="#E5484D" stroke-width="3" fill="none"/><path d="M6 28h20" stroke="#101418" stroke-width="2.4" stroke-linecap="round"/></svg>'
|
|
27246
|
-
};
|
|
27247
|
-
|
|
27248
|
-
// src/atlas/chrt-style.ts
|
|
27249
|
-
var CHRT_ICON_PREFIX = "chrt:";
|
|
27250
|
-
var CHRT_SDF_GLYPHS = /* @__PURE__ */ new Set([
|
|
27251
|
-
"buoy-can",
|
|
27252
|
-
"buoy-conical",
|
|
27253
|
-
"buoy-spherical",
|
|
27254
|
-
"buoy-pillar",
|
|
27255
|
-
"buoy-spar",
|
|
27256
|
-
"buoy-barrel",
|
|
27257
|
-
"buoy-super",
|
|
27258
|
-
"beacon-generic",
|
|
27259
|
-
"beacon-tower",
|
|
27260
|
-
"beacon-lattice",
|
|
27261
|
-
"beacon-stake",
|
|
27262
|
-
"beacon-cairn",
|
|
27263
|
-
"light-flare",
|
|
27264
|
-
"lightship",
|
|
27265
|
-
"daymark-triangle",
|
|
27266
|
-
"daymark-square"
|
|
27267
|
-
]);
|
|
27268
|
-
var CHRT_GLYPH_NAMES = new Set(Object.keys(CHRT_GLYPH_SVGS));
|
|
27269
|
-
var CHRT_ATON_COLORS = {
|
|
27270
|
-
"1": "#F8FAFC",
|
|
27271
|
-
// white
|
|
27272
|
-
"2": "#101418",
|
|
27273
|
-
// black
|
|
27274
|
-
"3": "#E5484D",
|
|
27275
|
-
// red
|
|
27276
|
-
"4": "#30A46C",
|
|
27277
|
-
// green
|
|
27278
|
-
"5": "#3E63DD",
|
|
27279
|
-
// blue
|
|
27280
|
-
"6": "#FFC805",
|
|
27281
|
-
// yellow
|
|
27282
|
-
"7": "#8B9298",
|
|
27283
|
-
// grey
|
|
27284
|
-
"8": "#A66B3A",
|
|
27285
|
-
// brown
|
|
27286
|
-
"9": "#FFB224",
|
|
27287
|
-
// amber
|
|
27288
|
-
"10": "#7E4CCB",
|
|
27289
|
-
// violet
|
|
27290
|
-
"11": "#F76B15",
|
|
27291
|
-
// orange
|
|
27292
|
-
"12": "#D671C1"
|
|
27293
|
-
// pink (magenta-ish)
|
|
27294
|
-
};
|
|
27295
|
-
var CHRT_UNKNOWN_TINT = "#8B9298";
|
|
27296
|
-
var HOUSE_BLACK = "#101418";
|
|
27297
|
-
function chrtHouseColor(dayHex, palette = "DAY") {
|
|
27298
|
-
if (palette === "DAY") return dayHex;
|
|
27299
|
-
const isBlack = dayHex.toLowerCase() === HOUSE_BLACK.toLowerCase();
|
|
27300
|
-
if (palette === "DUSK") {
|
|
27301
|
-
return isBlack ? dayHex : capLuminance(dayHex, relativeLuminance(resolveColor("CHBLK", "DUSK")));
|
|
27302
|
-
}
|
|
27303
|
-
return isBlack ? NIGHT_INK : capLuminance(dayHex, relativeLuminance(NIGHT_MUTED_INK));
|
|
27304
|
-
}
|
|
27305
|
-
function themeChrtGlyph(svg3, palette = "DAY") {
|
|
27306
|
-
if (palette === "DAY") return svg3;
|
|
27307
|
-
return svg3.replace(
|
|
27308
|
-
/(fill|stroke)="(#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6})"/g,
|
|
27309
|
-
(_m, attr, hex) => {
|
|
27310
|
-
const six = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
|
|
27311
|
-
return `${attr}="${chrtHouseColor(six, palette)}"`;
|
|
27312
|
-
}
|
|
27313
|
-
);
|
|
27314
|
-
}
|
|
27315
|
-
function chrtAtonTintExpression(palette = "DAY") {
|
|
27316
|
-
const c = (code) => chrtHouseColor(CHRT_ATON_COLORS[code], palette);
|
|
27317
|
-
return colourCodeCase(
|
|
27318
|
-
[
|
|
27319
|
-
["3", c("3")],
|
|
27320
|
-
["4", c("4")],
|
|
27321
|
-
["6", c("6")],
|
|
27322
|
-
["11", c("11")],
|
|
27323
|
-
["9", c("9")],
|
|
27324
|
-
["5", c("5")],
|
|
27325
|
-
["1", c("1")],
|
|
27326
|
-
["2", c("2")],
|
|
27327
|
-
["8", c("8")],
|
|
27328
|
-
["10", c("10")],
|
|
27329
|
-
["12", c("12")],
|
|
27330
|
-
["7", c("7")]
|
|
27331
|
-
],
|
|
27332
|
-
chrtHouseColor(CHRT_UNKNOWN_TINT, palette)
|
|
27333
|
-
);
|
|
27334
|
-
}
|
|
27335
|
-
function chrtLightTintExpression(palette = "DAY") {
|
|
27336
|
-
const c = (code) => chrtHouseColor(CHRT_ATON_COLORS[code], palette);
|
|
27337
|
-
return colourCodeCase(
|
|
27338
|
-
[
|
|
27339
|
-
["3", c("3")],
|
|
27340
|
-
["4", c("4")],
|
|
27341
|
-
["6", c("6")],
|
|
27342
|
-
["11", c("11")],
|
|
27343
|
-
["9", c("9")],
|
|
27344
|
-
["5", c("5")],
|
|
27345
|
-
["1", c("1")]
|
|
27346
|
-
],
|
|
27347
|
-
c("1")
|
|
27348
|
-
);
|
|
27349
|
-
}
|
|
27350
|
-
function scalar(attr) {
|
|
27351
|
-
return ["coalesce", ["get", attr], ["get", attr.toLowerCase()], 0];
|
|
27352
|
-
}
|
|
27353
|
-
var g = (name) => `${CHRT_ICON_PREFIX}${name}`;
|
|
27354
|
-
function buoyBodyExpression() {
|
|
27355
|
-
return [
|
|
27356
|
-
"match",
|
|
27357
|
-
scalar("BOYSHP"),
|
|
27358
|
-
1,
|
|
27359
|
-
g("buoy-conical"),
|
|
27360
|
-
2,
|
|
27361
|
-
g("buoy-can"),
|
|
27362
|
-
3,
|
|
27363
|
-
g("buoy-spherical"),
|
|
27364
|
-
4,
|
|
27365
|
-
g("buoy-pillar"),
|
|
27366
|
-
5,
|
|
27367
|
-
g("buoy-spar"),
|
|
27368
|
-
6,
|
|
27369
|
-
g("buoy-barrel"),
|
|
27370
|
-
7,
|
|
27371
|
-
g("buoy-super"),
|
|
27372
|
-
8,
|
|
27373
|
-
g("buoy-super"),
|
|
27374
|
-
g("buoy-pillar")
|
|
27375
|
-
];
|
|
27376
|
-
}
|
|
27377
|
-
function beaconBodyExpression() {
|
|
27378
|
-
return [
|
|
27379
|
-
"match",
|
|
27380
|
-
scalar("BCNSHP"),
|
|
27381
|
-
1,
|
|
27382
|
-
g("beacon-stake"),
|
|
27383
|
-
2,
|
|
27384
|
-
g("beacon-stake"),
|
|
27385
|
-
3,
|
|
27386
|
-
g("beacon-tower"),
|
|
27387
|
-
4,
|
|
27388
|
-
g("beacon-lattice"),
|
|
27389
|
-
5,
|
|
27390
|
-
g("beacon-stake"),
|
|
27391
|
-
6,
|
|
27392
|
-
g("beacon-cairn"),
|
|
27393
|
-
g("beacon-generic")
|
|
27394
|
-
];
|
|
28411
|
+
if (Array.isArray(node)) return node.map((n) => rewritePatternToS101(n, available));
|
|
28412
|
+
return node;
|
|
27395
28413
|
}
|
|
27396
|
-
function
|
|
27397
|
-
|
|
27398
|
-
|
|
27399
|
-
|
|
27400
|
-
|
|
27401
|
-
|
|
27402
|
-
2,
|
|
27403
|
-
g("cardinal-e"),
|
|
27404
|
-
3,
|
|
27405
|
-
g("cardinal-s"),
|
|
27406
|
-
4,
|
|
27407
|
-
g("cardinal-w"),
|
|
27408
|
-
g("cardinal-n")
|
|
27409
|
-
];
|
|
28414
|
+
function collectLiterals(node, out) {
|
|
28415
|
+
if (typeof node === "string") {
|
|
28416
|
+
out.add(node);
|
|
28417
|
+
return;
|
|
28418
|
+
}
|
|
28419
|
+
if (Array.isArray(node)) for (const n of node) collectLiterals(n, out);
|
|
27410
28420
|
}
|
|
27411
|
-
|
|
27412
|
-
|
|
27413
|
-
BOYSPP: buoyBodyExpression,
|
|
27414
|
-
BOYINB: buoyBodyExpression,
|
|
27415
|
-
BOYCAR: cardinalExpression,
|
|
27416
|
-
BOYISD: () => g("isolated-danger"),
|
|
27417
|
-
BOYSAW: () => g("safe-water"),
|
|
27418
|
-
BCNLAT: beaconBodyExpression,
|
|
27419
|
-
BCNSPP: beaconBodyExpression,
|
|
27420
|
-
BCNCAR: cardinalExpression,
|
|
27421
|
-
BCNISD: () => g("isolated-danger"),
|
|
27422
|
-
BCNSAW: () => g("safe-water"),
|
|
27423
|
-
LIGHTS: () => g("light-flare"),
|
|
27424
|
-
LITFLT: () => g("lightship"),
|
|
27425
|
-
LITVES: () => g("lightship"),
|
|
27426
|
-
FOGSIG: () => g("badge-sound"),
|
|
27427
|
-
RTPBCN: () => g("badge-radar"),
|
|
27428
|
-
RDOSTA: () => g("badge-radar"),
|
|
27429
|
-
DAYMAR: () => [
|
|
27430
|
-
"match",
|
|
27431
|
-
scalar("TOPSHP"),
|
|
27432
|
-
1,
|
|
27433
|
-
g("daymark-triangle"),
|
|
27434
|
-
2,
|
|
27435
|
-
g("daymark-triangle"),
|
|
27436
|
-
5,
|
|
27437
|
-
g("daymark-triangle"),
|
|
27438
|
-
g("daymark-square")
|
|
27439
|
-
]
|
|
27440
|
-
};
|
|
27441
|
-
var TINTED_CLASSES = /* @__PURE__ */ new Set([
|
|
27442
|
-
"BOYLAT",
|
|
27443
|
-
"BOYSPP",
|
|
27444
|
-
"BOYINB",
|
|
27445
|
-
"BCNLAT",
|
|
27446
|
-
"BCNSPP",
|
|
27447
|
-
"DAYMAR"
|
|
27448
|
-
]);
|
|
27449
|
-
var CHRT_HALO = { color: HOUSE_BLACK, width: 1 };
|
|
27450
|
-
var CHRT_LINE_DASH = {
|
|
27451
|
-
CBLSUB: { color: "CHMGD", width: 0.8, dash: [6, 3] },
|
|
27452
|
-
PIPSOL: { color: "PIPLN", width: 0.8, dash: [6, 3] }
|
|
27453
|
-
};
|
|
27454
|
-
function applyChrtSymbolSet(style, palette = "DAY") {
|
|
28421
|
+
function applyS101SymbolSet(style) {
|
|
28422
|
+
const seen = { icon: /* @__PURE__ */ new Set(), fill: /* @__PURE__ */ new Set(), line: /* @__PURE__ */ new Set() };
|
|
27455
28423
|
for (const layer of style.layers) {
|
|
27456
|
-
if (layer.type === "line") {
|
|
27457
|
-
const cls = layer.metadata?.["s52:objectClass"];
|
|
27458
|
-
const dash = cls ? CHRT_LINE_DASH[cls] : void 0;
|
|
27459
|
-
const paint2 = layer.paint ?? {};
|
|
27460
|
-
if (dash && paint2["line-pattern"] != null) {
|
|
27461
|
-
delete paint2["line-pattern"];
|
|
27462
|
-
paint2["line-color"] = resolveColor(dash.color, palette);
|
|
27463
|
-
paint2["line-width"] = dash.width;
|
|
27464
|
-
paint2["line-dasharray"] = dash.dash;
|
|
27465
|
-
layer.paint = paint2;
|
|
27466
|
-
}
|
|
27467
|
-
continue;
|
|
27468
|
-
}
|
|
27469
|
-
if (layer.type !== "symbol") continue;
|
|
27470
|
-
const objectClass = layer.metadata?.["s52:objectClass"];
|
|
27471
|
-
if (!objectClass || !CHRT_ICON_EXPRESSIONS[objectClass]) continue;
|
|
27472
28424
|
const layout = layer.layout;
|
|
27473
|
-
|
|
27474
|
-
layout["icon-image"]
|
|
27475
|
-
|
|
27476
|
-
|
|
27477
|
-
|
|
27478
|
-
|
|
27479
|
-
|
|
27480
|
-
|
|
27481
|
-
|
|
27482
|
-
|
|
27483
|
-
|
|
28425
|
+
const paint = layer.paint;
|
|
28426
|
+
if (layer.type === "symbol" && layout && layout["icon-image"] != null) {
|
|
28427
|
+
layout["icon-image"] = rewriteIconToS101(layout["icon-image"]);
|
|
28428
|
+
collectLiterals(layout["icon-image"], seen.icon);
|
|
28429
|
+
}
|
|
28430
|
+
for (const bag of [layout, paint]) {
|
|
28431
|
+
if (!bag) continue;
|
|
28432
|
+
if (bag["fill-pattern"] != null) {
|
|
28433
|
+
bag["fill-pattern"] = rewritePatternToS101(bag["fill-pattern"], S101_AREA_FILL_NAMES);
|
|
28434
|
+
collectLiterals(bag["fill-pattern"], seen.fill);
|
|
28435
|
+
}
|
|
28436
|
+
if (bag["line-pattern"] != null) {
|
|
28437
|
+
bag["line-pattern"] = rewritePatternToS101(bag["line-pattern"], S101_LINE_STYLE_NAMES);
|
|
28438
|
+
collectLiterals(bag["line-pattern"], seen.line);
|
|
28439
|
+
}
|
|
27484
28440
|
}
|
|
27485
|
-
layer.paint = paint;
|
|
27486
28441
|
}
|
|
28442
|
+
const official = (names) => [...names].filter((n) => n.startsWith(S101_ICON_PREFIX)).length;
|
|
28443
|
+
const iconSubs = [...seen.icon].filter((n) => S101_NO_OFFICIAL_COUNTERPART.has(n)).length;
|
|
28444
|
+
const patternSubs = (names) => [...names].filter((n) => /^(AP|LC):/.test(n)).length;
|
|
28445
|
+
const coverage = {
|
|
28446
|
+
pointSymbols: { official: official(seen.icon), s52Substitute: iconSubs },
|
|
28447
|
+
areaFills: { official: official(seen.fill), s52Substitute: patternSubs(seen.fill) },
|
|
28448
|
+
lineStyles: { official: official(seen.line), s52Substitute: patternSubs(seen.line) }
|
|
28449
|
+
};
|
|
27487
28450
|
const metadata = style.metadata;
|
|
27488
|
-
metadata["chrt:symbol-set"] = "
|
|
28451
|
+
metadata["chrt:symbol-set"] = "s101";
|
|
28452
|
+
metadata["chrt:s101-source-commit"] = S101_SOURCE_COMMIT;
|
|
28453
|
+
metadata["chrt:s101-coverage"] = {
|
|
28454
|
+
...coverage,
|
|
28455
|
+
/** True only when NOTHING in this document is an S-52 substitute. A
|
|
28456
|
+
* consumer that wants "S-101 or nothing" branches on this one boolean. */
|
|
28457
|
+
complete: Object.values(coverage).every((c) => c.s52Substitute === 0)
|
|
28458
|
+
};
|
|
27489
28459
|
return style;
|
|
27490
28460
|
}
|
|
27491
28461
|
|
|
@@ -27642,9 +28612,9 @@ var RASTER_ATON_CLASSES = Object.keys(
|
|
|
27642
28612
|
if (!s52) return true;
|
|
27643
28613
|
return JSON.stringify({ r: paper.rows, d: paper.defaultSymbol }) !== JSON.stringify({ r: s52.rows, d: s52.defaultSymbol });
|
|
27644
28614
|
});
|
|
27645
|
-
function rasterAtonIconExpression(
|
|
27646
|
-
const lookup = S52_ATON_LOOKUPS_PAPER[
|
|
27647
|
-
if (!lookup) throw new Error(`raster-style: no paper lookup for ${
|
|
28615
|
+
function rasterAtonIconExpression(objectClass2) {
|
|
28616
|
+
const lookup = S52_ATON_LOOKUPS_PAPER[objectClass2];
|
|
28617
|
+
if (!lookup) throw new Error(`raster-style: no paper lookup for ${objectClass2}`);
|
|
27648
28618
|
return compileAtonExpression(lookup, resolveRasterImage);
|
|
27649
28619
|
}
|
|
27650
28620
|
function getRasterSvg(name, table = "DAY") {
|
|
@@ -27658,9 +28628,9 @@ function applyRasterSymbolSet(style) {
|
|
|
27658
28628
|
const layout = layer.layout;
|
|
27659
28629
|
if (!layout || layout["icon-image"] == null) continue;
|
|
27660
28630
|
const metadata2 = layer.metadata;
|
|
27661
|
-
const
|
|
27662
|
-
if (typeof
|
|
27663
|
-
layout["icon-image"] = rasterAtonIconExpression(
|
|
28631
|
+
const objectClass2 = metadata2?.["s52:objectClass"];
|
|
28632
|
+
if (typeof objectClass2 !== "string" || !classes.has(objectClass2)) continue;
|
|
28633
|
+
layout["icon-image"] = rasterAtonIconExpression(objectClass2);
|
|
27664
28634
|
}
|
|
27665
28635
|
const metadata = style.metadata;
|
|
27666
28636
|
metadata["chrt:symbol-set"] = "raster";
|
|
@@ -27692,19 +28662,19 @@ function parseSymbolFamily(raw) {
|
|
|
27692
28662
|
const lower = raw.toLowerCase();
|
|
27693
28663
|
return SYMBOL_FAMILIES.find((f) => f === lower) ?? null;
|
|
27694
28664
|
}
|
|
27695
|
-
function iconExpressionForFamily(
|
|
27696
|
-
const s52 = getIconExpression(
|
|
28665
|
+
function iconExpressionForFamily(objectClass2, family) {
|
|
28666
|
+
const s52 = getIconExpression(objectClass2);
|
|
27697
28667
|
switch (family) {
|
|
27698
28668
|
case "s52":
|
|
27699
28669
|
return s52;
|
|
27700
28670
|
case "s101":
|
|
27701
28671
|
return rewriteIconToS101(s52);
|
|
27702
28672
|
case "chrt": {
|
|
27703
|
-
const build = CHRT_ICON_EXPRESSIONS[
|
|
28673
|
+
const build = CHRT_ICON_EXPRESSIONS[objectClass2];
|
|
27704
28674
|
return build ? build() : s52;
|
|
27705
28675
|
}
|
|
27706
28676
|
case "raster":
|
|
27707
|
-
return RASTER_ATON_CLASSES.includes(
|
|
28677
|
+
return RASTER_ATON_CLASSES.includes(objectClass2) ? rasterAtonIconExpression(objectClass2) : s52;
|
|
27708
28678
|
}
|
|
27709
28679
|
}
|
|
27710
28680
|
|
|
@@ -27752,16 +28722,16 @@ var LARGE = {
|
|
|
27752
28722
|
WRECKS: HAZARD_DEPTH
|
|
27753
28723
|
};
|
|
27754
28724
|
var LARGE_SOUNDING_PADDING_PX = 3.5;
|
|
27755
|
-
function applyDepthLabelSize(
|
|
28725
|
+
function applyDepthLabelSize(objectClass2, layer, size) {
|
|
27756
28726
|
if (size !== "large") return layer;
|
|
27757
|
-
const large = LARGE[
|
|
28727
|
+
const large = LARGE[objectClass2];
|
|
27758
28728
|
if (large === void 0) return layer;
|
|
27759
28729
|
const layout = {
|
|
27760
28730
|
...layer.layout ?? {},
|
|
27761
28731
|
"text-size": large.textSize,
|
|
27762
28732
|
"text-font": [...large.font]
|
|
27763
28733
|
};
|
|
27764
|
-
if (
|
|
28734
|
+
if (objectClass2 === "SOUNDG") layout["text-padding"] = LARGE_SOUNDING_PADDING_PX;
|
|
27765
28735
|
return {
|
|
27766
28736
|
...layer,
|
|
27767
28737
|
layout,
|
|
@@ -27958,47 +28928,47 @@ function buildLightLabelExpression() {
|
|
|
27958
28928
|
];
|
|
27959
28929
|
return ["concat", litchrExpr, siggrpExpr, colourExpr, sigperExpr, valnmrExpr];
|
|
27960
28930
|
}
|
|
27961
|
-
function buildLayersForClass(
|
|
27962
|
-
if (!S52_LOOKUP[
|
|
27963
|
-
const entry = S52_LOOKUP[
|
|
28931
|
+
function buildLayersForClass(objectClass2, ct, sourceId = DEFAULT_REGION, opts = {}) {
|
|
28932
|
+
if (!S52_LOOKUP[objectClass2]) return [];
|
|
28933
|
+
const entry = S52_LOOKUP[objectClass2];
|
|
27964
28934
|
const layers = [];
|
|
27965
|
-
const geomTypes = getGeomTypesForClass(
|
|
28935
|
+
const geomTypes = getGeomTypesForClass(objectClass2, entry?.style.type);
|
|
27966
28936
|
for (const geomType of geomTypes) {
|
|
27967
|
-
const resolved = resolveStyle(
|
|
27968
|
-
const layerId = `s52-${
|
|
28937
|
+
const resolved = resolveStyle(objectClass2, geomType, ct, { safetyContour: opts.safetyContour });
|
|
28938
|
+
const layerId = `s52-${objectClass2}-${resolved.type}`;
|
|
27969
28939
|
const layer = {
|
|
27970
28940
|
id: layerId,
|
|
27971
28941
|
type: resolved.type,
|
|
27972
28942
|
source: sourceId,
|
|
27973
|
-
"source-layer":
|
|
28943
|
+
"source-layer": objectClass2,
|
|
27974
28944
|
paint: resolved.paint,
|
|
27975
28945
|
metadata: {
|
|
27976
|
-
"s52:objectClass":
|
|
28946
|
+
"s52:objectClass": objectClass2,
|
|
27977
28947
|
"s52:displayCategory": entry?.displayCategory ?? "OTHER",
|
|
27978
28948
|
"s52:category": entry?.category ?? "Meta"
|
|
27979
28949
|
}
|
|
27980
28950
|
};
|
|
27981
|
-
if (resolved.type === "line" && LINE_FROM_POLYGON_LAYERS.has(
|
|
28951
|
+
if (resolved.type === "line" && LINE_FROM_POLYGON_LAYERS.has(objectClass2)) {
|
|
27982
28952
|
layer.filter = GEOM_FILTERS.fill;
|
|
27983
28953
|
} else if (GEOM_FILTERS[resolved.type]) {
|
|
27984
28954
|
layer.filter = GEOM_FILTERS[resolved.type];
|
|
27985
28955
|
}
|
|
27986
|
-
if (SCAMIN_DECLUTTER_CLASSES.has(
|
|
28956
|
+
if (SCAMIN_DECLUTTER_CLASSES.has(objectClass2)) {
|
|
27987
28957
|
layer.filter = layer.filter ? ["all", layer.filter, scaminZoomGateFilter()] : ["all", scaminZoomGateFilter()];
|
|
27988
28958
|
}
|
|
27989
28959
|
if (resolved.minzoom) {
|
|
27990
28960
|
layer.minzoom = resolved.minzoom;
|
|
27991
28961
|
}
|
|
27992
|
-
if (resolved.type === "fill" && OPAQUE_FILLS.has(
|
|
28962
|
+
if (resolved.type === "fill" && OPAQUE_FILLS.has(objectClass2)) {
|
|
27993
28963
|
layer.paint["fill-opacity"] = 1;
|
|
27994
28964
|
}
|
|
27995
|
-
if (resolved.type === "line" && ZOOM_SCALED_LINES2[
|
|
27996
|
-
const [z1, w1, z2, w2] = ZOOM_SCALED_LINES2[
|
|
28965
|
+
if (resolved.type === "line" && ZOOM_SCALED_LINES2[objectClass2]) {
|
|
28966
|
+
const [z1, w1, z2, w2] = ZOOM_SCALED_LINES2[objectClass2];
|
|
27997
28967
|
layer.paint["line-width"] = ["interpolate", ["linear"], ["zoom"], z1, w1, z2, w2];
|
|
27998
28968
|
}
|
|
27999
28969
|
if (resolved.type === "symbol") {
|
|
28000
|
-
const iconExpr = getIconExpression(
|
|
28001
|
-
const childOffset = CHILD_ICON_OFFSETS[
|
|
28970
|
+
const iconExpr = getIconExpression(objectClass2);
|
|
28971
|
+
const childOffset = CHILD_ICON_OFFSETS[objectClass2];
|
|
28002
28972
|
const isSafetyCritical = SAFETY_GROUPS.has(entry?.viewingGroup ?? 0);
|
|
28003
28973
|
const safetyCriticalIconSize = [
|
|
28004
28974
|
"interpolate",
|
|
@@ -28121,7 +29091,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28121
29091
|
]
|
|
28122
29092
|
};
|
|
28123
29093
|
}
|
|
28124
|
-
if (
|
|
29094
|
+
if (objectClass2 === "LIGHTS") {
|
|
28125
29095
|
layer.layout = {
|
|
28126
29096
|
...layer.layout,
|
|
28127
29097
|
"icon-allow-overlap": true,
|
|
@@ -28163,14 +29133,14 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28163
29133
|
} else if (resolved.layout) {
|
|
28164
29134
|
layer.layout = resolved.layout;
|
|
28165
29135
|
}
|
|
28166
|
-
if (
|
|
29136
|
+
if (objectClass2 === "LNDMRK" && resolved.type === "symbol") {
|
|
28167
29137
|
const baseFilterParts = layer.filter && layer.filter[0] === "all" ? layer.filter.slice(1) : layer.filter ? [layer.filter] : [];
|
|
28168
29138
|
const isWind = listAttrHas("CATLMK", ["18", "19"]);
|
|
28169
29139
|
const isLighthouse = listAttrHas("CATLMK", ["17"]);
|
|
28170
29140
|
const scaminFloor = scaminToMinZoom(entry?.scamin);
|
|
28171
29141
|
const windLayer = {
|
|
28172
29142
|
...layer,
|
|
28173
|
-
id: `s52-${
|
|
29143
|
+
id: `s52-${objectClass2}-wind-symbol`,
|
|
28174
29144
|
filter: ["all", ...baseFilterParts, isWind],
|
|
28175
29145
|
// Explicit, not inherited: turbines share exact coordinates with
|
|
28176
29146
|
// their aviation-light LIGHTS feature; without allow-overlap the
|
|
@@ -28183,7 +29153,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28183
29153
|
delete windLayer.minzoom;
|
|
28184
29154
|
const lighthouseLayer = {
|
|
28185
29155
|
...layer,
|
|
28186
|
-
id: `s52-${
|
|
29156
|
+
id: `s52-${objectClass2}-lighthouse-symbol`,
|
|
28187
29157
|
filter: ["all", ...baseFilterParts, isLighthouse, ["!", isWind]],
|
|
28188
29158
|
layout: {
|
|
28189
29159
|
...layer.layout ?? {},
|
|
@@ -28194,7 +29164,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28194
29164
|
delete lighthouseLayer.minzoom;
|
|
28195
29165
|
const otherLayer = {
|
|
28196
29166
|
...layer,
|
|
28197
|
-
id: `s52-${
|
|
29167
|
+
id: `s52-${objectClass2}-other-symbol`,
|
|
28198
29168
|
filter: ["all", ...baseFilterParts, ["!", isWind], ["!", isLighthouse]]
|
|
28199
29169
|
};
|
|
28200
29170
|
if (scaminFloor !== void 0) {
|
|
@@ -28209,10 +29179,10 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28209
29179
|
const valsouNum = ["to-number", ["coalesce", ["get", "VALSOU"], ["get", "valsou"], 999], 999];
|
|
28210
29180
|
const watlevNum = ["to-number", ["coalesce", ["get", "WATLEV"], ["get", "watlev"], 0], 0];
|
|
28211
29181
|
layers.push({
|
|
28212
|
-
id: `s52-${
|
|
29182
|
+
id: `s52-${objectClass2}-danger-ring`,
|
|
28213
29183
|
type: "symbol",
|
|
28214
29184
|
source: sourceId,
|
|
28215
|
-
"source-layer":
|
|
29185
|
+
"source-layer": objectClass2,
|
|
28216
29186
|
filter: [
|
|
28217
29187
|
"all",
|
|
28218
29188
|
GEOM_FILTERS.symbol,
|
|
@@ -28245,48 +29215,48 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28245
29215
|
},
|
|
28246
29216
|
paint: {},
|
|
28247
29217
|
minzoom: 13,
|
|
28248
|
-
metadata: { "s52:objectClass":
|
|
29218
|
+
metadata: { "s52:objectClass": objectClass2, "s52:role": "isolated-danger-ring" }
|
|
28249
29219
|
});
|
|
28250
29220
|
}
|
|
28251
|
-
if (resolved.type === "fill" && FILL_OUTLINE_LAYERS.has(
|
|
28252
|
-
const outlineColor =
|
|
29221
|
+
if (resolved.type === "fill" && FILL_OUTLINE_LAYERS.has(objectClass2)) {
|
|
29222
|
+
const outlineColor = objectClass2 === "DEPARE" ? resolveColor("CHGRD", ct) : resolveColor("CHGRF", ct);
|
|
28253
29223
|
layers.push({
|
|
28254
|
-
id: `s52-${
|
|
29224
|
+
id: `s52-${objectClass2}-outline`,
|
|
28255
29225
|
type: "line",
|
|
28256
29226
|
source: sourceId,
|
|
28257
|
-
"source-layer":
|
|
29227
|
+
"source-layer": objectClass2,
|
|
28258
29228
|
filter: GEOM_FILTERS.fill,
|
|
28259
29229
|
paint: {
|
|
28260
29230
|
"line-color": outlineColor,
|
|
28261
29231
|
"line-width": 0.3,
|
|
28262
29232
|
"line-opacity": 0.4
|
|
28263
29233
|
},
|
|
28264
|
-
metadata: { "s52:objectClass":
|
|
29234
|
+
metadata: { "s52:objectClass": objectClass2, "s52:role": "outline" }
|
|
28265
29235
|
});
|
|
28266
29236
|
}
|
|
28267
|
-
if (resolved.type === "fill" && REGULATED_AREA_BOUNDARY_LAYERS[
|
|
28268
|
-
const lineStyle = REGULATED_AREA_BOUNDARY_LINESTYLES[
|
|
29237
|
+
if (resolved.type === "fill" && REGULATED_AREA_BOUNDARY_LAYERS[objectClass2]) {
|
|
29238
|
+
const lineStyle = REGULATED_AREA_BOUNDARY_LINESTYLES[objectClass2];
|
|
28269
29239
|
const boundaryPaint = lineStyle ? lineStylePaint(lineStyle) : {
|
|
28270
|
-
"line-color": resolveColor(REGULATED_AREA_BOUNDARY_LAYERS[
|
|
29240
|
+
"line-color": resolveColor(REGULATED_AREA_BOUNDARY_LAYERS[objectClass2], ct),
|
|
28271
29241
|
"line-width": 1,
|
|
28272
29242
|
"line-dasharray": [4, 2],
|
|
28273
29243
|
"line-opacity": 0.85
|
|
28274
29244
|
};
|
|
28275
29245
|
layers.push({
|
|
28276
|
-
id: `s52-${
|
|
29246
|
+
id: `s52-${objectClass2}-boundary`,
|
|
28277
29247
|
type: "line",
|
|
28278
29248
|
source: sourceId,
|
|
28279
|
-
"source-layer":
|
|
29249
|
+
"source-layer": objectClass2,
|
|
28280
29250
|
filter: GEOM_FILTERS.fill,
|
|
28281
29251
|
paint: boundaryPaint,
|
|
28282
29252
|
metadata: {
|
|
28283
|
-
"s52:objectClass":
|
|
29253
|
+
"s52:objectClass": objectClass2,
|
|
28284
29254
|
"s52:role": "boundary",
|
|
28285
29255
|
...lineStyle ? { "s52:lineStyle": lineStyle } : {}
|
|
28286
29256
|
}
|
|
28287
29257
|
});
|
|
28288
29258
|
}
|
|
28289
|
-
if (
|
|
29259
|
+
if (objectClass2 === "ACHARE" && resolved.type === "fill") {
|
|
28290
29260
|
layers.push({
|
|
28291
29261
|
id: "s52-ACHARE-boundary",
|
|
28292
29262
|
type: "line",
|
|
@@ -28302,7 +29272,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28302
29272
|
metadata: { "s52:objectClass": "ACHARE", "s52:role": "boundary" }
|
|
28303
29273
|
});
|
|
28304
29274
|
}
|
|
28305
|
-
if (
|
|
29275
|
+
if (objectClass2 === "DRGARE" && resolved.type === "fill") {
|
|
28306
29276
|
layers.push({
|
|
28307
29277
|
id: "s52-DRGARE-boundary",
|
|
28308
29278
|
type: "line",
|
|
@@ -28318,7 +29288,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28318
29288
|
metadata: { "s52:objectClass": "DRGARE", "s52:role": "boundary" }
|
|
28319
29289
|
});
|
|
28320
29290
|
}
|
|
28321
|
-
if (
|
|
29291
|
+
if (objectClass2 === "ACHARE" && resolved.type === "fill") {
|
|
28322
29292
|
layers.push({
|
|
28323
29293
|
id: "s52-ACHARE-anchor-icon",
|
|
28324
29294
|
type: "symbol",
|
|
@@ -28347,7 +29317,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28347
29317
|
metadata: { "s52:objectClass": "ACHARE", "s52:role": "centroid-icon" }
|
|
28348
29318
|
});
|
|
28349
29319
|
}
|
|
28350
|
-
if (
|
|
29320
|
+
if (objectClass2 === "LNDARE" && resolved.type === "fill") {
|
|
28351
29321
|
layers.push({
|
|
28352
29322
|
id: `s52-LNDARE-point`,
|
|
28353
29323
|
type: "circle",
|
|
@@ -28363,7 +29333,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28363
29333
|
metadata: { "s52:objectClass": "LNDARE", "s52:role": "point" }
|
|
28364
29334
|
});
|
|
28365
29335
|
}
|
|
28366
|
-
if (
|
|
29336
|
+
if (objectClass2 === "LNDARE" && resolved.type === "fill") {
|
|
28367
29337
|
layers.push({
|
|
28368
29338
|
id: `s52-LNDARE-line`,
|
|
28369
29339
|
type: "line",
|
|
@@ -28377,7 +29347,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28377
29347
|
metadata: { "s52:objectClass": "LNDARE", "s52:role": "line" }
|
|
28378
29348
|
});
|
|
28379
29349
|
}
|
|
28380
|
-
if (
|
|
29350
|
+
if (objectClass2 === "BUAARE" && resolved.type === "fill") {
|
|
28381
29351
|
layers.push({
|
|
28382
29352
|
id: `s52-BUAARE-point`,
|
|
28383
29353
|
type: "circle",
|
|
@@ -28393,7 +29363,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28393
29363
|
metadata: { "s52:objectClass": "BUAARE", "s52:role": "point" }
|
|
28394
29364
|
});
|
|
28395
29365
|
}
|
|
28396
|
-
if (
|
|
29366
|
+
if (objectClass2 === "RIVERS" && resolved.type === "fill") {
|
|
28397
29367
|
layers.push({
|
|
28398
29368
|
id: `s52-RIVERS-line`,
|
|
28399
29369
|
type: "line",
|
|
@@ -28407,7 +29377,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28407
29377
|
metadata: { "s52:objectClass": "RIVERS", "s52:role": "line" }
|
|
28408
29378
|
});
|
|
28409
29379
|
}
|
|
28410
|
-
if (
|
|
29380
|
+
if (objectClass2 === "BUISGL" && resolved.type === "circle") {
|
|
28411
29381
|
layers.push({
|
|
28412
29382
|
id: `s52-BUISGL-polygon`,
|
|
28413
29383
|
type: "fill",
|
|
@@ -28433,7 +29403,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28433
29403
|
metadata: { "s52:objectClass": "BUISGL", "s52:role": "polygon-outline" }
|
|
28434
29404
|
});
|
|
28435
29405
|
}
|
|
28436
|
-
if (
|
|
29406
|
+
if (objectClass2 === "BRIDGE" && resolved.type === "line") {
|
|
28437
29407
|
layers.push({
|
|
28438
29408
|
id: `s52-BRIDGE-polygon`,
|
|
28439
29409
|
type: "fill",
|
|
@@ -28459,7 +29429,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28459
29429
|
metadata: { "s52:objectClass": "BRIDGE", "s52:role": "polygon-outline" }
|
|
28460
29430
|
});
|
|
28461
29431
|
}
|
|
28462
|
-
if (
|
|
29432
|
+
if (objectClass2 === "PYLONS" && resolved.type === "fill") {
|
|
28463
29433
|
layers.push({
|
|
28464
29434
|
id: `s52-PYLONS-point`,
|
|
28465
29435
|
type: "circle",
|
|
@@ -28475,7 +29445,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28475
29445
|
metadata: { "s52:objectClass": "PYLONS", "s52:role": "point" }
|
|
28476
29446
|
});
|
|
28477
29447
|
}
|
|
28478
|
-
if (
|
|
29448
|
+
if (objectClass2 === "WEDKLP" && resolved.type === "fill") {
|
|
28479
29449
|
layers.push({
|
|
28480
29450
|
id: `s52-WEDKLP-point`,
|
|
28481
29451
|
type: "circle",
|
|
@@ -28492,7 +29462,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28492
29462
|
metadata: { "s52:objectClass": "WEDKLP", "s52:role": "point" }
|
|
28493
29463
|
});
|
|
28494
29464
|
}
|
|
28495
|
-
if (
|
|
29465
|
+
if (objectClass2 === "SLOGRD" && resolved.type === "fill") {
|
|
28496
29466
|
layers.push({
|
|
28497
29467
|
id: `s52-SLOGRD-point`,
|
|
28498
29468
|
type: "circle",
|
|
@@ -28509,7 +29479,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28509
29479
|
metadata: { "s52:objectClass": "SLOGRD", "s52:role": "point" }
|
|
28510
29480
|
});
|
|
28511
29481
|
}
|
|
28512
|
-
if (
|
|
29482
|
+
if (objectClass2 === "RUNWAY" && resolved.type === "fill") {
|
|
28513
29483
|
layers.push({
|
|
28514
29484
|
id: `s52-RUNWAY-line`,
|
|
28515
29485
|
type: "line",
|
|
@@ -28523,7 +29493,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28523
29493
|
metadata: { "s52:objectClass": "RUNWAY", "s52:role": "line" }
|
|
28524
29494
|
});
|
|
28525
29495
|
}
|
|
28526
|
-
if (
|
|
29496
|
+
if (objectClass2 === "FORSTC" && resolved.type === "fill") {
|
|
28527
29497
|
layers.push({
|
|
28528
29498
|
id: `s52-FORSTC-line`,
|
|
28529
29499
|
type: "line",
|
|
@@ -28537,7 +29507,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28537
29507
|
metadata: { "s52:objectClass": "FORSTC", "s52:role": "line" }
|
|
28538
29508
|
});
|
|
28539
29509
|
}
|
|
28540
|
-
if (
|
|
29510
|
+
if (objectClass2 === "FSHFAC" && resolved.type === "fill") {
|
|
28541
29511
|
layers.push({
|
|
28542
29512
|
id: `s52-FSHFAC-point`,
|
|
28543
29513
|
type: "circle",
|
|
@@ -28553,7 +29523,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28553
29523
|
metadata: { "s52:objectClass": "FSHFAC", "s52:role": "point" }
|
|
28554
29524
|
});
|
|
28555
29525
|
}
|
|
28556
|
-
if (
|
|
29526
|
+
if (objectClass2 === "OBSTRN" && resolved.type === "symbol") {
|
|
28557
29527
|
layers.push({
|
|
28558
29528
|
id: `s52-OBSTRN-polygon`,
|
|
28559
29529
|
type: "fill",
|
|
@@ -28593,7 +29563,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28593
29563
|
metadata: { "s52:objectClass": "OBSTRN", "s52:role": "line" }
|
|
28594
29564
|
});
|
|
28595
29565
|
}
|
|
28596
|
-
if (
|
|
29566
|
+
if (objectClass2 === "SLCONS" && resolved.type === "line") {
|
|
28597
29567
|
layers.push({
|
|
28598
29568
|
id: `s52-SLCONS-polygon`,
|
|
28599
29569
|
type: "fill",
|
|
@@ -28633,7 +29603,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28633
29603
|
metadata: { "s52:objectClass": "SLCONS", "s52:role": "point" }
|
|
28634
29604
|
});
|
|
28635
29605
|
}
|
|
28636
|
-
if (
|
|
29606
|
+
if (objectClass2 === "PRDARE" && resolved.type === "line") {
|
|
28637
29607
|
layers.push({
|
|
28638
29608
|
id: `s52-PRDARE-point`,
|
|
28639
29609
|
type: "circle",
|
|
@@ -28650,7 +29620,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28650
29620
|
metadata: { "s52:objectClass": "PRDARE", "s52:role": "point" }
|
|
28651
29621
|
});
|
|
28652
29622
|
}
|
|
28653
|
-
if (
|
|
29623
|
+
if (objectClass2 === "CTNARE" && resolved.type === "line") {
|
|
28654
29624
|
layers.push({
|
|
28655
29625
|
id: `s52-CTNARE-point`,
|
|
28656
29626
|
type: "circle",
|
|
@@ -28666,7 +29636,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28666
29636
|
metadata: { "s52:objectClass": "CTNARE", "s52:role": "point" }
|
|
28667
29637
|
});
|
|
28668
29638
|
}
|
|
28669
|
-
if (
|
|
29639
|
+
if (objectClass2 === "PONTON" && resolved.type === "line") {
|
|
28670
29640
|
layers.push({
|
|
28671
29641
|
id: `s52-PONTON-polygon`,
|
|
28672
29642
|
type: "fill",
|
|
@@ -28692,7 +29662,7 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28692
29662
|
metadata: { "s52:objectClass": "PONTON", "s52:role": "polygon-outline" }
|
|
28693
29663
|
});
|
|
28694
29664
|
}
|
|
28695
|
-
if (
|
|
29665
|
+
if (objectClass2 === "WRECKS" && resolved.type === "symbol") {
|
|
28696
29666
|
layers.push({
|
|
28697
29667
|
id: `s52-WRECKS-polygon`,
|
|
28698
29668
|
type: "fill",
|
|
@@ -28706,1179 +29676,729 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
28706
29676
|
metadata: { "s52:objectClass": "WRECKS", "s52:role": "polygon" }
|
|
28707
29677
|
});
|
|
28708
29678
|
layers.push({
|
|
28709
|
-
id: `s52-WRECKS-polygon-outline`,
|
|
28710
|
-
type: "line",
|
|
28711
|
-
source: sourceId,
|
|
28712
|
-
"source-layer": "WRECKS",
|
|
28713
|
-
filter: GEOM_FILTERS.fill,
|
|
28714
|
-
paint: {
|
|
28715
|
-
"line-color": resolveColor("CHBLK", ct),
|
|
28716
|
-
"line-width": 1,
|
|
28717
|
-
"line-dasharray": [3, 2]
|
|
28718
|
-
},
|
|
28719
|
-
metadata: { "s52:objectClass": "WRECKS", "s52:role": "polygon-outline" }
|
|
28720
|
-
});
|
|
28721
|
-
}
|
|
28722
|
-
if (objectClass === "WATTUR" && resolved.type === "symbol") {
|
|
28723
|
-
layers.push({
|
|
28724
|
-
id: `s52-WATTUR-polygon`,
|
|
28725
|
-
type: "fill",
|
|
28726
|
-
source: sourceId,
|
|
28727
|
-
"source-layer": "WATTUR",
|
|
28728
|
-
filter: GEOM_FILTERS.fill,
|
|
28729
|
-
paint: {
|
|
28730
|
-
"fill-color": resolveColor("CHBLK", ct),
|
|
28731
|
-
"fill-opacity": 0.05
|
|
28732
|
-
},
|
|
28733
|
-
metadata: { "s52:objectClass": "WATTUR", "s52:role": "polygon" }
|
|
28734
|
-
});
|
|
28735
|
-
}
|
|
28736
|
-
if (objectClass === "MAGVAR" && resolved.type === "line") {
|
|
28737
|
-
layers.push({
|
|
28738
|
-
id: "s52-MAGVAR-point",
|
|
28739
|
-
type: "circle",
|
|
28740
|
-
source: sourceId,
|
|
28741
|
-
"source-layer": "MAGVAR",
|
|
28742
|
-
filter: GEOM_FILTERS.circle,
|
|
28743
|
-
paint: {
|
|
28744
|
-
"circle-color": resolveColor("CHMGD", ct),
|
|
28745
|
-
"circle-radius": ["interpolate", ["linear"], ["zoom"], 6, 1, 12, 2],
|
|
28746
|
-
"circle-stroke-color": resolveColor("CHBLK", ct),
|
|
28747
|
-
"circle-stroke-width": 0.4,
|
|
28748
|
-
"circle-opacity": 0.4
|
|
28749
|
-
},
|
|
28750
|
-
metadata: { "s52:objectClass": "MAGVAR", "s52:role": "point" }
|
|
28751
|
-
});
|
|
28752
|
-
}
|
|
28753
|
-
if (objectClass === "DMPGRD" && resolved.type === "fill") {
|
|
28754
|
-
layers.push({
|
|
28755
|
-
id: `s52-DMPGRD-point`,
|
|
28756
|
-
type: "circle",
|
|
28757
|
-
source: sourceId,
|
|
28758
|
-
"source-layer": "DMPGRD",
|
|
28759
|
-
filter: GEOM_FILTERS.circle,
|
|
28760
|
-
paint: {
|
|
28761
|
-
"circle-color": resolveColor("LITYW", ct),
|
|
28762
|
-
"circle-radius": ["interpolate", ["linear"], ["zoom"], 10, 1.5, 14, 2.5, 17, 3.6],
|
|
28763
|
-
"circle-stroke-color": resolveColor("CHBLK", ct),
|
|
28764
|
-
"circle-stroke-width": 0.5,
|
|
28765
|
-
"circle-opacity": 0.7
|
|
28766
|
-
},
|
|
28767
|
-
metadata: { "s52:objectClass": "DMPGRD", "s52:role": "point" }
|
|
28768
|
-
});
|
|
28769
|
-
}
|
|
28770
|
-
if (objectClass === "DAMCON" && resolved.type === "line") {
|
|
28771
|
-
layers.push({
|
|
28772
|
-
id: `s52-DAMCON-polygon`,
|
|
28773
|
-
type: "fill",
|
|
28774
|
-
source: sourceId,
|
|
28775
|
-
"source-layer": "DAMCON",
|
|
28776
|
-
filter: GEOM_FILTERS.fill,
|
|
28777
|
-
paint: {
|
|
28778
|
-
"fill-color": resolveColor("CHBRN", ct),
|
|
28779
|
-
"fill-opacity": 0.4
|
|
28780
|
-
},
|
|
28781
|
-
metadata: { "s52:objectClass": "DAMCON", "s52:role": "polygon" }
|
|
28782
|
-
});
|
|
28783
|
-
layers.push({
|
|
28784
|
-
id: `s52-DAMCON-polygon-outline`,
|
|
28785
|
-
type: "line",
|
|
28786
|
-
source: sourceId,
|
|
28787
|
-
"source-layer": "DAMCON",
|
|
28788
|
-
filter: GEOM_FILTERS.fill,
|
|
28789
|
-
paint: {
|
|
28790
|
-
"line-color": resolveColor("CHBLK", ct),
|
|
28791
|
-
"line-width": 0.6
|
|
28792
|
-
},
|
|
28793
|
-
metadata: { "s52:objectClass": "DAMCON", "s52:role": "outline" }
|
|
28794
|
-
});
|
|
28795
|
-
}
|
|
28796
|
-
if (objectClass === "GATCON" && resolved.type === "line") {
|
|
28797
|
-
layers.push({
|
|
28798
|
-
id: `s52-GATCON-polygon`,
|
|
28799
|
-
type: "fill",
|
|
28800
|
-
source: sourceId,
|
|
28801
|
-
"source-layer": "GATCON",
|
|
28802
|
-
filter: GEOM_FILTERS.fill,
|
|
28803
|
-
paint: {
|
|
28804
|
-
"fill-color": resolveColor("CHBRN", ct),
|
|
28805
|
-
"fill-opacity": 0.4
|
|
28806
|
-
},
|
|
28807
|
-
metadata: { "s52:objectClass": "GATCON", "s52:role": "polygon" }
|
|
28808
|
-
});
|
|
28809
|
-
layers.push({
|
|
28810
|
-
id: `s52-GATCON-polygon-outline`,
|
|
28811
|
-
type: "line",
|
|
28812
|
-
source: sourceId,
|
|
28813
|
-
"source-layer": "GATCON",
|
|
28814
|
-
filter: GEOM_FILTERS.fill,
|
|
28815
|
-
paint: {
|
|
28816
|
-
"line-color": resolveColor("CHBLK", ct),
|
|
28817
|
-
"line-width": 0.6
|
|
28818
|
-
},
|
|
28819
|
-
metadata: { "s52:objectClass": "GATCON", "s52:role": "outline" }
|
|
28820
|
-
});
|
|
28821
|
-
}
|
|
28822
|
-
if (objectClass === "CANALS" && resolved.type === "line") {
|
|
28823
|
-
layers.push({
|
|
28824
|
-
id: `s52-CANALS-polygon`,
|
|
28825
|
-
type: "fill",
|
|
28826
|
-
source: sourceId,
|
|
28827
|
-
"source-layer": "CANALS",
|
|
28828
|
-
filter: GEOM_FILTERS.fill,
|
|
28829
|
-
paint: {
|
|
28830
|
-
"fill-color": resolveColor("DEPMS", ct),
|
|
28831
|
-
"fill-opacity": 0.5
|
|
28832
|
-
},
|
|
28833
|
-
metadata: { "s52:objectClass": "CANALS", "s52:role": "polygon" }
|
|
28834
|
-
});
|
|
28835
|
-
}
|
|
28836
|
-
if (objectClass === "PILBOP" && resolved.type === "symbol") {
|
|
28837
|
-
layers.push({
|
|
28838
|
-
id: `s52-PILBOP-polygon`,
|
|
28839
|
-
type: "fill",
|
|
28840
|
-
source: sourceId,
|
|
28841
|
-
"source-layer": "PILBOP",
|
|
28842
|
-
filter: GEOM_FILTERS.fill,
|
|
28843
|
-
paint: {
|
|
28844
|
-
"fill-color": resolveColor("CHMGD", ct),
|
|
28845
|
-
"fill-opacity": 0.1
|
|
28846
|
-
},
|
|
28847
|
-
metadata: { "s52:objectClass": "PILBOP", "s52:role": "polygon" }
|
|
28848
|
-
});
|
|
28849
|
-
layers.push({
|
|
28850
|
-
id: `s52-PILBOP-polygon-outline`,
|
|
29679
|
+
id: `s52-WRECKS-polygon-outline`,
|
|
28851
29680
|
type: "line",
|
|
28852
29681
|
source: sourceId,
|
|
28853
|
-
"source-layer": "
|
|
29682
|
+
"source-layer": "WRECKS",
|
|
28854
29683
|
filter: GEOM_FILTERS.fill,
|
|
28855
29684
|
paint: {
|
|
28856
|
-
"line-color": resolveColor("
|
|
28857
|
-
"line-width":
|
|
28858
|
-
"line-dasharray": [
|
|
29685
|
+
"line-color": resolveColor("CHBLK", ct),
|
|
29686
|
+
"line-width": 1,
|
|
29687
|
+
"line-dasharray": [3, 2]
|
|
28859
29688
|
},
|
|
28860
|
-
metadata: { "s52:objectClass": "
|
|
29689
|
+
metadata: { "s52:objectClass": "WRECKS", "s52:role": "polygon-outline" }
|
|
28861
29690
|
});
|
|
28862
29691
|
}
|
|
28863
|
-
if (
|
|
29692
|
+
if (objectClass2 === "WATTUR" && resolved.type === "symbol") {
|
|
28864
29693
|
layers.push({
|
|
28865
|
-
id: `s52-
|
|
29694
|
+
id: `s52-WATTUR-polygon`,
|
|
28866
29695
|
type: "fill",
|
|
28867
29696
|
source: sourceId,
|
|
28868
|
-
"source-layer": "
|
|
29697
|
+
"source-layer": "WATTUR",
|
|
28869
29698
|
filter: GEOM_FILTERS.fill,
|
|
28870
29699
|
paint: {
|
|
28871
|
-
"fill-color": resolveColor("
|
|
28872
|
-
"fill-opacity": 0.
|
|
29700
|
+
"fill-color": resolveColor("CHBLK", ct),
|
|
29701
|
+
"fill-opacity": 0.05
|
|
28873
29702
|
},
|
|
28874
|
-
metadata: { "s52:objectClass": "
|
|
29703
|
+
metadata: { "s52:objectClass": "WATTUR", "s52:role": "polygon" }
|
|
28875
29704
|
});
|
|
28876
29705
|
}
|
|
28877
|
-
if (
|
|
29706
|
+
if (objectClass2 === "MAGVAR" && resolved.type === "line") {
|
|
28878
29707
|
layers.push({
|
|
28879
|
-
id:
|
|
29708
|
+
id: "s52-MAGVAR-point",
|
|
28880
29709
|
type: "circle",
|
|
28881
29710
|
source: sourceId,
|
|
28882
|
-
"source-layer": "
|
|
29711
|
+
"source-layer": "MAGVAR",
|
|
28883
29712
|
filter: GEOM_FILTERS.circle,
|
|
28884
29713
|
paint: {
|
|
28885
|
-
"circle-color": resolveColor("
|
|
28886
|
-
"circle-radius": ["interpolate", ["linear"], ["zoom"],
|
|
29714
|
+
"circle-color": resolveColor("CHMGD", ct),
|
|
29715
|
+
"circle-radius": ["interpolate", ["linear"], ["zoom"], 6, 1, 12, 2],
|
|
28887
29716
|
"circle-stroke-color": resolveColor("CHBLK", ct),
|
|
28888
29717
|
"circle-stroke-width": 0.4,
|
|
28889
|
-
"circle-opacity": 0.
|
|
29718
|
+
"circle-opacity": 0.4
|
|
28890
29719
|
},
|
|
28891
|
-
metadata: { "s52:objectClass": "
|
|
29720
|
+
metadata: { "s52:objectClass": "MAGVAR", "s52:role": "point" }
|
|
28892
29721
|
});
|
|
29722
|
+
}
|
|
29723
|
+
if (objectClass2 === "DMPGRD" && resolved.type === "fill") {
|
|
28893
29724
|
layers.push({
|
|
28894
|
-
id: `s52-
|
|
28895
|
-
type: "
|
|
29725
|
+
id: `s52-DMPGRD-point`,
|
|
29726
|
+
type: "circle",
|
|
28896
29727
|
source: sourceId,
|
|
28897
|
-
"source-layer": "
|
|
28898
|
-
filter: GEOM_FILTERS.
|
|
29728
|
+
"source-layer": "DMPGRD",
|
|
29729
|
+
filter: GEOM_FILTERS.circle,
|
|
28899
29730
|
paint: {
|
|
28900
|
-
"
|
|
28901
|
-
"
|
|
28902
|
-
"
|
|
29731
|
+
"circle-color": resolveColor("LITYW", ct),
|
|
29732
|
+
"circle-radius": ["interpolate", ["linear"], ["zoom"], 10, 1.5, 14, 2.5, 17, 3.6],
|
|
29733
|
+
"circle-stroke-color": resolveColor("CHBLK", ct),
|
|
29734
|
+
"circle-stroke-width": 0.5,
|
|
29735
|
+
"circle-opacity": 0.7
|
|
28903
29736
|
},
|
|
28904
|
-
metadata: { "s52:objectClass": "
|
|
29737
|
+
metadata: { "s52:objectClass": "DMPGRD", "s52:role": "point" }
|
|
28905
29738
|
});
|
|
28906
29739
|
}
|
|
28907
|
-
if (
|
|
29740
|
+
if (objectClass2 === "DAMCON" && resolved.type === "line") {
|
|
28908
29741
|
layers.push({
|
|
28909
|
-
id: `s52-
|
|
29742
|
+
id: `s52-DAMCON-polygon`,
|
|
28910
29743
|
type: "fill",
|
|
28911
29744
|
source: sourceId,
|
|
28912
|
-
"source-layer": "
|
|
29745
|
+
"source-layer": "DAMCON",
|
|
28913
29746
|
filter: GEOM_FILTERS.fill,
|
|
28914
29747
|
paint: {
|
|
28915
|
-
"fill-color": resolveColor("
|
|
28916
|
-
"fill-opacity": 0.
|
|
29748
|
+
"fill-color": resolveColor("CHBRN", ct),
|
|
29749
|
+
"fill-opacity": 0.4
|
|
28917
29750
|
},
|
|
28918
|
-
metadata: { "s52:objectClass": "
|
|
29751
|
+
metadata: { "s52:objectClass": "DAMCON", "s52:role": "polygon" }
|
|
28919
29752
|
});
|
|
28920
|
-
}
|
|
28921
|
-
if (objectClass === "PONTON" && resolved.type === "fill") {
|
|
28922
29753
|
layers.push({
|
|
28923
|
-
id: `s52-
|
|
29754
|
+
id: `s52-DAMCON-polygon-outline`,
|
|
28924
29755
|
type: "line",
|
|
28925
29756
|
source: sourceId,
|
|
28926
|
-
"source-layer": "
|
|
28927
|
-
filter: GEOM_FILTERS.
|
|
29757
|
+
"source-layer": "DAMCON",
|
|
29758
|
+
filter: GEOM_FILTERS.fill,
|
|
28928
29759
|
paint: {
|
|
28929
|
-
"line-color": resolveColor("
|
|
28930
|
-
"line-width":
|
|
29760
|
+
"line-color": resolveColor("CHBLK", ct),
|
|
29761
|
+
"line-width": 0.6
|
|
28931
29762
|
},
|
|
28932
|
-
metadata: { "s52:objectClass": "
|
|
29763
|
+
metadata: { "s52:objectClass": "DAMCON", "s52:role": "outline" }
|
|
28933
29764
|
});
|
|
28934
29765
|
}
|
|
28935
|
-
if (
|
|
29766
|
+
if (objectClass2 === "GATCON" && resolved.type === "line") {
|
|
28936
29767
|
layers.push({
|
|
28937
|
-
id: `s52-
|
|
28938
|
-
type: "
|
|
29768
|
+
id: `s52-GATCON-polygon`,
|
|
29769
|
+
type: "fill",
|
|
28939
29770
|
source: sourceId,
|
|
28940
|
-
"source-layer": "
|
|
29771
|
+
"source-layer": "GATCON",
|
|
28941
29772
|
filter: GEOM_FILTERS.fill,
|
|
28942
|
-
|
|
28943
|
-
"
|
|
28944
|
-
"
|
|
28945
|
-
"icon-allow-overlap": true,
|
|
28946
|
-
"icon-ignore-placement": false,
|
|
28947
|
-
"symbol-placement": "point"
|
|
29773
|
+
paint: {
|
|
29774
|
+
"fill-color": resolveColor("CHBRN", ct),
|
|
29775
|
+
"fill-opacity": 0.4
|
|
28948
29776
|
},
|
|
28949
|
-
|
|
28950
|
-
metadata: { "s52:objectClass": "SILTNK", "s52:role": "symbol-polygon" }
|
|
29777
|
+
metadata: { "s52:objectClass": "GATCON", "s52:role": "polygon" }
|
|
28951
29778
|
});
|
|
28952
|
-
}
|
|
28953
|
-
if (objectClass === "ACHBRT" && resolved.type === "symbol") {
|
|
28954
29779
|
layers.push({
|
|
28955
|
-
id: `s52-
|
|
28956
|
-
type: "
|
|
29780
|
+
id: `s52-GATCON-polygon-outline`,
|
|
29781
|
+
type: "line",
|
|
28957
29782
|
source: sourceId,
|
|
28958
|
-
"source-layer": "
|
|
29783
|
+
"source-layer": "GATCON",
|
|
28959
29784
|
filter: GEOM_FILTERS.fill,
|
|
28960
|
-
layout: {
|
|
28961
|
-
"icon-image": "ACHARE02",
|
|
28962
|
-
"icon-size": 0.5,
|
|
28963
|
-
"icon-allow-overlap": true,
|
|
28964
|
-
"icon-ignore-placement": false,
|
|
28965
|
-
"symbol-placement": "point"
|
|
28966
|
-
},
|
|
28967
|
-
paint: {},
|
|
28968
|
-
metadata: { "s52:objectClass": "ACHBRT", "s52:role": "symbol-polygon" }
|
|
28969
|
-
});
|
|
28970
|
-
}
|
|
28971
|
-
if (objectClass === "BERTHS" && resolved.type === "line") {
|
|
28972
|
-
layers.push({
|
|
28973
|
-
id: `s52-BERTHS-circle`,
|
|
28974
|
-
type: "circle",
|
|
28975
|
-
source: sourceId,
|
|
28976
|
-
"source-layer": "BERTHS",
|
|
28977
|
-
filter: GEOM_FILTERS.circle,
|
|
28978
29785
|
paint: {
|
|
28979
|
-
"
|
|
28980
|
-
"
|
|
28981
|
-
"circle-stroke-color": resolveColor("CHBLK", ct),
|
|
28982
|
-
"circle-stroke-width": 0.5
|
|
29786
|
+
"line-color": resolveColor("CHBLK", ct),
|
|
29787
|
+
"line-width": 0.6
|
|
28983
29788
|
},
|
|
28984
|
-
metadata: { "s52:objectClass": "
|
|
29789
|
+
metadata: { "s52:objectClass": "GATCON", "s52:role": "outline" }
|
|
28985
29790
|
});
|
|
28986
29791
|
}
|
|
28987
|
-
if (
|
|
29792
|
+
if (objectClass2 === "CANALS" && resolved.type === "line") {
|
|
28988
29793
|
layers.push({
|
|
28989
|
-
|
|
28990
|
-
|
|
28991
|
-
// are a Mapbox style-spec violation (caught by style-integrity.test).
|
|
28992
|
-
id: `s52-TUNNEL-linestring`,
|
|
28993
|
-
type: "line",
|
|
29794
|
+
id: `s52-CANALS-polygon`,
|
|
29795
|
+
type: "fill",
|
|
28994
29796
|
source: sourceId,
|
|
28995
|
-
"source-layer": "
|
|
28996
|
-
filter: GEOM_FILTERS.
|
|
29797
|
+
"source-layer": "CANALS",
|
|
29798
|
+
filter: GEOM_FILTERS.fill,
|
|
28997
29799
|
paint: {
|
|
28998
|
-
"
|
|
28999
|
-
"
|
|
29000
|
-
"line-dasharray": [2, 2]
|
|
29800
|
+
"fill-color": resolveColor("DEPMS", ct),
|
|
29801
|
+
"fill-opacity": 0.5
|
|
29001
29802
|
},
|
|
29002
|
-
metadata: { "s52:objectClass": "
|
|
29003
|
-
});
|
|
29004
|
-
}
|
|
29005
|
-
}
|
|
29006
|
-
return layers;
|
|
29007
|
-
}
|
|
29008
|
-
function buildLabelLayer2(objectClass, ct, sourceId = DEFAULT_REGION, depthUnits = "meters", labelOpts = {}) {
|
|
29009
|
-
if (!LABELED_LAYERS.has(objectClass)) return null;
|
|
29010
|
-
const config = getLabelConfig(objectClass, {
|
|
29011
|
-
colorTable: ct,
|
|
29012
|
-
safetyContour: labelOpts.safetyContour,
|
|
29013
|
-
twoShadeSoundings: labelOpts.twoShadeSoundings,
|
|
29014
|
-
soundingFontWeight: labelOpts.soundingFontWeight
|
|
29015
|
-
});
|
|
29016
|
-
if (!config) return null;
|
|
29017
|
-
let textField = config.textField;
|
|
29018
|
-
if (objectClass === "LIGHTS") {
|
|
29019
|
-
textField = buildLightLabelExpression();
|
|
29020
|
-
}
|
|
29021
|
-
if (typeof textField !== "string" && Array.isArray(textField)) {
|
|
29022
|
-
const flat = JSON.stringify(textField);
|
|
29023
|
-
if (flat.includes("_navAidLabel")) {
|
|
29024
|
-
textField = buildNavAidLabelExpression();
|
|
29025
|
-
}
|
|
29026
|
-
}
|
|
29027
|
-
if (depthUnits === "feet") {
|
|
29028
|
-
if (objectClass === "SOUNDG") {
|
|
29029
|
-
textField = [
|
|
29030
|
-
"concat",
|
|
29031
|
-
[
|
|
29032
|
-
"round",
|
|
29033
|
-
[
|
|
29034
|
-
"*",
|
|
29035
|
-
[
|
|
29036
|
-
"to-number",
|
|
29037
|
-
["coalesce", ["get", "depth"], ["get", "DEPTH"], ["get", "VALSOU"]],
|
|
29038
|
-
0
|
|
29039
|
-
],
|
|
29040
|
-
3.28084
|
|
29041
|
-
]
|
|
29042
|
-
],
|
|
29043
|
-
""
|
|
29044
|
-
];
|
|
29045
|
-
} else if (objectClass === "DEPCNT") {
|
|
29046
|
-
textField = [
|
|
29047
|
-
"concat",
|
|
29048
|
-
["round", ["*", ["to-number", ["get", "VALDCO"]], 3.28084]],
|
|
29049
|
-
"ft"
|
|
29050
|
-
];
|
|
29051
|
-
} else if (objectClass === "UWTROC" || objectClass === "OBSTRN" || objectClass === "WRECKS") {
|
|
29052
|
-
const valsouFt = [
|
|
29053
|
-
"to-number",
|
|
29054
|
-
["coalesce", ["get", "VALSOU"], ["get", "valsou"], 0],
|
|
29055
|
-
0
|
|
29056
|
-
];
|
|
29057
|
-
textField = [
|
|
29058
|
-
"case",
|
|
29059
|
-
[">", valsouFt, 0],
|
|
29060
|
-
["concat", ["to-string", ["round", ["*", valsouFt, 3.28084]]], "ft"],
|
|
29061
|
-
""
|
|
29062
|
-
];
|
|
29063
|
-
}
|
|
29064
|
-
}
|
|
29065
|
-
const labelPriority = getLabelPriority(objectClass);
|
|
29066
|
-
const layer = {
|
|
29067
|
-
id: `s52-${objectClass}-label`,
|
|
29068
|
-
type: "symbol",
|
|
29069
|
-
source: sourceId,
|
|
29070
|
-
"source-layer": objectClass,
|
|
29071
|
-
filter: GEOM_FILTERS.symbol,
|
|
29072
|
-
layout: {
|
|
29073
|
-
"text-field": textField,
|
|
29074
|
-
"text-size": config.textSize,
|
|
29075
|
-
"text-font": config.textFont ?? ["Open Sans Regular"],
|
|
29076
|
-
"text-offset": config.textOffset,
|
|
29077
|
-
"text-anchor": "top",
|
|
29078
|
-
"text-allow-overlap": false,
|
|
29079
|
-
"text-optional": true,
|
|
29080
|
-
"text-padding": 4,
|
|
29081
|
-
"symbol-sort-key": labelPriority * 1e3,
|
|
29082
|
-
...config.layout ?? {}
|
|
29083
|
-
},
|
|
29084
|
-
paint: {
|
|
29085
|
-
"text-color": config.textColor,
|
|
29086
|
-
"text-halo-color": config.textHaloColor,
|
|
29087
|
-
"text-halo-width": config.textHaloWidth
|
|
29088
|
-
},
|
|
29089
|
-
metadata: {
|
|
29090
|
-
"s52:objectClass": objectClass,
|
|
29091
|
-
"chrt:labelPriority": labelPriority
|
|
29092
|
-
}
|
|
29093
|
-
};
|
|
29094
|
-
if (config.minzoom) {
|
|
29095
|
-
layer.minzoom = config.minzoom;
|
|
29096
|
-
}
|
|
29097
|
-
if (objectClass === "DEPCNT") {
|
|
29098
|
-
layer.filter = GEOM_FILTERS.line;
|
|
29099
|
-
}
|
|
29100
|
-
if (objectClass === "CBLOHD" || objectClass === "PIPOHD") {
|
|
29101
|
-
layer.filter = GEOM_FILTERS.line;
|
|
29102
|
-
}
|
|
29103
|
-
if (objectClass === "SBDARE") {
|
|
29104
|
-
delete layer.filter;
|
|
29105
|
-
}
|
|
29106
|
-
if (objectClass === "MAGVAR") {
|
|
29107
|
-
delete layer.filter;
|
|
29108
|
-
}
|
|
29109
|
-
if (getLabelBehavior(objectClass) === "orientation-cross-band") {
|
|
29110
|
-
layer.filter = LABEL_ANCHOR_FILTER;
|
|
29111
|
-
}
|
|
29112
|
-
return applyDepthLabelSize(objectClass, layer, labelOpts.depthLabelSize);
|
|
29113
|
-
}
|
|
29114
|
-
function getGeomTypesForClass(objectClass, defaultType) {
|
|
29115
|
-
if (SYMBOL_MAP[objectClass] && defaultType === "symbol") {
|
|
29116
|
-
return ["symbol"];
|
|
29117
|
-
}
|
|
29118
|
-
if (objectClass === "SOUNDG") {
|
|
29119
|
-
return ["circle"];
|
|
29120
|
-
}
|
|
29121
|
-
if (defaultType) {
|
|
29122
|
-
return [defaultType];
|
|
29123
|
-
}
|
|
29124
|
-
return ["circle"];
|
|
29125
|
-
}
|
|
29126
|
-
function getOrderedClasses() {
|
|
29127
|
-
const ordered = [...S52_DRAW_ORDER];
|
|
29128
|
-
for (const key of Object.keys(S52_LOOKUP)) {
|
|
29129
|
-
if (!ordered.includes(key)) {
|
|
29130
|
-
const insertIdx = ordered.indexOf("SOUNDG");
|
|
29131
|
-
if (insertIdx >= 0) {
|
|
29132
|
-
ordered.splice(insertIdx, 0, key);
|
|
29133
|
-
} else {
|
|
29134
|
-
ordered.push(key);
|
|
29135
|
-
}
|
|
29803
|
+
metadata: { "s52:objectClass": "CANALS", "s52:role": "polygon" }
|
|
29804
|
+
});
|
|
29136
29805
|
}
|
|
29137
|
-
|
|
29138
|
-
|
|
29139
|
-
|
|
29140
|
-
|
|
29141
|
-
|
|
29142
|
-
|
|
29143
|
-
|
|
29144
|
-
|
|
29145
|
-
|
|
29146
|
-
|
|
29147
|
-
|
|
29148
|
-
|
|
29149
|
-
|
|
29150
|
-
|
|
29151
|
-
|
|
29152
|
-
|
|
29153
|
-
|
|
29154
|
-
|
|
29155
|
-
|
|
29156
|
-
|
|
29157
|
-
|
|
29158
|
-
|
|
29159
|
-
|
|
29160
|
-
|
|
29161
|
-
|
|
29162
|
-
|
|
29163
|
-
|
|
29164
|
-
if (
|
|
29165
|
-
|
|
29166
|
-
|
|
29167
|
-
|
|
29168
|
-
|
|
29169
|
-
|
|
29170
|
-
|
|
29171
|
-
|
|
29172
|
-
|
|
29173
|
-
|
|
29174
|
-
}
|
|
29175
|
-
|
|
29176
|
-
|
|
29177
|
-
|
|
29178
|
-
|
|
29179
|
-
|
|
29180
|
-
|
|
29181
|
-
|
|
29182
|
-
|
|
29183
|
-
|
|
29184
|
-
|
|
29185
|
-
|
|
29186
|
-
|
|
29187
|
-
|
|
29188
|
-
|
|
29189
|
-
|
|
29190
|
-
|
|
29191
|
-
|
|
29192
|
-
|
|
29193
|
-
|
|
29194
|
-
|
|
29195
|
-
|
|
29196
|
-
|
|
29197
|
-
|
|
29198
|
-
|
|
29199
|
-
|
|
29200
|
-
|
|
29201
|
-
|
|
29202
|
-
|
|
29203
|
-
|
|
29204
|
-
|
|
29205
|
-
"
|
|
29206
|
-
|
|
29207
|
-
|
|
29208
|
-
|
|
29209
|
-
|
|
29210
|
-
|
|
29211
|
-
|
|
29212
|
-
|
|
29213
|
-
"
|
|
29214
|
-
|
|
29215
|
-
|
|
29216
|
-
|
|
29217
|
-
|
|
29218
|
-
|
|
29219
|
-
|
|
29220
|
-
|
|
29221
|
-
|
|
29222
|
-
|
|
29223
|
-
|
|
29224
|
-
|
|
29225
|
-
"
|
|
29226
|
-
|
|
29227
|
-
"
|
|
29228
|
-
|
|
29229
|
-
|
|
29806
|
+
if (objectClass2 === "PILBOP" && resolved.type === "symbol") {
|
|
29807
|
+
layers.push({
|
|
29808
|
+
id: `s52-PILBOP-polygon`,
|
|
29809
|
+
type: "fill",
|
|
29810
|
+
source: sourceId,
|
|
29811
|
+
"source-layer": "PILBOP",
|
|
29812
|
+
filter: GEOM_FILTERS.fill,
|
|
29813
|
+
paint: {
|
|
29814
|
+
"fill-color": resolveColor("CHMGD", ct),
|
|
29815
|
+
"fill-opacity": 0.1
|
|
29816
|
+
},
|
|
29817
|
+
metadata: { "s52:objectClass": "PILBOP", "s52:role": "polygon" }
|
|
29818
|
+
});
|
|
29819
|
+
layers.push({
|
|
29820
|
+
id: `s52-PILBOP-polygon-outline`,
|
|
29821
|
+
type: "line",
|
|
29822
|
+
source: sourceId,
|
|
29823
|
+
"source-layer": "PILBOP",
|
|
29824
|
+
filter: GEOM_FILTERS.fill,
|
|
29825
|
+
paint: {
|
|
29826
|
+
"line-color": resolveColor("CHMGD", ct),
|
|
29827
|
+
"line-width": 0.8,
|
|
29828
|
+
"line-dasharray": [4, 2]
|
|
29829
|
+
},
|
|
29830
|
+
metadata: { "s52:objectClass": "PILBOP", "s52:role": "outline" }
|
|
29831
|
+
});
|
|
29832
|
+
}
|
|
29833
|
+
if (objectClass2 === "HRBFAC" && resolved.type === "circle") {
|
|
29834
|
+
layers.push({
|
|
29835
|
+
id: `s52-HRBFAC-polygon`,
|
|
29836
|
+
type: "fill",
|
|
29837
|
+
source: sourceId,
|
|
29838
|
+
"source-layer": "HRBFAC",
|
|
29839
|
+
filter: GEOM_FILTERS.fill,
|
|
29840
|
+
paint: {
|
|
29841
|
+
"fill-color": resolveColor("TRFCD", ct),
|
|
29842
|
+
"fill-opacity": 0.15
|
|
29843
|
+
},
|
|
29844
|
+
metadata: { "s52:objectClass": "HRBFAC", "s52:role": "polygon" }
|
|
29845
|
+
});
|
|
29846
|
+
}
|
|
29847
|
+
if (objectClass2 === "MARCUL" && resolved.type === "fill") {
|
|
29848
|
+
layers.push({
|
|
29849
|
+
id: `s52-MARCUL-point`,
|
|
29850
|
+
type: "circle",
|
|
29851
|
+
source: sourceId,
|
|
29852
|
+
"source-layer": "MARCUL",
|
|
29853
|
+
filter: GEOM_FILTERS.circle,
|
|
29854
|
+
paint: {
|
|
29855
|
+
"circle-color": resolveColor("CHBRN", ct),
|
|
29856
|
+
"circle-radius": ["interpolate", ["linear"], ["zoom"], 12, 1.2, 14, 1.8, 17, 2.6],
|
|
29857
|
+
"circle-stroke-color": resolveColor("CHBLK", ct),
|
|
29858
|
+
"circle-stroke-width": 0.4,
|
|
29859
|
+
"circle-opacity": 0.6
|
|
29860
|
+
},
|
|
29861
|
+
metadata: { "s52:objectClass": "MARCUL", "s52:role": "point" }
|
|
29862
|
+
});
|
|
29863
|
+
layers.push({
|
|
29864
|
+
id: `s52-MARCUL-line`,
|
|
29865
|
+
type: "line",
|
|
29866
|
+
source: sourceId,
|
|
29867
|
+
"source-layer": "MARCUL",
|
|
29868
|
+
filter: GEOM_FILTERS.line,
|
|
29869
|
+
paint: {
|
|
29870
|
+
"line-color": resolveColor("CHBLK", ct),
|
|
29871
|
+
"line-width": 0.5,
|
|
29872
|
+
"line-dasharray": [2, 2]
|
|
29873
|
+
},
|
|
29874
|
+
metadata: { "s52:objectClass": "MARCUL", "s52:role": "line" }
|
|
29875
|
+
});
|
|
29876
|
+
}
|
|
29877
|
+
if (objectClass2 === "RECTRC" && resolved.type === "line") {
|
|
29878
|
+
layers.push({
|
|
29879
|
+
id: `s52-RECTRC-polygon`,
|
|
29880
|
+
type: "fill",
|
|
29881
|
+
source: sourceId,
|
|
29882
|
+
"source-layer": "RECTRC",
|
|
29883
|
+
filter: GEOM_FILTERS.fill,
|
|
29884
|
+
paint: {
|
|
29885
|
+
"fill-color": resolveColor("TRFCD", ct),
|
|
29886
|
+
"fill-opacity": 0.05
|
|
29887
|
+
},
|
|
29888
|
+
metadata: { "s52:objectClass": "RECTRC", "s52:role": "polygon" }
|
|
29889
|
+
});
|
|
29890
|
+
}
|
|
29891
|
+
if (objectClass2 === "PONTON" && resolved.type === "fill") {
|
|
29892
|
+
layers.push({
|
|
29893
|
+
id: `s52-PONTON-line`,
|
|
29894
|
+
type: "line",
|
|
29895
|
+
source: sourceId,
|
|
29896
|
+
"source-layer": "PONTON",
|
|
29897
|
+
filter: GEOM_FILTERS.line,
|
|
29898
|
+
paint: {
|
|
29899
|
+
"line-color": resolveColor("CHGRF", ct),
|
|
29900
|
+
"line-width": 1.5
|
|
29901
|
+
},
|
|
29902
|
+
metadata: { "s52:objectClass": "PONTON", "s52:role": "line" }
|
|
29903
|
+
});
|
|
29904
|
+
}
|
|
29905
|
+
if (objectClass2 === "SILTNK" && resolved.type === "symbol") {
|
|
29906
|
+
layers.push({
|
|
29907
|
+
id: `s52-SILTNK-symbol-polygon`,
|
|
29908
|
+
type: "symbol",
|
|
29909
|
+
source: sourceId,
|
|
29910
|
+
"source-layer": "SILTNK",
|
|
29911
|
+
filter: GEOM_FILTERS.fill,
|
|
29912
|
+
layout: {
|
|
29913
|
+
"icon-image": "TNKCON02",
|
|
29914
|
+
"icon-size": 0.6,
|
|
29915
|
+
"icon-allow-overlap": true,
|
|
29916
|
+
"icon-ignore-placement": false,
|
|
29917
|
+
"symbol-placement": "point"
|
|
29918
|
+
},
|
|
29919
|
+
paint: {},
|
|
29920
|
+
metadata: { "s52:objectClass": "SILTNK", "s52:role": "symbol-polygon" }
|
|
29921
|
+
});
|
|
29922
|
+
}
|
|
29923
|
+
if (objectClass2 === "ACHBRT" && resolved.type === "symbol") {
|
|
29924
|
+
layers.push({
|
|
29925
|
+
id: `s52-ACHBRT-symbol-polygon`,
|
|
29926
|
+
type: "symbol",
|
|
29927
|
+
source: sourceId,
|
|
29928
|
+
"source-layer": "ACHBRT",
|
|
29929
|
+
filter: GEOM_FILTERS.fill,
|
|
29930
|
+
layout: {
|
|
29931
|
+
"icon-image": "ACHARE02",
|
|
29932
|
+
"icon-size": 0.5,
|
|
29933
|
+
"icon-allow-overlap": true,
|
|
29934
|
+
"icon-ignore-placement": false,
|
|
29935
|
+
"symbol-placement": "point"
|
|
29936
|
+
},
|
|
29937
|
+
paint: {},
|
|
29938
|
+
metadata: { "s52:objectClass": "ACHBRT", "s52:role": "symbol-polygon" }
|
|
29939
|
+
});
|
|
29940
|
+
}
|
|
29941
|
+
if (objectClass2 === "BERTHS" && resolved.type === "line") {
|
|
29942
|
+
layers.push({
|
|
29943
|
+
id: `s52-BERTHS-circle`,
|
|
29944
|
+
type: "circle",
|
|
29945
|
+
source: sourceId,
|
|
29946
|
+
"source-layer": "BERTHS",
|
|
29947
|
+
filter: GEOM_FILTERS.circle,
|
|
29948
|
+
paint: {
|
|
29949
|
+
"circle-color": resolveColor("CHBLK", ct),
|
|
29950
|
+
"circle-radius": ["interpolate", ["linear"], ["zoom"], 12, 1.5, 14, 2.2, 17, 3],
|
|
29951
|
+
"circle-stroke-color": resolveColor("CHBLK", ct),
|
|
29952
|
+
"circle-stroke-width": 0.5
|
|
29953
|
+
},
|
|
29954
|
+
metadata: { "s52:objectClass": "BERTHS", "s52:role": "point" }
|
|
29955
|
+
});
|
|
29956
|
+
}
|
|
29957
|
+
if (objectClass2 === "TUNNEL" && resolved.type === "line") {
|
|
29958
|
+
layers.push({
|
|
29959
|
+
// NOT `s52-TUNNEL-line` — that id is already taken by the main layer
|
|
29960
|
+
// (`s52-${objectClass}-${resolved.type}`), and duplicate layer ids
|
|
29961
|
+
// are a Mapbox style-spec violation (caught by style-integrity.test).
|
|
29962
|
+
id: `s52-TUNNEL-linestring`,
|
|
29963
|
+
type: "line",
|
|
29964
|
+
source: sourceId,
|
|
29965
|
+
"source-layer": "TUNNEL",
|
|
29966
|
+
filter: GEOM_FILTERS.line,
|
|
29967
|
+
paint: {
|
|
29968
|
+
"line-color": resolveColor("CHGRD", ct),
|
|
29969
|
+
"line-width": 1,
|
|
29970
|
+
"line-dasharray": [2, 2]
|
|
29971
|
+
},
|
|
29972
|
+
metadata: { "s52:objectClass": "TUNNEL", "s52:role": "line" }
|
|
29973
|
+
});
|
|
29230
29974
|
}
|
|
29231
|
-
];
|
|
29232
|
-
}
|
|
29233
|
-
|
|
29234
|
-
// src/atlas/band-priority.ts
|
|
29235
|
-
var BAND_PRIORITY_RANGES = {
|
|
29236
|
-
"1": { minzoom: 0 },
|
|
29237
|
-
"2": { minzoom: 5 },
|
|
29238
|
-
"3": { minzoom: 7 },
|
|
29239
|
-
"4": { minzoom: 9 },
|
|
29240
|
-
"5": { minzoom: 11 },
|
|
29241
|
-
"6": { minzoom: 11 }
|
|
29242
|
-
};
|
|
29243
|
-
var BAND_DATA_MINZOOM = {
|
|
29244
|
-
"1": 0,
|
|
29245
|
-
"2": 5,
|
|
29246
|
-
"3": 7,
|
|
29247
|
-
"4": 9,
|
|
29248
|
-
"5": 11,
|
|
29249
|
-
"6": 13
|
|
29250
|
-
};
|
|
29251
|
-
function dominatedVariantMaxzoom(D) {
|
|
29252
|
-
return Math.max(BAND_PRIORITY_RANGES[D].minzoom, BAND_DATA_MINZOOM[D]);
|
|
29253
|
-
}
|
|
29254
|
-
var DOMINANCE_EXEMPT_FILL_CLASSES = /* @__PURE__ */ new Set([
|
|
29255
|
-
"LNDARE",
|
|
29256
|
-
"DEPARE",
|
|
29257
|
-
"UNSARE",
|
|
29258
|
-
"LAKARE",
|
|
29259
|
-
"DRGARE",
|
|
29260
|
-
"SEAARE"
|
|
29261
|
-
]);
|
|
29262
|
-
function isExemptOpaqueFill(layer) {
|
|
29263
|
-
if (layer.type !== "fill") return false;
|
|
29264
|
-
for (const cls of DOMINANCE_EXEMPT_FILL_CLASSES) {
|
|
29265
|
-
if (layer.id.startsWith(`s52-${cls}-`)) return true;
|
|
29266
|
-
}
|
|
29267
|
-
return false;
|
|
29268
|
-
}
|
|
29269
|
-
var GROUND_FILL_CLASSES = /* @__PURE__ */ new Set([
|
|
29270
|
-
...DOMINANCE_EXEMPT_FILL_CLASSES,
|
|
29271
|
-
"RIVERS"
|
|
29272
|
-
]);
|
|
29273
|
-
function isGroundFill(layer) {
|
|
29274
|
-
if (layer.type !== "fill") return false;
|
|
29275
|
-
for (const cls of GROUND_FILL_CLASSES) {
|
|
29276
|
-
if (layer.id.startsWith(`s52-${cls}-`)) return true;
|
|
29277
|
-
}
|
|
29278
|
-
return false;
|
|
29279
|
-
}
|
|
29280
|
-
var FILL_FLOOR_FREE_BANDS = /* @__PURE__ */ new Set([
|
|
29281
|
-
"1",
|
|
29282
|
-
"2",
|
|
29283
|
-
"3"
|
|
29284
|
-
]);
|
|
29285
|
-
function bandVariantMinzoom(layer, B) {
|
|
29286
|
-
const classMinzoom = layer.minzoom ?? 0;
|
|
29287
|
-
if (isGroundFill(layer) && FILL_FLOOR_FREE_BANDS.has(B)) {
|
|
29288
|
-
return 0;
|
|
29289
|
-
}
|
|
29290
|
-
if (isGroundFill(layer)) {
|
|
29291
|
-
return BAND_PRIORITY_RANGES[B].minzoom;
|
|
29292
|
-
}
|
|
29293
|
-
return Math.max(classMinzoom, BAND_PRIORITY_RANGES[B].minzoom);
|
|
29294
|
-
}
|
|
29295
|
-
var GENERALISED_AREA_FILL_CLASSES = /* @__PURE__ */ new Set([
|
|
29296
|
-
"BUAARE",
|
|
29297
|
-
// 2026-08-28, New York Harbor: the "New York Marine Inspection Zone and
|
|
29298
|
-
// Captain of the Port Zone" RESARE exists at bands 2/3 as a generalized
|
|
29299
|
-
// shore-hugging polygon whose point-sampled dominance tag MISSED (the
|
|
29300
|
-
// Providence-BUAARE failure mode), so its magenta dashed boundary drew
|
|
29301
|
-
// OFFSET over the band-5 detail at z11.5 — read in the field as "a
|
|
29302
|
-
// magenta shoreline bleeding down from a less coarse band". The same
|
|
29303
|
-
// tile carried untagged band-2 ADMARE and CTNARE giants in the same
|
|
29304
|
-
// state. All three are area classes whose coarse-band boundaries hug
|
|
29305
|
-
// shorelines and whose fine-band copies are authoritative.
|
|
29306
|
-
"RESARE",
|
|
29307
|
-
"CTNARE",
|
|
29308
|
-
"ADMARE"
|
|
29309
|
-
]);
|
|
29310
|
-
var GENERALISED_AREA_MAX_BAND = 3;
|
|
29311
|
-
function generalisedAreaCeiling(layer, B) {
|
|
29312
|
-
if (layer.type !== "fill" && layer.type !== "line") return null;
|
|
29313
|
-
if (parseInt(B, 10) > GENERALISED_AREA_MAX_BAND) return null;
|
|
29314
|
-
for (const cls of GENERALISED_AREA_FILL_CLASSES) {
|
|
29315
|
-
if (layer.id.startsWith(`s52-${cls}-`)) return BAND_PRIORITY_RANGES["5"].minzoom;
|
|
29316
|
-
}
|
|
29317
|
-
return null;
|
|
29318
|
-
}
|
|
29319
|
-
var BAND_DRAW_ORDER = ["1", "2", "3", "4", "5", "6"];
|
|
29320
|
-
var CHART_BAND_CODES = {
|
|
29321
|
-
Overview: ["1"],
|
|
29322
|
-
General: ["2"],
|
|
29323
|
-
Coastal: ["3"],
|
|
29324
|
-
Approach: ["4"],
|
|
29325
|
-
Harbor: ["5", "6"]
|
|
29326
|
-
};
|
|
29327
|
-
var CHART_CASCADE_CODES = {
|
|
29328
|
-
Overview: ["1"],
|
|
29329
|
-
General: ["1", "2"],
|
|
29330
|
-
Coastal: ["1", "2", "3"],
|
|
29331
|
-
Approach: ["1", "2", "3", "4"],
|
|
29332
|
-
Harbor: ["1", "2", "3", "4", "5", "6"]
|
|
29333
|
-
};
|
|
29334
|
-
var CHRT_STYLE_MODES = [
|
|
29335
|
-
"continuous",
|
|
29336
|
-
...Object.keys(CHART_BAND_CODES).map(
|
|
29337
|
-
(band) => `chart:${band}`
|
|
29338
|
-
)
|
|
29339
|
-
];
|
|
29340
|
-
function normalizeStyleMode(raw) {
|
|
29341
|
-
if (raw === null || raw === void 0 || raw === "") return "continuous";
|
|
29342
|
-
const lower = raw.toLowerCase();
|
|
29343
|
-
return CHRT_STYLE_MODES.find((mode) => mode.toLowerCase() === lower) ?? null;
|
|
29344
|
-
}
|
|
29345
|
-
function styleModeBand(mode) {
|
|
29346
|
-
return mode === "continuous" ? null : mode.slice("chart:".length);
|
|
29347
|
-
}
|
|
29348
|
-
function bandFilterExpression(codes) {
|
|
29349
|
-
return cellBandMatch(["slice", ["get", "_cell_id"], 2, 3], codes);
|
|
29350
|
-
}
|
|
29351
|
-
var BAND_CODE_ALIASES = {
|
|
29352
|
-
"5": ["7"]
|
|
29353
|
-
};
|
|
29354
|
-
function cellBandCharacters(code) {
|
|
29355
|
-
return [code, ...BAND_CODE_ALIASES[code] ?? []];
|
|
29356
|
-
}
|
|
29357
|
-
function cellBandMatch(cellBandExpr, codes) {
|
|
29358
|
-
const list = Array.isArray(codes) ? codes : [codes];
|
|
29359
|
-
const chars = [...new Set(list.flatMap((c) => cellBandCharacters(c)))];
|
|
29360
|
-
if (chars.length === 1) {
|
|
29361
|
-
return ["==", cellBandExpr, chars[0]];
|
|
29362
29975
|
}
|
|
29363
|
-
return
|
|
29976
|
+
return layers;
|
|
29364
29977
|
}
|
|
29365
|
-
function
|
|
29366
|
-
if (!
|
|
29367
|
-
|
|
29368
|
-
|
|
29978
|
+
function buildLabelLayer2(objectClass2, ct, sourceId = DEFAULT_REGION, depthUnits = "meters", labelOpts = {}) {
|
|
29979
|
+
if (!LABELED_LAYERS.has(objectClass2)) return null;
|
|
29980
|
+
const config = getLabelConfig(objectClass2, {
|
|
29981
|
+
colorTable: ct,
|
|
29982
|
+
safetyContour: labelOpts.safetyContour,
|
|
29983
|
+
twoShadeSoundings: labelOpts.twoShadeSoundings,
|
|
29984
|
+
soundingFontWeight: labelOpts.soundingFontWeight
|
|
29985
|
+
});
|
|
29986
|
+
if (!config) return null;
|
|
29987
|
+
let textField = config.textField;
|
|
29988
|
+
if (objectClass2 === "LIGHTS") {
|
|
29989
|
+
textField = buildLightLabelExpression();
|
|
29369
29990
|
}
|
|
29370
|
-
|
|
29371
|
-
|
|
29372
|
-
|
|
29373
|
-
|
|
29374
|
-
|
|
29375
|
-
["!=", ["get", "_dominated"], true]
|
|
29376
|
-
];
|
|
29377
|
-
function dominatedByMinFilter(D) {
|
|
29378
|
-
const dInt = parseInt(D, 10);
|
|
29379
|
-
if (D === "6") {
|
|
29380
|
-
return [
|
|
29381
|
-
"any",
|
|
29382
|
-
["==", ["get", "_dominated_by_min"], dInt],
|
|
29383
|
-
["==", ["get", "_dominated"], true]
|
|
29384
|
-
];
|
|
29991
|
+
if (typeof textField !== "string" && Array.isArray(textField)) {
|
|
29992
|
+
const flat = JSON.stringify(textField);
|
|
29993
|
+
if (flat.includes("_navAidLabel")) {
|
|
29994
|
+
textField = buildNavAidLabelExpression();
|
|
29995
|
+
}
|
|
29385
29996
|
}
|
|
29386
|
-
|
|
29387
|
-
|
|
29388
|
-
|
|
29389
|
-
|
|
29390
|
-
const [e, n] = bbox.ne;
|
|
29391
|
-
return [
|
|
29392
|
-
"within",
|
|
29393
|
-
{
|
|
29394
|
-
type: "Polygon",
|
|
29395
|
-
coordinates: [
|
|
29997
|
+
if (depthUnits === "feet") {
|
|
29998
|
+
if (objectClass2 === "SOUNDG") {
|
|
29999
|
+
textField = [
|
|
30000
|
+
"concat",
|
|
29396
30001
|
[
|
|
29397
|
-
|
|
29398
|
-
[
|
|
29399
|
-
|
|
29400
|
-
|
|
29401
|
-
|
|
29402
|
-
|
|
29403
|
-
|
|
30002
|
+
"round",
|
|
30003
|
+
[
|
|
30004
|
+
"*",
|
|
30005
|
+
[
|
|
30006
|
+
"to-number",
|
|
30007
|
+
["coalesce", ["get", "depth"], ["get", "DEPTH"], ["get", "VALSOU"]],
|
|
30008
|
+
0
|
|
30009
|
+
],
|
|
30010
|
+
3.28084
|
|
30011
|
+
]
|
|
30012
|
+
],
|
|
30013
|
+
""
|
|
30014
|
+
];
|
|
30015
|
+
} else if (objectClass2 === "DEPCNT") {
|
|
30016
|
+
textField = [
|
|
30017
|
+
"concat",
|
|
30018
|
+
["round", ["*", ["to-number", ["get", "VALDCO"]], 3.28084]],
|
|
30019
|
+
"ft"
|
|
30020
|
+
];
|
|
30021
|
+
} else if (objectClass2 === "UWTROC" || objectClass2 === "OBSTRN" || objectClass2 === "WRECKS") {
|
|
30022
|
+
const valsouFt = [
|
|
30023
|
+
"to-number",
|
|
30024
|
+
["coalesce", ["get", "VALSOU"], ["get", "valsou"], 0],
|
|
30025
|
+
0
|
|
30026
|
+
];
|
|
30027
|
+
textField = [
|
|
30028
|
+
"case",
|
|
30029
|
+
[">", valsouFt, 0],
|
|
30030
|
+
["concat", ["to-string", ["round", ["*", valsouFt, 3.28084]]], "ft"],
|
|
30031
|
+
""
|
|
30032
|
+
];
|
|
30033
|
+
}
|
|
30034
|
+
}
|
|
30035
|
+
const labelPriority = getLabelPriority(objectClass2);
|
|
30036
|
+
const layer = {
|
|
30037
|
+
id: `s52-${objectClass2}-label`,
|
|
30038
|
+
type: "symbol",
|
|
30039
|
+
source: sourceId,
|
|
30040
|
+
"source-layer": objectClass2,
|
|
30041
|
+
filter: GEOM_FILTERS.symbol,
|
|
30042
|
+
layout: {
|
|
30043
|
+
"text-field": textField,
|
|
30044
|
+
"text-size": config.textSize,
|
|
30045
|
+
"text-font": config.textFont ?? ["Open Sans Regular"],
|
|
30046
|
+
"text-offset": config.textOffset,
|
|
30047
|
+
"text-anchor": "top",
|
|
30048
|
+
"text-allow-overlap": false,
|
|
30049
|
+
"text-optional": true,
|
|
30050
|
+
"text-padding": 4,
|
|
30051
|
+
"symbol-sort-key": labelPriority * 1e3,
|
|
30052
|
+
...config.layout ?? {}
|
|
30053
|
+
},
|
|
30054
|
+
paint: {
|
|
30055
|
+
"text-color": config.textColor,
|
|
30056
|
+
"text-halo-color": config.textHaloColor,
|
|
30057
|
+
"text-halo-width": config.textHaloWidth
|
|
30058
|
+
},
|
|
30059
|
+
metadata: {
|
|
30060
|
+
"s52:objectClass": objectClass2,
|
|
30061
|
+
"chrt:labelPriority": labelPriority
|
|
29404
30062
|
}
|
|
29405
|
-
];
|
|
29406
|
-
}
|
|
29407
|
-
function worldMinusBboxPolygon(bbox) {
|
|
29408
|
-
const [w, s] = bbox.sw;
|
|
29409
|
-
const [e, n] = bbox.ne;
|
|
29410
|
-
return {
|
|
29411
|
-
type: "Polygon",
|
|
29412
|
-
coordinates: [
|
|
29413
|
-
[
|
|
29414
|
-
[-180, -85],
|
|
29415
|
-
[180, -85],
|
|
29416
|
-
[180, 85],
|
|
29417
|
-
[-180, 85],
|
|
29418
|
-
[-180, -85]
|
|
29419
|
-
],
|
|
29420
|
-
// Inner ring (hole) — winding opposite to outer ring per GeoJSON
|
|
29421
|
-
// spec. MapLibre is permissive but we follow strict winding.
|
|
29422
|
-
[
|
|
29423
|
-
[w, s],
|
|
29424
|
-
[w, n],
|
|
29425
|
-
[e, n],
|
|
29426
|
-
[e, s],
|
|
29427
|
-
[w, s]
|
|
29428
|
-
]
|
|
29429
|
-
]
|
|
29430
30063
|
};
|
|
30064
|
+
if (config.minzoom) {
|
|
30065
|
+
layer.minzoom = config.minzoom;
|
|
30066
|
+
}
|
|
30067
|
+
if (objectClass2 === "DEPCNT") {
|
|
30068
|
+
layer.filter = GEOM_FILTERS.line;
|
|
30069
|
+
}
|
|
30070
|
+
if (objectClass2 === "CBLOHD" || objectClass2 === "PIPOHD") {
|
|
30071
|
+
layer.filter = GEOM_FILTERS.line;
|
|
30072
|
+
}
|
|
30073
|
+
if (objectClass2 === "SBDARE") {
|
|
30074
|
+
delete layer.filter;
|
|
30075
|
+
}
|
|
30076
|
+
if (objectClass2 === "MAGVAR") {
|
|
30077
|
+
delete layer.filter;
|
|
30078
|
+
}
|
|
30079
|
+
if (getLabelBehavior(objectClass2) === "orientation-cross-band") {
|
|
30080
|
+
layer.filter = LABEL_ANCHOR_FILTER;
|
|
30081
|
+
}
|
|
30082
|
+
return applyDepthLabelSize(objectClass2, layer, labelOpts.depthLabelSize);
|
|
29431
30083
|
}
|
|
29432
|
-
|
|
29433
|
-
|
|
29434
|
-
|
|
29435
|
-
var UNCHARTED_PATTERN = "chrt:hatch-uncharted";
|
|
29436
|
-
function inlandWaterColor(palette) {
|
|
29437
|
-
return (BASE_THEMES[palette] ?? BASE_THEMES.DAY).inlandWater;
|
|
29438
|
-
}
|
|
29439
|
-
var BASE_THEMES = {
|
|
29440
|
-
DAY: {
|
|
29441
|
-
// ── `earth` is the jurisdiction tan DIMMED (~0.55), not a blue-grey ──
|
|
29442
|
-
// Outside the jurisdiction the map still owes the reader "what is land".
|
|
29443
|
-
// State 3 in the header is "the geography, under a crosshatch", and until
|
|
29444
|
-
// 2026-08-31 that geography was unreadable: earth #2A3439 against sea
|
|
29445
|
-
// #1B2328 measured 1.25:1, so Hispaniola showed charted boxes with tan
|
|
29446
|
-
// land inside and nothing recognisable around them (owner report: "no
|
|
29447
|
-
// land painting down near the DR at some zooms"). Land is warm and sea is
|
|
29448
|
-
// cool because that is what land and sea are; dimming the JURISDICTION
|
|
29449
|
-
// tan rather than inventing a colour says the true thing — this is the
|
|
29450
|
-
// same land, we simply do not carry charts for it. Held against BOTH
|
|
29451
|
-
// neighbours: legible over sea, and never mistakable for the full tan of
|
|
29452
|
-
// a country we do carry. DAY 3.59:1 vs sea, 3.17:1 vs tan.
|
|
29453
|
-
earth: "#807761",
|
|
29454
|
-
water: "#1B2328",
|
|
29455
|
-
river: "#24313A",
|
|
29456
|
-
boundary: "#4A575E",
|
|
29457
|
-
jurisdiction: "#D4C69D",
|
|
29458
|
-
// CHRTland's own tan — one land colour
|
|
29459
|
-
inlandWater: "#B9CFDD",
|
|
29460
|
-
// muted, unmistakably not a charted blue
|
|
29461
|
-
// The uncharted hatch's stripe, held to 2.3:1 against `inlandWater` in
|
|
29462
|
-
// every palette (`inland-hatch-contrast.test.ts`) — the hatch says "we have
|
|
29463
|
-
// not charted this water", and stripes the eye cannot find say nothing.
|
|
29464
|
-
// DAY 3.08:1, darker than its ground. Also the colour the artwork file
|
|
29465
|
-
// itself is drawn in.
|
|
29466
|
-
inlandHatch: "#5B7383",
|
|
29467
|
-
// State furniture. These three were referenced by the layers but missing
|
|
29468
|
-
// from this table (and its type — the long-standing TS2339 trio), so the
|
|
29469
|
-
// lines shipped on MapLibre's DEFAULT black. Now deliberate: a hairline
|
|
29470
|
-
// a shade deeper than the tan, quiet caps, tan halo.
|
|
29471
|
-
stateLine: "#B1A077",
|
|
29472
|
-
stateLabel: "#8E8468",
|
|
29473
|
-
stateHalo: "#D4C69D",
|
|
29474
|
-
// Rough-lake furniture (owner ask 2026-08-28: "the lakes need labels,
|
|
29475
|
-
// and shorelines drawn"): a shoreline a shade deeper than the rough
|
|
29476
|
-
// water, and a name in the water's own voice, haloed by the water.
|
|
29477
|
-
inlandShore: "#8FA9BA",
|
|
29478
|
-
inlandLabel: "#54707F",
|
|
29479
|
-
inlandHalo: "#B9CFDD"
|
|
29480
|
-
},
|
|
29481
|
-
DUSK: {
|
|
29482
|
-
// ── Re-derived 2026-09-01: the basemap sits UNDER the chart ──────────
|
|
29483
|
-
// These were the DAY tones scaled by a constant, never measured against
|
|
29484
|
-
// the DUSK chart — so `jurisdiction` came out at L=0.506 against a chart
|
|
29485
|
-
// whose own land (LANDA #8a7d5e) is L=0.209, i.e. the context layer was
|
|
29486
|
-
// 2.4x brighter than the data layer. Now capped at the chart's own land.
|
|
29487
|
-
// The rest of the block rides the same 0.666 channel factor so every
|
|
29488
|
-
// relationship the palette already chose is preserved, only moved down.
|
|
29489
|
-
// `water` is deliberately NOT scaled: it is the reference the land/sea
|
|
29490
|
-
// floor is measured against.
|
|
29491
|
-
earth: "#544E3E",
|
|
29492
|
-
water: "#161D21",
|
|
29493
|
-
river: "#141B20",
|
|
29494
|
-
boundary: "#293135",
|
|
29495
|
-
jurisdiction: "#867D64",
|
|
29496
|
-
inlandWater: "#62717A",
|
|
29497
|
-
// Owner's choice, 2026-10-04: dark stripes, 2.37:1. The DAY stripe here
|
|
29498
|
-
// was 1.02:1 — invisible, so an uncharted lake read as plain water.
|
|
29499
|
-
inlandHatch: "#2E383F",
|
|
29500
|
-
// Label stays DARK here — the halo is still mid-toned, so 3:1 is reachable
|
|
29501
|
-
// downward and a bright label would be a new light source at dusk.
|
|
29502
|
-
stateLine: "#B5A987",
|
|
29503
|
-
stateLabel: "#38342A",
|
|
29504
|
-
stateHalo: "#867D64",
|
|
29505
|
-
inlandShore: "#4D5B67",
|
|
29506
|
-
inlandLabel: "#212629",
|
|
29507
|
-
inlandHalo: "#62717A"
|
|
29508
|
-
},
|
|
29509
|
-
NIGHT: {
|
|
29510
|
-
// ── Re-derived 2026-09-01 — the owner-reported night defect ──────────
|
|
29511
|
-
// `jurisdiction` was L=0.240 against a chart whose own land (LANDA
|
|
29512
|
-
// #3a3020) is L=0.031: the world basemap was 7.7x BRIGHTER than the chart
|
|
29513
|
-
// it sits under, so at z<11 the uncharted interior read as a pale
|
|
29514
|
-
// continent-sized slab on a night chart. Capped at the chart's own land.
|
|
29515
|
-
//
|
|
29516
|
-
// ⚠ `earth` AND `jurisdiction` CONVERGE HERE, and that is forced, not
|
|
29517
|
-
// sloppy. Holding earth 2:1 above the ocean AND 2:1 below the jurisdiction
|
|
29518
|
-
// tan requires jurisdiction >= L 0.174 — 5.6x the chart's own land. At
|
|
29519
|
-
// night the range between the ocean (L 0.006) and the cap (L 0.031) is too
|
|
29520
|
-
// compressed to carry two land tones. COVERAGE IS STILL SAID, by the
|
|
29521
|
-
// `chrt:hatch-nocoverage` crosshatch, which is a stronger signal than tone
|
|
29522
|
-
// and is the one thing that cannot be lost to palette compression.
|
|
29523
|
-
//
|
|
29524
|
-
// Labels invert to light-on-dark: 3:1 downward is unreachable off a halo
|
|
29525
|
-
// this close to black, and CHRTland's own night town labels already sit at
|
|
29526
|
-
// L=0.177 for exactly this reason.
|
|
29527
|
-
earth: "#333026",
|
|
29528
|
-
water: "#10161A",
|
|
29529
|
-
river: "#090D0F",
|
|
29530
|
-
boundary: "#131719",
|
|
29531
|
-
jurisdiction: "#353128",
|
|
29532
|
-
inlandWater: "#232A30",
|
|
29533
|
-
// The DAY stripe, lighter than this ground: 2.92:1, and L 0.16, under the
|
|
29534
|
-
// NIGHT muted-ink ceiling (`night-luminance.test.ts`). Red night draws the
|
|
29535
|
-
// NIGHT chart, so this is its stripe too.
|
|
29536
|
-
inlandHatch: "#5B7383",
|
|
29537
|
-
stateLine: "#484236",
|
|
29538
|
-
stateLabel: "#837963",
|
|
29539
|
-
stateHalo: "#353128",
|
|
29540
|
-
inlandShore: "#1C2227",
|
|
29541
|
-
inlandLabel: "#617484",
|
|
29542
|
-
inlandHalo: "#232A30"
|
|
30084
|
+
function getGeomTypesForClass(objectClass2, defaultType) {
|
|
30085
|
+
if (SYMBOL_MAP[objectClass2] && defaultType === "symbol") {
|
|
30086
|
+
return ["symbol"];
|
|
29543
30087
|
}
|
|
29544
|
-
|
|
29545
|
-
|
|
29546
|
-
|
|
29547
|
-
|
|
29548
|
-
|
|
29549
|
-
|
|
29550
|
-
return [
|
|
29551
|
-
|
|
29552
|
-
|
|
29553
|
-
|
|
29554
|
-
|
|
29555
|
-
|
|
29556
|
-
|
|
29557
|
-
|
|
29558
|
-
|
|
29559
|
-
|
|
29560
|
-
|
|
29561
|
-
}),
|
|
29562
|
-
L({
|
|
29563
|
-
id: "chrtbase-earth",
|
|
29564
|
-
type: "fill",
|
|
29565
|
-
source: src,
|
|
29566
|
-
"source-layer": "base_earth",
|
|
29567
|
-
paint: { "fill-color": T.earth }
|
|
29568
|
-
}),
|
|
29569
|
-
L({
|
|
29570
|
-
id: "chrtbase-water",
|
|
29571
|
-
type: "fill",
|
|
29572
|
-
source: src,
|
|
29573
|
-
"source-layer": "base_water",
|
|
29574
|
-
paint: { "fill-color": T.water }
|
|
29575
|
-
}),
|
|
29576
|
-
L({
|
|
29577
|
-
id: "chrtbase-river",
|
|
29578
|
-
type: "line",
|
|
29579
|
-
source: src,
|
|
29580
|
-
"source-layer": "base_river",
|
|
29581
|
-
minzoom: 9,
|
|
29582
|
-
paint: {
|
|
29583
|
-
"line-color": T.river,
|
|
29584
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 9, 0.6, 14, 1.6]
|
|
29585
|
-
}
|
|
29586
|
-
}),
|
|
29587
|
-
L({
|
|
29588
|
-
id: "chrtbase-boundary",
|
|
29589
|
-
type: "line",
|
|
29590
|
-
source: src,
|
|
29591
|
-
"source-layer": "base_boundary",
|
|
29592
|
-
paint: { "line-color": T.boundary, "line-width": 0.6, "line-opacity": 0.8 }
|
|
29593
|
-
}),
|
|
29594
|
-
// 2. THE DEFAULT: no coverage, everywhere, as a geometry-free background.
|
|
29595
|
-
// Constant opacity by design — see the header. What kills it is being
|
|
29596
|
-
// painted OVER, never fading.
|
|
29597
|
-
L({
|
|
29598
|
-
id: "chrtbase-nocoverage",
|
|
29599
|
-
type: "background",
|
|
29600
|
-
paint: { "background-pattern": NOCOVERAGE_PATTERN, "background-opacity": 0.55 }
|
|
29601
|
-
}),
|
|
29602
|
-
// 3. The jurisdiction: countries whose charts CHRT carries go tan — the
|
|
29603
|
-
// same tan as CHRTland, so "land in our world" is ONE colour. Opaque,
|
|
29604
|
-
// so it takes the crosshatch off its ground entirely.
|
|
29605
|
-
L({
|
|
29606
|
-
id: "chrtbase-jurisdiction",
|
|
29607
|
-
type: "fill",
|
|
29608
|
-
source: src,
|
|
29609
|
-
"source-layer": "jurisdiction",
|
|
29610
|
-
paint: { "fill-color": T.jurisdiction }
|
|
29611
|
-
}),
|
|
29612
|
-
// 4. States — internal boundaries and names, inside the jurisdiction
|
|
29613
|
-
// only (owner decision 2026-08-28). A hairline a shade deeper than the
|
|
29614
|
-
// tan, and quiet letter-spaced caps that fade as harbour detail takes
|
|
29615
|
-
// over. The one deliberate exception to no-names-on-the-basemap:
|
|
29616
|
-
// ADMIN furniture, nothing else — see the fence test.
|
|
29617
|
-
L({
|
|
29618
|
-
id: "chrtbase-state-boundary",
|
|
29619
|
-
type: "line",
|
|
29620
|
-
source: src,
|
|
29621
|
-
"source-layer": "state_boundary",
|
|
29622
|
-
minzoom: 4,
|
|
29623
|
-
paint: {
|
|
29624
|
-
"line-color": T.stateLine,
|
|
29625
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 4, 0.5, 10, 1],
|
|
29626
|
-
"line-dasharray": [3, 2],
|
|
29627
|
-
"line-opacity": 0.8
|
|
29628
|
-
}
|
|
29629
|
-
}),
|
|
29630
|
-
// 5. Country borders, drawn to be HOISTED above the whole chart by the
|
|
29631
|
-
// generator (owner, 2026-08-31: "where there is charted land, can we
|
|
29632
|
-
// add country borders on top of everything? I want it clear where
|
|
29633
|
-
// there is a boarder."). Sourced from NE boundary_lines_land — land
|
|
29634
|
-
// borders only, never coastline — so riding on top cannot stroke a
|
|
29635
|
-
// coast. Dashed so it reads as an administrative line, not chart
|
|
29636
|
-
// linework.
|
|
29637
|
-
L({
|
|
29638
|
-
id: "chrtbase-country-boundary",
|
|
29639
|
-
type: "line",
|
|
29640
|
-
source: src,
|
|
29641
|
-
"source-layer": "country_boundary",
|
|
29642
|
-
paint: {
|
|
29643
|
-
"line-color": T.boundary,
|
|
29644
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 3, 0.8, 8, 1.4, 12, 2.2],
|
|
29645
|
-
"line-dasharray": [4, 2],
|
|
29646
|
-
"line-opacity": 0.9
|
|
29647
|
-
}
|
|
29648
|
-
}),
|
|
29649
|
-
L({
|
|
29650
|
-
id: "chrtbase-state-label",
|
|
29651
|
-
type: "symbol",
|
|
29652
|
-
source: src,
|
|
29653
|
-
"source-layer": "state_label",
|
|
29654
|
-
minzoom: 4,
|
|
29655
|
-
maxzoom: 10,
|
|
29656
|
-
layout: {
|
|
29657
|
-
"text-field": ["upcase", ["get", "name"]],
|
|
29658
|
-
"text-font": ["Open Sans Regular"],
|
|
29659
|
-
"text-size": ["interpolate", ["linear"], ["zoom"], 4, 9, 8, 12],
|
|
29660
|
-
"text-letter-spacing": 0.25,
|
|
29661
|
-
"text-allow-overlap": false,
|
|
29662
|
-
"text-padding": 8
|
|
29663
|
-
},
|
|
29664
|
-
paint: {
|
|
29665
|
-
"text-color": T.stateLabel,
|
|
29666
|
-
"text-halo-color": T.stateHalo,
|
|
29667
|
-
"text-halo-width": 1.2,
|
|
29668
|
-
"text-opacity": ["interpolate", ["linear"], ["zoom"], 4, 0.7, 8, 0.85, 10, 0.4]
|
|
30088
|
+
if (objectClass2 === "SOUNDG") {
|
|
30089
|
+
return ["circle"];
|
|
30090
|
+
}
|
|
30091
|
+
if (defaultType) {
|
|
30092
|
+
return [defaultType];
|
|
30093
|
+
}
|
|
30094
|
+
return ["circle"];
|
|
30095
|
+
}
|
|
30096
|
+
function getOrderedClasses() {
|
|
30097
|
+
const ordered = [...S52_DRAW_ORDER];
|
|
30098
|
+
for (const key of Object.keys(S52_LOOKUP)) {
|
|
30099
|
+
if (!ordered.includes(key)) {
|
|
30100
|
+
const insertIdx = ordered.indexOf("SOUNDG");
|
|
30101
|
+
if (insertIdx >= 0) {
|
|
30102
|
+
ordered.splice(insertIdx, 0, key);
|
|
30103
|
+
} else {
|
|
30104
|
+
ordered.push(key);
|
|
29669
30105
|
}
|
|
29670
|
-
}
|
|
29671
|
-
|
|
30106
|
+
}
|
|
30107
|
+
}
|
|
30108
|
+
return ordered;
|
|
29672
30109
|
}
|
|
29673
|
-
|
|
29674
|
-
|
|
29675
|
-
|
|
29676
|
-
|
|
29677
|
-
|
|
29678
|
-
|
|
29679
|
-
|
|
29680
|
-
|
|
30110
|
+
|
|
30111
|
+
// src/atlas/terrain-order.ts
|
|
30112
|
+
var DRAPEABLE_LAYER_TYPES = /* @__PURE__ */ new Set([
|
|
30113
|
+
"background",
|
|
30114
|
+
"fill",
|
|
30115
|
+
"line",
|
|
30116
|
+
"raster",
|
|
30117
|
+
"hillshade",
|
|
30118
|
+
"color-relief"
|
|
30119
|
+
]);
|
|
30120
|
+
function isDrapeable(layer) {
|
|
30121
|
+
return DRAPEABLE_LAYER_TYPES.has(layer.type);
|
|
30122
|
+
}
|
|
30123
|
+
function drapedFirst(layers) {
|
|
30124
|
+
const draped = [];
|
|
30125
|
+
const direct = [];
|
|
30126
|
+
for (const l of layers) (isDrapeable(l) ? draped : direct).push(l);
|
|
30127
|
+
return [...draped, ...direct];
|
|
30128
|
+
}
|
|
30129
|
+
function terrainStackCount(layers) {
|
|
30130
|
+
let stacks = 0;
|
|
30131
|
+
let prevDraped = false;
|
|
30132
|
+
for (const l of layers) {
|
|
30133
|
+
const d = isDrapeable(l);
|
|
30134
|
+
if (d && !prevDraped) stacks++;
|
|
30135
|
+
prevDraped = d;
|
|
30136
|
+
}
|
|
30137
|
+
return stacks;
|
|
30138
|
+
}
|
|
30139
|
+
function drapeHalves(layers) {
|
|
30140
|
+
const draped = [];
|
|
30141
|
+
const direct = [];
|
|
30142
|
+
for (const l of layers) (isDrapeable(l) ? draped : direct).push(l);
|
|
30143
|
+
return { draped, direct };
|
|
30144
|
+
}
|
|
30145
|
+
|
|
30146
|
+
// src/atlas/lamps.ts
|
|
30147
|
+
var LAMP_GLOW_LAYER_ID = "s52-LIGHTS-lamp-glow";
|
|
30148
|
+
var LAMP_CORE_LAYER_ID = "s52-LIGHTS-lamp-core";
|
|
30149
|
+
var LAMP_LAYER_IDS = [LAMP_GLOW_LAYER_ID, LAMP_CORE_LAYER_ID];
|
|
30150
|
+
var RANGE_NM = ["to-number", ["coalesce", ["get", "VALNMR"], ["get", "valnmr"]], 6];
|
|
30151
|
+
var UNSECTORED_POINTS = [
|
|
30152
|
+
"all",
|
|
30153
|
+
["any", ["==", ["geometry-type"], "Point"], ["==", ["geometry-type"], "MultiPoint"]],
|
|
30154
|
+
["!", ["has", "SECTR1"]],
|
|
30155
|
+
// …and not lights with a charted rhythm either: those flash, and the
|
|
30156
|
+
// flashing is computed by the app from `SIGSEQ` (light-sigseq.ts). What is
|
|
30157
|
+
// left here is exactly the set that is steady from every bearing.
|
|
30158
|
+
["!", ["has", "SIGSEQ"]]
|
|
30159
|
+
];
|
|
30160
|
+
function buildLampLayers(sourceId, ct) {
|
|
30161
|
+
const colour = lightFillExpression(ct);
|
|
30162
|
+
const common = {
|
|
30163
|
+
type: "circle",
|
|
30164
|
+
source: sourceId,
|
|
30165
|
+
"source-layer": "LIGHTS",
|
|
30166
|
+
filter: UNSECTORED_POINTS,
|
|
30167
|
+
layout: { visibility: "none" }
|
|
30168
|
+
};
|
|
30169
|
+
const metadata = { "chrt:role": "lamp", "s52:objectClass": "LIGHTS" };
|
|
29681
30170
|
return [
|
|
29682
|
-
|
|
29683
|
-
|
|
29684
|
-
|
|
29685
|
-
// name), and an unsplit fill draws BOTH — which means the NE polygon is
|
|
29686
|
-
// painted over the planet one at every zoom. That is not a cosmetic
|
|
29687
|
-
// double-draw: NE 10m carries no interior rings, so its blob has no
|
|
29688
|
-
// ISLANDS in it, and painting it over the planet's holed polygons buries
|
|
29689
|
-
// every island in the lake under "uncharted water". Owner-reported at
|
|
29690
|
-
// Winnipesaukee z11.7 ("there is land (and islands) being covered by the
|
|
29691
|
-
// 'no chart here' boundary"), and measured: rendering the planet tier
|
|
29692
|
-
// alone brings back the whole archipelago — Rattlesnake, Bear, Long
|
|
29693
|
-
// Island, Diamond, the Barndoors — while the NE tier alone is a faceted
|
|
29694
|
-
// blob whose edges bear no relation to the shoreline drawn beneath it.
|
|
29695
|
-
//
|
|
29696
|
-
// So each tier owns its own zoom range, the same handover the shoreline
|
|
29697
|
-
// below uses. Known residue, measured over the whole archive: of the 141
|
|
29698
|
-
// NE lakes we still carry, 138 have planet water beneath them; the
|
|
29699
|
-
// exceptions are two unnamed western-Alaska tundra lakes and a 2e-5 deg²
|
|
29700
|
-
// Lake Michigan sliver, which lose their rough fill above z9 because the
|
|
29701
|
-
// planet has no `water` polygon there at all (checked against the raw
|
|
29702
|
-
// pre-clip NDJSON — not a clip artefact).
|
|
29703
|
-
L({
|
|
29704
|
-
id: "chrtbase-inland-water",
|
|
29705
|
-
type: "fill",
|
|
29706
|
-
source: src,
|
|
29707
|
-
"source-layer": "inland_water",
|
|
29708
|
-
filter: NE_TIER,
|
|
29709
|
-
maxzoom: HANDOVER,
|
|
29710
|
-
paint: { "fill-color": T.inlandWater }
|
|
29711
|
-
}),
|
|
29712
|
-
L({
|
|
29713
|
-
id: "chrtbase-inland-hatch",
|
|
29714
|
-
type: "fill",
|
|
29715
|
-
source: src,
|
|
29716
|
-
"source-layer": "inland_water",
|
|
29717
|
-
filter: NE_TIER,
|
|
29718
|
-
maxzoom: HANDOVER,
|
|
29719
|
-
paint: { "fill-pattern": UNCHARTED_PATTERN, "fill-opacity": 0.7 }
|
|
29720
|
-
}),
|
|
29721
|
-
L({
|
|
29722
|
-
id: "chrtbase-inland-water-detail",
|
|
29723
|
-
type: "fill",
|
|
29724
|
-
source: src,
|
|
29725
|
-
"source-layer": "inland_water",
|
|
29726
|
-
filter: PLANET_TIER,
|
|
29727
|
-
minzoom: HANDOVER,
|
|
29728
|
-
paint: { "fill-color": T.inlandWater }
|
|
29729
|
-
}),
|
|
29730
|
-
L({
|
|
29731
|
-
id: "chrtbase-inland-hatch-detail",
|
|
29732
|
-
type: "fill",
|
|
29733
|
-
source: src,
|
|
29734
|
-
"source-layer": "inland_water",
|
|
29735
|
-
filter: PLANET_TIER,
|
|
29736
|
-
minzoom: HANDOVER,
|
|
29737
|
-
paint: { "fill-pattern": UNCHARTED_PATTERN, "fill-opacity": 0.7 }
|
|
29738
|
-
}),
|
|
29739
|
-
// The rough shoreline (owner ask 2026-08-28). Drawn ABOVE the hatch so
|
|
29740
|
-
// the edge stays crisp through the texture, and BELOW the charted-water
|
|
29741
|
-
// repaint clones the generator splices in after it — so wherever the
|
|
29742
|
-
// chart repaints its own water, the rough NE10m line yields to the
|
|
29743
|
-
// chart's COALNE instead of double-striking it.
|
|
29744
|
-
//
|
|
29745
|
-
// NE-tier geometry ONLY (`kind` absent): the planet detail tier joins
|
|
29746
|
-
// the same source-layer from z9 as MANY polygons whose chunk-clip seams
|
|
29747
|
-
// rejoin invisibly as FILLS — but a line layer strokes every seam, and
|
|
29748
|
-
// Winnipesaukee rendered as a mesh of internal edges. Planet features
|
|
29749
|
-
// carry `kind` (the INLAND_KINDS filter's own field); NE's carry only
|
|
29750
|
-
// `name`, so the absence of `kind` IS the tier discriminator.
|
|
29751
|
-
L({
|
|
29752
|
-
id: "chrtbase-inland-shore",
|
|
29753
|
-
type: "line",
|
|
29754
|
-
source: src,
|
|
29755
|
-
"source-layer": "inland_water",
|
|
29756
|
-
filter: NE_TIER,
|
|
29757
|
-
// Hands the shoreline over to the planet tier at ITS floor. Both
|
|
29758
|
-
// tiers live in `inland_water` from z9 up (tile-join concatenates the
|
|
29759
|
-
// same layer name), and their FILLS merge invisibly — but two
|
|
29760
|
-
// outlines do not: NE 10m generalises Winnipesaukee's shape, so its
|
|
29761
|
-
// outline ran straight across the middle of the lake the planet had
|
|
29762
|
-
// drawn correctly around. The coarse line is right only while it is
|
|
29763
|
-
// the only shape we have.
|
|
29764
|
-
maxzoom: HANDOVER,
|
|
29765
|
-
paint: {
|
|
29766
|
-
"line-color": T.inlandShore,
|
|
29767
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 4, 0.5, 10, 1.1, 14, 1.6],
|
|
29768
|
-
"line-opacity": 0.9
|
|
29769
|
-
}
|
|
29770
|
-
}),
|
|
29771
|
-
// The PLANET tier's shoreline (owner ask 2026-08-31: "uncharted small
|
|
29772
|
-
// lakes render with no outline"). It reads its own `inland_shore` layer,
|
|
29773
|
-
// NOT `inland_water`, and that indirection is the whole fix: the mesh
|
|
29774
|
-
// that forced the `!has kind` fence above is a CLIP artefact — an MVT
|
|
29775
|
-
// feature arrives already cut to its own z10 tile, so stroking the
|
|
29776
|
-
// polygon strokes every tile boundary it crosses. The build now walks
|
|
29777
|
-
// those rings, drops the axis-aligned runs that sit on the read zoom's
|
|
29778
|
-
// tile grid, and emits what is left as lines (measured on one New
|
|
29779
|
-
// England chunk: 61 long axis-aligned mesh edges → 5, and the 5 survivors
|
|
29780
|
-
// are 0.02–0.5 tiles off the grid, i.e. real straight water edges).
|
|
29781
|
-
//
|
|
29782
|
-
// Thinner and quieter than the NE line: this is finer geometry describing
|
|
29783
|
-
// water nobody has surveyed, and approximate data should look
|
|
29784
|
-
// approximate.
|
|
29785
|
-
L({
|
|
29786
|
-
id: "chrtbase-inland-shore-detail",
|
|
29787
|
-
type: "line",
|
|
29788
|
-
source: src,
|
|
29789
|
-
"source-layer": "inland_shore",
|
|
29790
|
-
minzoom: HANDOVER,
|
|
29791
|
-
paint: {
|
|
29792
|
-
"line-color": T.inlandShore,
|
|
29793
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 9, 0.5, 12, 0.9, 15, 1.2],
|
|
29794
|
-
"line-opacity": 0.85
|
|
29795
|
-
}
|
|
29796
|
-
}),
|
|
29797
|
-
// The lake's name (owner ask 2026-08-28) — the second scoped exception
|
|
29798
|
-
// to no-names-on-the-basemap, after the states: WATER-BODY names only.
|
|
29799
|
-
// No maxzoom: an uncharted lake keeps its name at every zoom; over
|
|
29800
|
-
// charted lakes the chart's own SEAARE label takes over at detail zooms
|
|
29801
|
-
// and collision culls the echo.
|
|
29802
|
-
//
|
|
29803
|
-
// The archive's `inland_water_label` anchors (v3+). v3 shipped ONE
|
|
29804
|
-
// PointOnSurface anchor per lake, and a big lake's single anchor pans
|
|
29805
|
-
// off-viewport — Winnipesaukee at z11.7 read nameless with its name two
|
|
29806
|
-
// tiles west of the screen (owner-reported). Labelling the polygons
|
|
29807
|
-
// instead is NOT the fix: tippecanoe's coalescing drops the NE polygon
|
|
29808
|
-
// from some z11 tiles (measured: 11/619/747 carries only planet pieces),
|
|
29809
|
-
// so a polygon-sourced label vanishes tile by tile. v4 therefore bakes a
|
|
29810
|
-
// deterministic anchor GRID into big lakes — the paper-chart convention
|
|
29811
|
-
// of repeating a name along a large water body — and this one layer
|
|
29812
|
-
// renders however many anchors are in view; collision culls the rest.
|
|
29813
|
-
// Planet-tier water-body NAMES (owner ask 2026-08-31: NE 10m names only
|
|
29814
|
-
// 113 US lakes). Emitted BELOW the NE layer on purpose — MapLibre places
|
|
29815
|
-
// symbols topmost-layer-first, so the big NE lake wins collision against
|
|
29816
|
-
// the pond beside it, and both lose to the chart's own labels (every ENC
|
|
29817
|
-
// class is emitted after this pair).
|
|
29818
|
-
//
|
|
29819
|
-
// The size threshold is OSM's own `min_zoom`, carried through the build:
|
|
29820
|
-
// Lake Winnipesaukee reads 10, Squam Lake 12, so a pond simply is not in
|
|
29821
|
-
// the filter until the user is close enough for it to be the answer to
|
|
29822
|
-
// "what is that water". `["zoom"]` in a filter evaluates at integer zoom
|
|
29823
|
-
// levels and removes the feature from placement entirely — verified
|
|
29824
|
-
// against maplibre-gl-native rather than assumed, because a text-size-0
|
|
29825
|
-
// gate would still claim a collision slot.
|
|
29826
|
-
//
|
|
29827
|
-
// The tiers are separate LAYERS, not a filtered split of one — see the
|
|
29828
|
-
// builder for why: an archive that a not-yet-deployed style would
|
|
29829
|
-
// mis-render cannot be promoted first, and this one has to be.
|
|
29830
|
-
L({
|
|
29831
|
-
id: "chrtbase-inland-label-detail",
|
|
29832
|
-
type: "symbol",
|
|
29833
|
-
source: src,
|
|
29834
|
-
"source-layer": "inland_water_label_detail",
|
|
29835
|
-
minzoom: HANDOVER,
|
|
29836
|
-
filter: [">=", ["zoom"], ["get", "min_zoom"]],
|
|
29837
|
-
layout: {
|
|
29838
|
-
"text-field": ["get", "name"],
|
|
29839
|
-
"text-font": ["Open Sans Regular"],
|
|
29840
|
-
"text-size": ["interpolate", ["linear"], ["zoom"], 9, 9, 12, 10.5, 15, 11],
|
|
29841
|
-
"text-max-width": 8,
|
|
29842
|
-
"text-allow-overlap": false,
|
|
29843
|
-
"text-padding": 6,
|
|
29844
|
-
// Bigger water first within the tier — min_zoom IS the size rank.
|
|
29845
|
-
"symbol-sort-key": ["get", "min_zoom"]
|
|
29846
|
-
},
|
|
30171
|
+
{
|
|
30172
|
+
...common,
|
|
30173
|
+
id: LAMP_GLOW_LAYER_ID,
|
|
29847
30174
|
paint: {
|
|
29848
|
-
"
|
|
29849
|
-
|
|
29850
|
-
|
|
29851
|
-
"
|
|
29852
|
-
|
|
29853
|
-
|
|
29854
|
-
|
|
29855
|
-
|
|
29856
|
-
|
|
29857
|
-
|
|
29858
|
-
"source-layer": "inland_water_label",
|
|
29859
|
-
minzoom: 5,
|
|
29860
|
-
layout: {
|
|
29861
|
-
"text-field": ["get", "name"],
|
|
29862
|
-
"text-font": ["Open Sans Regular"],
|
|
29863
|
-
"text-size": ["interpolate", ["linear"], ["zoom"], 5, 9.5, 10, 12],
|
|
29864
|
-
"text-max-width": 7,
|
|
29865
|
-
"text-allow-overlap": false,
|
|
29866
|
-
// Zoom-scaled spacing for the anchor GRID: at z8.9 the 0.08-deg
|
|
29867
|
-
// anchors sit ~54 px apart and a flat padding let six copies of
|
|
29868
|
-
// "Lake Ontario" crowd one screen (owner-reported 2026-08-30).
|
|
29869
|
-
// Wide collision boxes at low zoom thin the grid to the repeat-
|
|
29870
|
-
// by-convention cadence; by z12 the anchors are ~850 px apart and
|
|
29871
|
-
// the padding relaxes to normal.
|
|
29872
|
-
"text-padding": ["interpolate", ["linear"], ["zoom"], 5, 80, 9, 64, 12, 16]
|
|
30175
|
+
"circle-color": colour,
|
|
30176
|
+
// 4 nm → 7 px, 12 nm → 12 px, 25 nm → 20 px; capped, because a
|
|
30177
|
+
// primary seacoast light is not a searchlight.
|
|
30178
|
+
"circle-radius": ["interpolate", ["linear"], RANGE_NM, 0, 5, 4, 7, 12, 12, 25, 20],
|
|
30179
|
+
"circle-blur": 1,
|
|
30180
|
+
"circle-opacity": 0.55,
|
|
30181
|
+
// A lamp is a point of light: it does not grow as it comes near, and
|
|
30182
|
+
// it does not lie down with the chart.
|
|
30183
|
+
"circle-pitch-alignment": "viewport",
|
|
30184
|
+
"circle-pitch-scale": "viewport"
|
|
29873
30185
|
},
|
|
30186
|
+
metadata: { ...metadata, "chrt:lamp": "glow" }
|
|
30187
|
+
},
|
|
30188
|
+
{
|
|
30189
|
+
...common,
|
|
30190
|
+
id: LAMP_CORE_LAYER_ID,
|
|
29874
30191
|
paint: {
|
|
29875
|
-
"
|
|
29876
|
-
"
|
|
29877
|
-
"
|
|
29878
|
-
|
|
29879
|
-
|
|
30192
|
+
"circle-color": colour,
|
|
30193
|
+
"circle-radius": ["interpolate", ["linear"], RANGE_NM, 0, 1.5, 12, 2.5, 25, 3.5],
|
|
30194
|
+
"circle-blur": 0.25,
|
|
30195
|
+
"circle-opacity": 1,
|
|
30196
|
+
"circle-pitch-alignment": "viewport",
|
|
30197
|
+
"circle-pitch-scale": "viewport"
|
|
30198
|
+
},
|
|
30199
|
+
metadata: { ...metadata, "chrt:lamp": "core" }
|
|
30200
|
+
}
|
|
30201
|
+
];
|
|
30202
|
+
}
|
|
30203
|
+
|
|
30204
|
+
// src/atlas/band-priority.ts
|
|
30205
|
+
var BAND_PRIORITY_RANGES = {
|
|
30206
|
+
"1": { minzoom: 0 },
|
|
30207
|
+
"2": { minzoom: 5 },
|
|
30208
|
+
"3": { minzoom: 7 },
|
|
30209
|
+
"4": { minzoom: 9 },
|
|
30210
|
+
"5": { minzoom: 11 },
|
|
30211
|
+
"6": { minzoom: 11 }
|
|
30212
|
+
};
|
|
30213
|
+
var BAND_DATA_MINZOOM = {
|
|
30214
|
+
"1": 0,
|
|
30215
|
+
"2": 5,
|
|
30216
|
+
"3": 7,
|
|
30217
|
+
"4": 9,
|
|
30218
|
+
"5": 11,
|
|
30219
|
+
"6": 13
|
|
30220
|
+
};
|
|
30221
|
+
function dominatedVariantMaxzoom(D) {
|
|
30222
|
+
return Math.max(BAND_PRIORITY_RANGES[D].minzoom, BAND_DATA_MINZOOM[D]);
|
|
30223
|
+
}
|
|
30224
|
+
var DOMINANCE_EXEMPT_FILL_CLASSES = /* @__PURE__ */ new Set([
|
|
30225
|
+
"LNDARE",
|
|
30226
|
+
"DEPARE",
|
|
30227
|
+
"UNSARE",
|
|
30228
|
+
"LAKARE",
|
|
30229
|
+
"DRGARE",
|
|
30230
|
+
"SEAARE"
|
|
30231
|
+
]);
|
|
30232
|
+
function isExemptOpaqueFill(layer) {
|
|
30233
|
+
if (layer.type !== "fill") return false;
|
|
30234
|
+
for (const cls of DOMINANCE_EXEMPT_FILL_CLASSES) {
|
|
30235
|
+
if (layer.id.startsWith(`s52-${cls}-`)) return true;
|
|
30236
|
+
}
|
|
30237
|
+
return false;
|
|
30238
|
+
}
|
|
30239
|
+
var GROUND_FILL_CLASSES = /* @__PURE__ */ new Set([
|
|
30240
|
+
...DOMINANCE_EXEMPT_FILL_CLASSES,
|
|
30241
|
+
"RIVERS"
|
|
30242
|
+
]);
|
|
30243
|
+
function isGroundFill(layer) {
|
|
30244
|
+
if (layer.type !== "fill") return false;
|
|
30245
|
+
for (const cls of GROUND_FILL_CLASSES) {
|
|
30246
|
+
if (layer.id.startsWith(`s52-${cls}-`)) return true;
|
|
30247
|
+
}
|
|
30248
|
+
return false;
|
|
30249
|
+
}
|
|
30250
|
+
var FILL_FLOOR_FREE_BANDS = /* @__PURE__ */ new Set([
|
|
30251
|
+
"1",
|
|
30252
|
+
"2",
|
|
30253
|
+
"3"
|
|
30254
|
+
]);
|
|
30255
|
+
function bandVariantMinzoom(layer, B) {
|
|
30256
|
+
const classMinzoom = layer.minzoom ?? 0;
|
|
30257
|
+
if (isGroundFill(layer) && FILL_FLOOR_FREE_BANDS.has(B)) {
|
|
30258
|
+
return 0;
|
|
30259
|
+
}
|
|
30260
|
+
if (isGroundFill(layer)) {
|
|
30261
|
+
return BAND_PRIORITY_RANGES[B].minzoom;
|
|
30262
|
+
}
|
|
30263
|
+
return Math.max(classMinzoom, BAND_PRIORITY_RANGES[B].minzoom);
|
|
30264
|
+
}
|
|
30265
|
+
var GENERALISED_AREA_FILL_CLASSES = /* @__PURE__ */ new Set([
|
|
30266
|
+
"BUAARE",
|
|
30267
|
+
// 2026-08-28, New York Harbor: the "New York Marine Inspection Zone and
|
|
30268
|
+
// Captain of the Port Zone" RESARE exists at bands 2/3 as a generalized
|
|
30269
|
+
// shore-hugging polygon whose point-sampled dominance tag MISSED (the
|
|
30270
|
+
// Providence-BUAARE failure mode), so its magenta dashed boundary drew
|
|
30271
|
+
// OFFSET over the band-5 detail at z11.5 — read in the field as "a
|
|
30272
|
+
// magenta shoreline bleeding down from a less coarse band". The same
|
|
30273
|
+
// tile carried untagged band-2 ADMARE and CTNARE giants in the same
|
|
30274
|
+
// state. All three are area classes whose coarse-band boundaries hug
|
|
30275
|
+
// shorelines and whose fine-band copies are authoritative.
|
|
30276
|
+
"RESARE",
|
|
30277
|
+
"CTNARE",
|
|
30278
|
+
"ADMARE"
|
|
30279
|
+
]);
|
|
30280
|
+
var GENERALISED_AREA_MAX_BAND = 3;
|
|
30281
|
+
function generalisedAreaCeiling(layer, B) {
|
|
30282
|
+
if (layer.type !== "fill" && layer.type !== "line") return null;
|
|
30283
|
+
if (parseInt(B, 10) > GENERALISED_AREA_MAX_BAND) return null;
|
|
30284
|
+
for (const cls of GENERALISED_AREA_FILL_CLASSES) {
|
|
30285
|
+
if (layer.id.startsWith(`s52-${cls}-`)) return BAND_PRIORITY_RANGES["5"].minzoom;
|
|
30286
|
+
}
|
|
30287
|
+
return null;
|
|
30288
|
+
}
|
|
30289
|
+
var BAND_DRAW_ORDER = ["1", "2", "3", "4", "5", "6"];
|
|
30290
|
+
var CHART_BAND_CODES = {
|
|
30291
|
+
Overview: ["1"],
|
|
30292
|
+
General: ["2"],
|
|
30293
|
+
Coastal: ["3"],
|
|
30294
|
+
Approach: ["4"],
|
|
30295
|
+
Harbor: ["5", "6"]
|
|
30296
|
+
};
|
|
30297
|
+
var CHART_CASCADE_CODES = {
|
|
30298
|
+
Overview: ["1"],
|
|
30299
|
+
General: ["1", "2"],
|
|
30300
|
+
Coastal: ["1", "2", "3"],
|
|
30301
|
+
Approach: ["1", "2", "3", "4"],
|
|
30302
|
+
Harbor: ["1", "2", "3", "4", "5", "6"]
|
|
30303
|
+
};
|
|
30304
|
+
var CHRT_STYLE_MODES = [
|
|
30305
|
+
"continuous",
|
|
30306
|
+
...Object.keys(CHART_BAND_CODES).map(
|
|
30307
|
+
(band) => `chart:${band}`
|
|
30308
|
+
)
|
|
30309
|
+
];
|
|
30310
|
+
function normalizeStyleMode(raw) {
|
|
30311
|
+
if (raw === null || raw === void 0 || raw === "") return "continuous";
|
|
30312
|
+
const lower = raw.toLowerCase();
|
|
30313
|
+
return CHRT_STYLE_MODES.find((mode) => mode.toLowerCase() === lower) ?? null;
|
|
30314
|
+
}
|
|
30315
|
+
function styleModeBand(mode) {
|
|
30316
|
+
return mode === "continuous" ? null : mode.slice("chart:".length);
|
|
30317
|
+
}
|
|
30318
|
+
function bandFilterExpression(codes) {
|
|
30319
|
+
return cellBandMatch(["slice", ["get", "_cell_id"], 2, 3], codes);
|
|
30320
|
+
}
|
|
30321
|
+
var BAND_CODE_ALIASES = {
|
|
30322
|
+
"5": ["7"]
|
|
30323
|
+
};
|
|
30324
|
+
function cellBandCharacters(code) {
|
|
30325
|
+
return [code, ...BAND_CODE_ALIASES[code] ?? []];
|
|
30326
|
+
}
|
|
30327
|
+
function cellBandMatch(cellBandExpr, codes) {
|
|
30328
|
+
const list = Array.isArray(codes) ? codes : [codes];
|
|
30329
|
+
const chars = [...new Set(list.flatMap((c) => cellBandCharacters(c)))];
|
|
30330
|
+
if (chars.length === 1) {
|
|
30331
|
+
return ["==", cellBandExpr, chars[0]];
|
|
30332
|
+
}
|
|
30333
|
+
return ["in", cellBandExpr, ["literal", chars]];
|
|
30334
|
+
}
|
|
30335
|
+
function combineWithBandFilter(baseFilter, bandFilter) {
|
|
30336
|
+
if (!baseFilter) return bandFilter;
|
|
30337
|
+
if (baseFilter[0] === "all") {
|
|
30338
|
+
return ["all", ...baseFilter.slice(1), bandFilter];
|
|
30339
|
+
}
|
|
30340
|
+
return ["all", baseFilter, bandFilter];
|
|
30341
|
+
}
|
|
30342
|
+
var NOT_DOMINATED_FILTER = [
|
|
30343
|
+
"all",
|
|
30344
|
+
["!", ["has", "_dominated_by_min"]],
|
|
30345
|
+
["!=", ["get", "_dominated"], true]
|
|
30346
|
+
];
|
|
30347
|
+
function dominatedByMinFilter(D) {
|
|
30348
|
+
const dInt = parseInt(D, 10);
|
|
30349
|
+
if (D === "6") {
|
|
30350
|
+
return [
|
|
30351
|
+
"any",
|
|
30352
|
+
["==", ["get", "_dominated_by_min"], dInt],
|
|
30353
|
+
["==", ["get", "_dominated"], true]
|
|
30354
|
+
];
|
|
30355
|
+
}
|
|
30356
|
+
return ["==", ["get", "_dominated_by_min"], dInt];
|
|
30357
|
+
}
|
|
30358
|
+
function withinBboxFilter(bbox) {
|
|
30359
|
+
const [w, s] = bbox.sw;
|
|
30360
|
+
const [e, n] = bbox.ne;
|
|
30361
|
+
return [
|
|
30362
|
+
"within",
|
|
30363
|
+
{
|
|
30364
|
+
type: "Polygon",
|
|
30365
|
+
coordinates: [
|
|
30366
|
+
[
|
|
30367
|
+
[w, s],
|
|
30368
|
+
[e, s],
|
|
30369
|
+
[e, n],
|
|
30370
|
+
[w, n],
|
|
30371
|
+
[w, s]
|
|
30372
|
+
]
|
|
30373
|
+
]
|
|
30374
|
+
}
|
|
29880
30375
|
];
|
|
29881
30376
|
}
|
|
30377
|
+
function worldMinusBboxPolygon(bbox) {
|
|
30378
|
+
const [w, s] = bbox.sw;
|
|
30379
|
+
const [e, n] = bbox.ne;
|
|
30380
|
+
return {
|
|
30381
|
+
type: "Polygon",
|
|
30382
|
+
coordinates: [
|
|
30383
|
+
[
|
|
30384
|
+
[-180, -85],
|
|
30385
|
+
[180, -85],
|
|
30386
|
+
[180, 85],
|
|
30387
|
+
[-180, 85],
|
|
30388
|
+
[-180, -85]
|
|
30389
|
+
],
|
|
30390
|
+
// Inner ring (hole) — winding opposite to outer ring per GeoJSON
|
|
30391
|
+
// spec. MapLibre is permissive but we follow strict winding.
|
|
30392
|
+
[
|
|
30393
|
+
[w, s],
|
|
30394
|
+
[w, n],
|
|
30395
|
+
[e, n],
|
|
30396
|
+
[e, s],
|
|
30397
|
+
[w, s]
|
|
30398
|
+
]
|
|
30399
|
+
]
|
|
30400
|
+
};
|
|
30401
|
+
}
|
|
29882
30402
|
|
|
29883
30403
|
// src/atlas/tile-number.ts
|
|
29884
30404
|
function tileNumber(property, fallback) {
|
|
@@ -29949,6 +30469,57 @@ var LAND_THEMES = {
|
|
|
29949
30469
|
// skipper is navigating by. Left at the shipped value rather than
|
|
29950
30470
|
// lowered, because lowering it is a separate decision from this one.
|
|
29951
30471
|
exaggeration: 0.45
|
|
30472
|
+
},
|
|
30473
|
+
// ── E-ink: paper land, no relief ──────────────────────────────────────
|
|
30474
|
+
// Hillshade is a continuous grey ramp — exactly what an e-ink panel cannot
|
|
30475
|
+
// show (and a moving one costs a refresh), so both e-ink palettes switch it
|
|
30476
|
+
// off (`exaggeration: 0`). Land is the chart's own LANDA in that table, so
|
|
30477
|
+
// charted and CHRTland land are one tone; labels are black on paper.
|
|
30478
|
+
EINK_COLOR: {
|
|
30479
|
+
base: "#f2e2b0",
|
|
30480
|
+
cover: { wood: "#d6e0b0", wetland: "#d0dccc", urban: "#e0dacb", sand: "#f2e2b0" },
|
|
30481
|
+
contour: "#a08a5a",
|
|
30482
|
+
contourIndex: "#6b5a3e",
|
|
30483
|
+
road: "#d8c08a",
|
|
30484
|
+
roadMajor: "#c49a4a",
|
|
30485
|
+
label: "#000000",
|
|
30486
|
+
halo: "#ffffff",
|
|
30487
|
+
shadow: "#6b5a3e",
|
|
30488
|
+
highlight: "#ffffff",
|
|
30489
|
+
fade: "#ffffff",
|
|
30490
|
+
exaggeration: 0
|
|
30491
|
+
},
|
|
30492
|
+
// Mono: one land tone (MID). Land cover is not drawn as tone — four greys
|
|
30493
|
+
// cannot spare one for "wood" — so every cover class is the land tone.
|
|
30494
|
+
EINK_MONO: {
|
|
30495
|
+
base: "#aaaaaa",
|
|
30496
|
+
cover: { wood: "#aaaaaa", wetland: "#aaaaaa", urban: "#aaaaaa", sand: "#aaaaaa" },
|
|
30497
|
+
contour: "#555555",
|
|
30498
|
+
contourIndex: "#555555",
|
|
30499
|
+
road: "#ffffff",
|
|
30500
|
+
roadMajor: "#ffffff",
|
|
30501
|
+
label: "#000000",
|
|
30502
|
+
halo: "#ffffff",
|
|
30503
|
+
shadow: "#555555",
|
|
30504
|
+
highlight: "#ffffff",
|
|
30505
|
+
fade: "#ffffff",
|
|
30506
|
+
exaggeration: 0
|
|
30507
|
+
},
|
|
30508
|
+
// Night: land is the DIM grey (the chart's EINK_NIGHT LANDA), drawn on in
|
|
30509
|
+
// black so the land adds no lit lines of its own; labels the night line grey.
|
|
30510
|
+
EINK_NIGHT: {
|
|
30511
|
+
base: "#555555",
|
|
30512
|
+
cover: { wood: "#555555", wetland: "#555555", urban: "#555555", sand: "#555555" },
|
|
30513
|
+
contour: "#000000",
|
|
30514
|
+
contourIndex: "#000000",
|
|
30515
|
+
road: "#000000",
|
|
30516
|
+
roadMajor: "#000000",
|
|
30517
|
+
label: "#aaaaaa",
|
|
30518
|
+
halo: "#000000",
|
|
30519
|
+
shadow: "#000000",
|
|
30520
|
+
highlight: "#555555",
|
|
30521
|
+
fade: "#000000",
|
|
30522
|
+
exaggeration: 0
|
|
29952
30523
|
}
|
|
29953
30524
|
};
|
|
29954
30525
|
var FITS = ["<=", tileNumber("min_z", 0), ["zoom"]];
|
|
@@ -30331,7 +30902,10 @@ var META_LAYERS = /* @__PURE__ */ new Set([
|
|
|
30331
30902
|
var PALETTE_NAMES = {
|
|
30332
30903
|
DAY: "DAY_BRIGHT",
|
|
30333
30904
|
DUSK: "DUSK",
|
|
30334
|
-
NIGHT: "NIGHT"
|
|
30905
|
+
NIGHT: "NIGHT",
|
|
30906
|
+
EINK_COLOR: "EINK_COLOR",
|
|
30907
|
+
EINK_MONO: "EINK_MONO",
|
|
30908
|
+
EINK_NIGHT: "EINK_NIGHT"
|
|
30335
30909
|
};
|
|
30336
30910
|
var SYMBOL_SET_LABELS = {
|
|
30337
30911
|
s52: "S-52",
|
|
@@ -30443,7 +31017,7 @@ var ORIENTATION_OPACITY_SCALE = {
|
|
|
30443
31017
|
};
|
|
30444
31018
|
var ORIENTATION_OPACITY_MAX = 0.92;
|
|
30445
31019
|
var ORIENTATION_BOOST_MINZOOM = 11;
|
|
30446
|
-
function fanOrientationLabelByCellBand(label, bandFan,
|
|
31020
|
+
function fanOrientationLabelByCellBand(label, bandFan, objectClass2) {
|
|
30447
31021
|
const cellBandExpr = [
|
|
30448
31022
|
"slice",
|
|
30449
31023
|
["coalesce", ["get", "_cell_id"], "??9???"],
|
|
@@ -30451,7 +31025,7 @@ function fanOrientationLabelByCellBand(label, bandFan, objectClass) {
|
|
|
30451
31025
|
3
|
|
30452
31026
|
];
|
|
30453
31027
|
const variants = [];
|
|
30454
|
-
const scale =
|
|
31028
|
+
const scale = objectClass2 ? ORIENTATION_OPACITY_SCALE[objectClass2] ?? 1 : 1;
|
|
30455
31029
|
for (const code of BAND_DRAW_ORDER) {
|
|
30456
31030
|
const range = BAND_PRIORITY_RANGES[code];
|
|
30457
31031
|
const curve = CELL_BAND_OPACITY_CURVE[code];
|
|
@@ -30650,14 +31224,14 @@ function generateStyle(palette = "DAY", opts = {}) {
|
|
|
30650
31224
|
const bandFan = opts.bandFan ?? "collapsed";
|
|
30651
31225
|
const lockedBounds = opts.chartMode?.lockedBounds;
|
|
30652
31226
|
const bundles = [];
|
|
30653
|
-
for (const
|
|
30654
|
-
if (META_LAYERS.has(
|
|
31227
|
+
for (const objectClass2 of orderedClasses) {
|
|
31228
|
+
if (META_LAYERS.has(objectClass2)) continue;
|
|
30655
31229
|
bundles.push({
|
|
30656
|
-
objectClass,
|
|
30657
|
-
featureLayers: buildLayersForClass(
|
|
31230
|
+
objectClass: objectClass2,
|
|
31231
|
+
featureLayers: buildLayersForClass(objectClass2, palette, sourceId, {
|
|
30658
31232
|
safetyContour: opts.safetyContour
|
|
30659
31233
|
}),
|
|
30660
|
-
label: buildLabelLayer2(
|
|
31234
|
+
label: buildLabelLayer2(objectClass2, palette, sourceId, opts.depthUnits ?? "meters", {
|
|
30661
31235
|
safetyContour: opts.safetyContour,
|
|
30662
31236
|
twoShadeSoundings: opts.twoShadeSoundings,
|
|
30663
31237
|
soundingFontWeight: opts.soundingFontWeight,
|
|
@@ -30802,17 +31376,17 @@ function generateStyle(palette = "DAY", opts = {}) {
|
|
|
30802
31376
|
if (opts.labels === "placename") {
|
|
30803
31377
|
labelLayers.push(...buildPlaceNameLayers(sourceId, palette));
|
|
30804
31378
|
} else {
|
|
30805
|
-
for (const { objectClass, label } of bundles) {
|
|
31379
|
+
for (const { objectClass: objectClass2, label } of bundles) {
|
|
30806
31380
|
if (!label) continue;
|
|
30807
|
-
if (getLabelBehavior(
|
|
30808
|
-
if (
|
|
31381
|
+
if (getLabelBehavior(objectClass2) === "orientation-cross-band") {
|
|
31382
|
+
if (objectClass2 === "LNDARE" || objectClass2 === "SEAARE") {
|
|
30809
31383
|
const Z = ISLAND_LABEL_HOIST_MINZOOM;
|
|
30810
|
-
const { hoist, watermark } =
|
|
30811
|
-
fanOrientationLabelByCellBand(label, bandFan,
|
|
31384
|
+
const { hoist, watermark } = objectClass2 === "LNDARE" ? splitOrientationFan(
|
|
31385
|
+
fanOrientationLabelByCellBand(label, bandFan, objectClass2),
|
|
30812
31386
|
[">=", ["zoom"], Z],
|
|
30813
31387
|
["<", ["zoom"], Z]
|
|
30814
31388
|
) : splitOrientationFan(
|
|
30815
|
-
fanOrientationLabelByCellBand(label, bandFan,
|
|
31389
|
+
fanOrientationLabelByCellBand(label, bandFan, objectClass2),
|
|
30816
31390
|
["<=", buildSeaAreaTierExpression(), MAJOR_WATER_TIER_MAX],
|
|
30817
31391
|
[">", buildSeaAreaTierExpression(), MAJOR_WATER_TIER_MAX],
|
|
30818
31392
|
{ "text-padding": MAJOR_WATER_TEXT_PADDING }
|
|
@@ -30821,7 +31395,7 @@ function generateStyle(palette = "DAY", opts = {}) {
|
|
|
30821
31395
|
labelLayers.push(...watermark);
|
|
30822
31396
|
continue;
|
|
30823
31397
|
}
|
|
30824
|
-
labelLayers.push(...fanOrientationLabelByCellBand(label, bandFan,
|
|
31398
|
+
labelLayers.push(...fanOrientationLabelByCellBand(label, bandFan, objectClass2));
|
|
30825
31399
|
}
|
|
30826
31400
|
}
|
|
30827
31401
|
}
|
|
@@ -31085,10 +31659,8 @@ function generateStyle(palette = "DAY", opts = {}) {
|
|
|
31085
31659
|
glyphs: `${glyphsBase}/{fontstack}/{range}.pbf`,
|
|
31086
31660
|
layers: finalLayers
|
|
31087
31661
|
};
|
|
31088
|
-
|
|
31089
|
-
|
|
31090
|
-
if (symbolSet === "raster") return applyRasterSymbolSet(style);
|
|
31091
|
-
return style;
|
|
31662
|
+
const familyStyle = symbolSet === "s101" ? applyS101SymbolSet(style) : symbolSet === "chrt" ? applyChrtSymbolSet(style, palette) : symbolSet === "raster" ? applyRasterSymbolSet(style) : style;
|
|
31663
|
+
return applyEinkPortrayal(familyStyle, palette, { safetyContour: opts.safetyContour });
|
|
31092
31664
|
}
|
|
31093
31665
|
function generateStyleJSON(palette = "DAY", opts = {}) {
|
|
31094
31666
|
return JSON.stringify(generateStyle(palette, opts), null, 2);
|
|
@@ -31232,7 +31804,7 @@ var DEFAULT_CUSTOM_STYLE_CONFIG = {
|
|
|
31232
31804
|
water_body_settings: DEFAULT_WATER_BODY_SETTINGS,
|
|
31233
31805
|
visible_layers: null
|
|
31234
31806
|
};
|
|
31235
|
-
var COLOR_TABLE_NAMES = /* @__PURE__ */ new Set(["DAY", "DUSK", "NIGHT"]);
|
|
31807
|
+
var COLOR_TABLE_NAMES = /* @__PURE__ */ new Set(["DAY", "DUSK", "NIGHT", "EINK_COLOR", "EINK_MONO", "EINK_NIGHT"]);
|
|
31236
31808
|
var DISPLAY_MODES = /* @__PURE__ */ new Set(["BASE", "STANDARD", "ALL"]);
|
|
31237
31809
|
var LAYER_NAME_RE = /^[A-Za-z0-9_$]{2,16}$/;
|
|
31238
31810
|
var MAX_VISIBLE_LAYERS = 512;
|
|
@@ -31339,12 +31911,12 @@ function sanitizeCustomStyleConfig(raw) {
|
|
|
31339
31911
|
}
|
|
31340
31912
|
function normalizeTheme(raw) {
|
|
31341
31913
|
if (!raw) return null;
|
|
31342
|
-
const upper = raw.trim().toUpperCase();
|
|
31914
|
+
const upper = raw.trim().toUpperCase().replace(/-/g, "_");
|
|
31343
31915
|
return COLOR_TABLE_NAMES.has(upper) ? upper : null;
|
|
31344
31916
|
}
|
|
31345
31917
|
function resolveCustomTheme(config, requested) {
|
|
31346
31918
|
if (!requested) return { palette: config.default_color_table, themeFellBack: false };
|
|
31347
|
-
if (config.enabled_color_tables.includes(requested)) {
|
|
31919
|
+
if (isEinkColorTable(requested) || config.enabled_color_tables.includes(requested)) {
|
|
31348
31920
|
return { palette: requested, themeFellBack: false };
|
|
31349
31921
|
}
|
|
31350
31922
|
return { palette: config.default_color_table, themeFellBack: true };
|
|
@@ -32022,6 +32594,11 @@ export {
|
|
|
32022
32594
|
DEPTH_LABEL_CLASSES,
|
|
32023
32595
|
DEPTH_LABEL_SIZES,
|
|
32024
32596
|
DRAPEABLE_LAYER_TYPES,
|
|
32597
|
+
EINK_COLOR_TABLES,
|
|
32598
|
+
EINK_DANGER_PATTERN,
|
|
32599
|
+
EINK_DOTS_PATTERN,
|
|
32600
|
+
EINK_HATCH_PATTERN,
|
|
32601
|
+
EINK_MONO_GREYS,
|
|
32025
32602
|
INSPECT_CLASS_RANK,
|
|
32026
32603
|
INSPECT_RANK_DEVIATIONS,
|
|
32027
32604
|
InteractClient,
|
|
@@ -32074,6 +32651,9 @@ export {
|
|
|
32074
32651
|
S52_DAY,
|
|
32075
32652
|
S52_DRAW_ORDER,
|
|
32076
32653
|
S52_DUSK,
|
|
32654
|
+
S52_EINK_COLOR,
|
|
32655
|
+
S52_EINK_MONO,
|
|
32656
|
+
S52_EINK_NIGHT,
|
|
32077
32657
|
S52_LOOKUP,
|
|
32078
32658
|
S52_NIGHT,
|
|
32079
32659
|
S52_PATTERN_SPRITE_PREFIX,
|
|
@@ -32093,6 +32673,7 @@ export {
|
|
|
32093
32673
|
applyColorTheme,
|
|
32094
32674
|
applyCustomStyleSettings,
|
|
32095
32675
|
applyDepthLabelSize,
|
|
32676
|
+
applyEinkPortrayal,
|
|
32096
32677
|
applyRasterSymbolSet,
|
|
32097
32678
|
applyS101SymbolSet,
|
|
32098
32679
|
atonIconExpression,
|
|
@@ -32172,6 +32753,8 @@ export {
|
|
|
32172
32753
|
iconExpressionForFamily,
|
|
32173
32754
|
isDepthAreaClassLayerId,
|
|
32174
32755
|
isDrapeable,
|
|
32756
|
+
isEinkColorTable,
|
|
32757
|
+
isEinkGreyTable,
|
|
32175
32758
|
isLabelLayerVisible,
|
|
32176
32759
|
isMapLive,
|
|
32177
32760
|
isNavAidLayer,
|
|
@@ -32211,6 +32794,7 @@ export {
|
|
|
32211
32794
|
resolveTargetClass,
|
|
32212
32795
|
rhythmProperties,
|
|
32213
32796
|
s101ArtworkProvenance,
|
|
32797
|
+
safetyContourValues,
|
|
32214
32798
|
sanitizeCustomStyleConfig,
|
|
32215
32799
|
scaleLinearLight,
|
|
32216
32800
|
scaleSizeValue,
|