@chrtco/sdk 0.10.32 → 0.10.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +236 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +236 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24574,6 +24574,197 @@ function buildPlaceNameLayers(sourceId) {
|
|
|
24574
24574
|
make("land", PLACENAME_LAND_CLASSES, ["Open Sans Regular"], COLOR.LAND_REGION, 0.02, PLACENAME_LAND_SIZE_STOPS)
|
|
24575
24575
|
];
|
|
24576
24576
|
}
|
|
24577
|
+
var DRGNOTE_SOURCE_LAYER = "DRGNOTE";
|
|
24578
|
+
var DRGNOTE_LABEL_PRIORITY = 300;
|
|
24579
|
+
var DRGNOTE_MINZOOM = 13;
|
|
24580
|
+
var DRGNOTE_FULL_ZOOM = 16;
|
|
24581
|
+
var DRGNOTE_MIN_TEXT_PX = 1;
|
|
24582
|
+
var DRGNOTE_MAX_TEXT_PX = 64;
|
|
24583
|
+
function legacyNoteSizePx(zoom) {
|
|
24584
|
+
const z = Math.min(16, Math.max(13, zoom));
|
|
24585
|
+
return 10.5 + (13 - 10.5) * (z - 13) / 3;
|
|
24586
|
+
}
|
|
24587
|
+
var DRGNOTE_FIT_ZOOM = 15;
|
|
24588
|
+
function dredgeNoteSize() {
|
|
24589
|
+
const stops = [];
|
|
24590
|
+
for (let z = 12; z <= 20; z++) {
|
|
24591
|
+
const prop = z < DRGNOTE_FULL_ZOOM ? "size_s" : "size_f";
|
|
24592
|
+
const fitted = ["to-number", ["get", prop], 0];
|
|
24593
|
+
stops.push(z, [
|
|
24594
|
+
"case",
|
|
24595
|
+
[">", fitted, 0],
|
|
24596
|
+
[
|
|
24597
|
+
"min",
|
|
24598
|
+
DRGNOTE_MAX_TEXT_PX,
|
|
24599
|
+
["max", DRGNOTE_MIN_TEXT_PX, ["*", fitted, 2 ** (z - DRGNOTE_FIT_ZOOM)]]
|
|
24600
|
+
],
|
|
24601
|
+
legacyNoteSizePx(z)
|
|
24602
|
+
]);
|
|
24603
|
+
}
|
|
24604
|
+
return ["interpolate", ["exponential", 2], ["zoom"], ...stops];
|
|
24605
|
+
}
|
|
24606
|
+
function noteDepthText(prop, depthUnits) {
|
|
24607
|
+
return depthUnits === "feet" ? ["concat", ["to-string", ["round", ["*", ["to-number", ["get", prop]], 3.28084]]], " FT"] : ["concat", ["to-string", ["get", prop]], " M"];
|
|
24608
|
+
}
|
|
24609
|
+
function buildDredgeNoteLayers(sourceId, palette = "DAY", depthUnits = "meters") {
|
|
24610
|
+
const widthProp = depthUnits === "feet" ? "width_ft" : "width_m";
|
|
24611
|
+
const widthUnit = depthUnits === "feet" ? " FT" : " M";
|
|
24612
|
+
const titleText = [
|
|
24613
|
+
"to-string",
|
|
24614
|
+
["coalesce", ["get", "designation"], ["get", "name"], ""]
|
|
24615
|
+
];
|
|
24616
|
+
const placeText = ["to-string", ["coalesce", ["get", "place"], ""]];
|
|
24617
|
+
const sep = (prop) => [
|
|
24618
|
+
"to-string",
|
|
24619
|
+
["coalesce", ["get", prop], "\n"]
|
|
24620
|
+
];
|
|
24621
|
+
const legendText = [
|
|
24622
|
+
"concat",
|
|
24623
|
+
noteDepthText("depth_m", depthUnits),
|
|
24624
|
+
[
|
|
24625
|
+
"case",
|
|
24626
|
+
[">", ["to-number", ["get", "qual_m"], -1], 0],
|
|
24627
|
+
[
|
|
24628
|
+
"concat",
|
|
24629
|
+
" ",
|
|
24630
|
+
noteDepthText("qual_m", depthUnits),
|
|
24631
|
+
" ",
|
|
24632
|
+
["to-string", ["get", "qual_part"]]
|
|
24633
|
+
],
|
|
24634
|
+
""
|
|
24635
|
+
],
|
|
24636
|
+
[
|
|
24637
|
+
"case",
|
|
24638
|
+
[">", ["to-number", ["get", widthProp], -1], 0],
|
|
24639
|
+
["concat", " FOR A WIDTH OF ", ["to-string", ["get", widthProp]], widthUnit],
|
|
24640
|
+
""
|
|
24641
|
+
],
|
|
24642
|
+
[
|
|
24643
|
+
"case",
|
|
24644
|
+
["!=", ["to-string", ["get", "date"]], ""],
|
|
24645
|
+
["concat", " ", ["to-string", ["get", "date"]]],
|
|
24646
|
+
""
|
|
24647
|
+
],
|
|
24648
|
+
["case", ["==", ["get", "unmaintained"], true], " NOT MAINTAINED", ""]
|
|
24649
|
+
];
|
|
24650
|
+
const shortField = [
|
|
24651
|
+
"case",
|
|
24652
|
+
["!=", titleText, ""],
|
|
24653
|
+
["concat", titleText, sep("sep_s"), legendText],
|
|
24654
|
+
legendText
|
|
24655
|
+
];
|
|
24656
|
+
const fullField = [
|
|
24657
|
+
"case",
|
|
24658
|
+
["!=", placeText, ""],
|
|
24659
|
+
["concat", placeText, sep("sep_fp"), titleText, sep("sep_ft"), legendText],
|
|
24660
|
+
["case", ["!=", titleText, ""], ["concat", titleText, sep("sep_ft"), legendText], legendText]
|
|
24661
|
+
];
|
|
24662
|
+
const noteField = [
|
|
24663
|
+
"step",
|
|
24664
|
+
["zoom"],
|
|
24665
|
+
shortField,
|
|
24666
|
+
DRGNOTE_FULL_ZOOM,
|
|
24667
|
+
fullField
|
|
24668
|
+
];
|
|
24669
|
+
const sortKey = [
|
|
24670
|
+
"case",
|
|
24671
|
+
[">=", ["to-number", ["get", "rank"], -1], 0],
|
|
24672
|
+
["to-number", ["get", "rank"]],
|
|
24673
|
+
["*", 1e3, ["to-number", ["get", "depth_m"], 99]]
|
|
24674
|
+
];
|
|
24675
|
+
return [
|
|
24676
|
+
{
|
|
24677
|
+
// The `-label` suffix is how this repo marks a label layer, and
|
|
24678
|
+
// z-order guards partition on it (sector-light-zorder.test.ts).
|
|
24679
|
+
id: "chrt-dredge-note-label",
|
|
24680
|
+
type: "symbol",
|
|
24681
|
+
source: sourceId,
|
|
24682
|
+
"source-layer": DRGNOTE_SOURCE_LAYER,
|
|
24683
|
+
minzoom: DRGNOTE_MINZOOM,
|
|
24684
|
+
layout: {
|
|
24685
|
+
"text-field": noteField,
|
|
24686
|
+
"text-font": ["Open Sans Regular"],
|
|
24687
|
+
// Ink on the chart, not type on the screen.
|
|
24688
|
+
//
|
|
24689
|
+
// The size is fitted to THIS polygon at build time (px at z15) and
|
|
24690
|
+
// doubled per zoom here, so the note holds a fixed GEOGRAPHIC size
|
|
24691
|
+
// the way a raster chart's note is fixed to its paper. Set at one
|
|
24692
|
+
// screen size instead, a note fits its channel at one zoom and
|
|
24693
|
+
// spills at every other — measured at Gloucester z15, only 37% of
|
|
24694
|
+
// North Channel's note lay inside North Channel.
|
|
24695
|
+
//
|
|
24696
|
+
// `interpolate` with base 2 and stops ONE zoom apart is exactly
|
|
24697
|
+
// geometric: t = (2^(z-z1)-1)/(2^1-1) and v2 = 2*v1 collapse to
|
|
24698
|
+
// v1*2^(z-z1). Writing it the obvious way instead —
|
|
24699
|
+
// ["*", size, ["^", 2, ["-", ["zoom"], 15]]] — is INVALID, because
|
|
24700
|
+
// ["zoom"] may only be the direct input of an outer interpolate or
|
|
24701
|
+
// step. MapLibre rejects it silently, keeps the previous value and
|
|
24702
|
+
// renders on as if nothing happened.
|
|
24703
|
+
//
|
|
24704
|
+
// It is NOT clamped to a legible band. That was tried and it
|
|
24705
|
+
// defeated the point: measured across z13-z18 a clamp bound at
|
|
24706
|
+
// five of six zooms for every Gloucester note, pinning the note to
|
|
24707
|
+
// a fixed screen size while its channel grew. A note that keeps
|
|
24708
|
+
// its proportion is illegibly small when its channel is small,
|
|
24709
|
+
// and that is correct — it is how the eye tells which channel a
|
|
24710
|
+
// note belongs to, and how a raster chart behaves. Zoom in and it
|
|
24711
|
+
// grows with the water. A tile built before the fit carries no
|
|
24712
|
+
// size and keeps the fixed size it was designed for.
|
|
24713
|
+
"text-size": dredgeNoteSize(),
|
|
24714
|
+
"text-transform": "uppercase",
|
|
24715
|
+
"text-letter-spacing": 0.08,
|
|
24716
|
+
// ONE line, and wide enough never to wrap into a second.
|
|
24717
|
+
//
|
|
24718
|
+
// Must equal noteFit.ts#LINE_HEIGHT_EM — the build side measures
|
|
24719
|
+
// the note's height with it before deciding how large it can set.
|
|
24720
|
+
"text-line-height": 1.2,
|
|
24721
|
+
// Wide enough that MapLibre NEVER wraps. Every break in this note
|
|
24722
|
+
// is an explicit "\n" the build side chose by fitting the result
|
|
24723
|
+
// against the polygon; an automatic wrap on top of that would
|
|
24724
|
+
// re-flow the label into lines nothing measured, and MapLibre's
|
|
24725
|
+
// line breaker balances lines rather than filling greedily, so the
|
|
24726
|
+
// build side cannot predict where it would land.
|
|
24727
|
+
"text-max-width": 512,
|
|
24728
|
+
"text-rotate": ["get", "rotate"],
|
|
24729
|
+
"text-rotation-alignment": "map",
|
|
24730
|
+
"text-padding": 3,
|
|
24731
|
+
"text-allow-overlap": false,
|
|
24732
|
+
"text-ignore-placement": false,
|
|
24733
|
+
"text-optional": true,
|
|
24734
|
+
// Placement rank from the build side (dredgeNote.ts#stationRank):
|
|
24735
|
+
// shoaler water always survives a collision, bigger channel first
|
|
24736
|
+
// among equal depths.
|
|
24737
|
+
//
|
|
24738
|
+
// Deliberately NOT labelSortKey. That helper clamps its second
|
|
24739
|
+
// argument to [0, 999] — fine for a VALDCO contour value, fatal
|
|
24740
|
+
// here: every rank in the millions collapsed to 999 and both notes
|
|
24741
|
+
// evaluated to the identical key 300999, making the whole ranking
|
|
24742
|
+
// inert. The priority prefix it adds is redundant anyway, because
|
|
24743
|
+
// symbol-sort-key only orders WITHIN a layer; cross-layer order is
|
|
24744
|
+
// the layer stack's job (spliceByLabelPriority). PLACENAME reads
|
|
24745
|
+
// its own `rank` bare for exactly this reason.
|
|
24746
|
+
//
|
|
24747
|
+
// Tiles built before `rank` existed fall back to depth ordering,
|
|
24748
|
+
// so they degrade to shoal-first rather than to one flat value.
|
|
24749
|
+
"symbol-sort-key": sortKey
|
|
24750
|
+
},
|
|
24751
|
+
paint: {
|
|
24752
|
+
"text-color": resolveColor("CHBLK", palette),
|
|
24753
|
+
// Halo in the dredged-area fill itself, so the note reads as set
|
|
24754
|
+
// INTO the channel rather than floating over it. Kept thin: the
|
|
24755
|
+
// note crosses its own dashed limit and whatever soundings sit in
|
|
24756
|
+
// the channel, so it needs SOME separation — but a wide halo on
|
|
24757
|
+
// ~11px type erodes the glyph strokes and turns black type grey.
|
|
24758
|
+
"text-halo-color": resolveColor("DEPMD", palette),
|
|
24759
|
+
"text-halo-width": 1
|
|
24760
|
+
},
|
|
24761
|
+
metadata: {
|
|
24762
|
+
"chrt:dredgeNote": true,
|
|
24763
|
+
"chrt:labelPriority": DRGNOTE_LABEL_PRIORITY
|
|
24764
|
+
}
|
|
24765
|
+
}
|
|
24766
|
+
];
|
|
24767
|
+
}
|
|
24577
24768
|
|
|
24578
24769
|
// src/atlas/feature-decimation.ts
|
|
24579
24770
|
function getGridSizeForZoom(zoom) {
|
|
@@ -27844,6 +28035,22 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION, opts =
|
|
|
27844
28035
|
metadata: { "s52:objectClass": "ACHARE", "s52:role": "boundary" }
|
|
27845
28036
|
});
|
|
27846
28037
|
}
|
|
28038
|
+
if (objectClass === "DRGARE" && resolved.type === "fill") {
|
|
28039
|
+
layers.push({
|
|
28040
|
+
id: "s52-DRGARE-boundary",
|
|
28041
|
+
type: "line",
|
|
28042
|
+
source: sourceId,
|
|
28043
|
+
"source-layer": "DRGARE",
|
|
28044
|
+
filter: GEOM_FILTERS.fill,
|
|
28045
|
+
paint: {
|
|
28046
|
+
"line-color": resolveColor("CHGRD", ct),
|
|
28047
|
+
"line-width": 0.9,
|
|
28048
|
+
"line-dasharray": [4, 3],
|
|
28049
|
+
"line-opacity": 0.75
|
|
28050
|
+
},
|
|
28051
|
+
metadata: { "s52:objectClass": "DRGARE", "s52:role": "boundary" }
|
|
28052
|
+
});
|
|
28053
|
+
}
|
|
27847
28054
|
if (objectClass === "ACHARE" && resolved.type === "fill") {
|
|
27848
28055
|
layers.push({
|
|
27849
28056
|
id: "s52-ACHARE-anchor-icon",
|
|
@@ -29919,6 +30126,17 @@ function byLabelPriorityBottomUp(bundles) {
|
|
|
29919
30126
|
(a, b) => getLabelPriority(b.objectClass) - getLabelPriority(a.objectClass)
|
|
29920
30127
|
);
|
|
29921
30128
|
}
|
|
30129
|
+
function spliceByLabelPriority(labelLayers, incoming, priority) {
|
|
30130
|
+
if (incoming.length === 0) return;
|
|
30131
|
+
const rankOf = (l) => {
|
|
30132
|
+
const meta = l.metadata;
|
|
30133
|
+
const p = meta?.["chrt:labelPriority"];
|
|
30134
|
+
return typeof p === "number" ? p : DEFAULT_LABEL_PRIORITY;
|
|
30135
|
+
};
|
|
30136
|
+
const at = labelLayers.findIndex((l) => rankOf(l) < priority);
|
|
30137
|
+
if (at === -1) labelLayers.push(...incoming);
|
|
30138
|
+
else labelLayers.splice(at, 0, ...incoming);
|
|
30139
|
+
}
|
|
29922
30140
|
function chartModeBandClauses(layer, B, higherCascadeBands, lockedBounds, isRequestedBand) {
|
|
29923
30141
|
const parts = [bandFilterExpression(B)];
|
|
29924
30142
|
if (!isDominanceExempt(layer)) {
|
|
@@ -30105,6 +30323,15 @@ function generateStyle(palette = "DAY", opts = {}) {
|
|
|
30105
30323
|
labelLayers.push(variant);
|
|
30106
30324
|
}
|
|
30107
30325
|
}
|
|
30326
|
+
spliceByLabelPriority(
|
|
30327
|
+
labelLayers,
|
|
30328
|
+
buildDredgeNoteLayers(
|
|
30329
|
+
sourceId,
|
|
30330
|
+
palette,
|
|
30331
|
+
opts.depthUnits ?? "meters"
|
|
30332
|
+
),
|
|
30333
|
+
DRGNOTE_LABEL_PRIORITY
|
|
30334
|
+
);
|
|
30108
30335
|
layers.push(...labelLayers);
|
|
30109
30336
|
} else {
|
|
30110
30337
|
const emitBand = (base, code) => bandFan === "legacy" ? makeBandVariants(base, code) : makeCollapsedBandVariant(base, code, isDominanceExempt(base));
|
|
@@ -30192,6 +30419,15 @@ function generateStyle(palette = "DAY", opts = {}) {
|
|
|
30192
30419
|
}
|
|
30193
30420
|
}
|
|
30194
30421
|
if (!majorsEmitted) labelLayers.push(...majorWaterLayers);
|
|
30422
|
+
spliceByLabelPriority(
|
|
30423
|
+
labelLayers,
|
|
30424
|
+
buildDredgeNoteLayers(
|
|
30425
|
+
sourceId,
|
|
30426
|
+
palette,
|
|
30427
|
+
opts.depthUnits ?? "meters"
|
|
30428
|
+
),
|
|
30429
|
+
DRGNOTE_LABEL_PRIORITY
|
|
30430
|
+
);
|
|
30195
30431
|
layers.push(...labelLayers);
|
|
30196
30432
|
}
|
|
30197
30433
|
const symbolSet = opts.symbolSet ?? "s52";
|