@chrtco/sdk 0.7.5 → 0.7.6

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.js CHANGED
@@ -3143,18 +3143,37 @@ function depareFillExpression(ct = "DAY") {
3143
3143
  resolveColor("DEPDW", ct)
3144
3144
  ];
3145
3145
  }
3146
- function colourCodeCase(cases, fallback) {
3147
- const colourStr = ["to-string", ["coalesce", ["get", "COLOUR"], ["get", "colour"], ""]];
3146
+ function listAttrString(attr) {
3147
+ return ["to-string", ["coalesce", ["get", attr], ["get", attr.toLowerCase()], ""]];
3148
+ }
3149
+ function listAttrCase(attr, cases, fallback) {
3150
+ const attrStr = listAttrString(attr);
3148
3151
  const expr = ["case"];
3149
3152
  for (const [code, value] of cases) {
3150
- expr.push([">=", ["index-of", `"${code}"`, colourStr], 0], value);
3153
+ expr.push([">=", ["index-of", `"${code}"`, attrStr], 0], value);
3154
+ }
3155
+ for (const [code, value] of cases) {
3156
+ expr.push(["==", attrStr, code], value);
3151
3157
  }
3152
3158
  for (const [code, value] of cases) {
3153
- expr.push(["==", colourStr, code], value);
3159
+ expr.push(["==", attrStr, `[${code}]`], value);
3154
3160
  }
3155
3161
  expr.push(fallback);
3156
3162
  return expr;
3157
3163
  }
3164
+ function listAttrHas(attr, codes) {
3165
+ const attrStr = listAttrString(attr);
3166
+ const clauses = [];
3167
+ for (const code of codes) {
3168
+ clauses.push([">=", ["index-of", `"${code}"`, attrStr], 0]);
3169
+ clauses.push(["==", attrStr, code]);
3170
+ clauses.push(["==", attrStr, `[${code}]`]);
3171
+ }
3172
+ return ["any", ...clauses];
3173
+ }
3174
+ function colourCodeCase(cases, fallback) {
3175
+ return listAttrCase("COLOUR", cases, fallback);
3176
+ }
3158
3177
  function lightColor(props, ct = "DAY") {
3159
3178
  const raw = props.COLOUR ?? props.colour;
3160
3179
  const code = Array.isArray(raw) ? Number(raw[0]) : typeof raw === "string" && raw.startsWith("[") ? Number(JSON.parse(raw)[0]) : Number(raw ?? 0);
@@ -5193,7 +5212,7 @@ var NAUTICAL_SYMBOLS = [
5193
5212
  description: "Church spire or steeple, conspicuous from seaward. Useful for visual fixing.",
5194
5213
  s52PlRef: "LNDMRK17",
5195
5214
  attributeKey: "CATLMK",
5196
- attributeValue: 17,
5215
+ attributeValue: 20,
5197
5216
  renderSize: "32x32",
5198
5217
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Spire, building, position circle" }],
5199
5218
  lineStyles: [{ element: "Building outline", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5210,7 +5229,7 @@ var NAUTICAL_SYMBOLS = [
5210
5229
  description: "Tower conspicuous from seaward. General-purpose landmark symbol.",
5211
5230
  s52PlRef: "LNDMRK20",
5212
5231
  attributeKey: "CATLMK",
5213
- attributeValue: 20,
5232
+ attributeValue: 17,
5214
5233
  renderSize: "32x32",
5215
5234
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tower body, cap, position circle" }],
5216
5235
  lineStyles: [{ element: "Tower outline", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5227,7 +5246,7 @@ var NAUTICAL_SYMBOLS = [
5227
5246
  description: "Industrial chimney or smokestack visible from the sea.",
5228
5247
  s52PlRef: "LNDMRK01",
5229
5248
  attributeKey: "CATLMK",
5230
- attributeValue: 1,
5249
+ attributeValue: 3,
5231
5250
  renderSize: "32x32",
5232
5251
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Chimney body, smoke, position circle" }],
5233
5252
  lineStyles: [{ element: "Body outline", width: 0.8, color: "#000000" }, { element: "Smoke plume", width: 1, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5244,7 +5263,7 @@ var NAUTICAL_SYMBOLS = [
5244
5263
  description: "Flagstaff or flagpole conspicuous from seaward.",
5245
5264
  s52PlRef: "LNDMRK03",
5246
5265
  attributeKey: "CATLMK",
5247
- attributeValue: 3,
5266
+ attributeValue: 5,
5248
5267
  renderSize: "32x32",
5249
5268
  colors: [
5250
5269
  { token: "CHBLK", hex: "#000000", usage: "Pole and position circle" },
@@ -5264,7 +5283,7 @@ var NAUTICAL_SYMBOLS = [
5264
5283
  description: "Monument or memorial conspicuous from the sea.",
5265
5284
  s52PlRef: "LNDMRK05",
5266
5285
  attributeKey: "CATLMK",
5267
- attributeValue: 5,
5286
+ attributeValue: 9,
5268
5287
  renderSize: "32x32",
5269
5288
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Monument body, base, position circle" }],
5270
5289
  lineStyles: [{ element: "Body outline", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5279,9 +5298,9 @@ var NAUTICAL_SYMBOLS = [
5279
5298
  getSvg: landmarkWindmill,
5280
5299
  group: "landmarks",
5281
5300
  description: "Traditional windmill with rotating vanes. Conspicuous landmark.",
5282
- s52PlRef: "LNDMRK21",
5301
+ s52PlRef: "WNDMIL12",
5283
5302
  attributeKey: "CATLMK",
5284
- attributeValue: 7,
5303
+ attributeValue: 18,
5285
5304
  renderSize: "32x32",
5286
5305
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tower, vanes, hub, position circle" }],
5287
5306
  lineStyles: [{ element: "Tower", width: 1.5, color: "#000000" }, { element: "Vane arms", width: 1.2, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5296,9 +5315,9 @@ var NAUTICAL_SYMBOLS = [
5296
5315
  getSvg: landmarkWindTurbine,
5297
5316
  group: "landmarks",
5298
5317
  description: "Modern 3-blade wind turbine. Increasingly common offshore landmark.",
5299
- s52PlRef: "LNDMRK22",
5318
+ s52PlRef: "WIMCON11",
5300
5319
  attributeKey: "CATLMK",
5301
- attributeValue: 26,
5320
+ attributeValue: 19,
5302
5321
  renderSize: "32x32",
5303
5322
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tower, blades, hub, position circle" }],
5304
5323
  lineStyles: [{ element: "Tower", width: 1.5, color: "#000000" }, { element: "Blades", width: 1.2, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5315,7 +5334,7 @@ var NAUTICAL_SYMBOLS = [
5315
5334
  description: "Dome or cupola (e.g., observatory, mosque) visible from the sea.",
5316
5335
  s52PlRef: "LNDMRK03",
5317
5336
  attributeKey: "CATLMK",
5318
- attributeValue: 6,
5337
+ attributeValue: 15,
5319
5338
  renderSize: "32x32",
5320
5339
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Dome, base, position circle" }],
5321
5340
  lineStyles: [{ element: "Base outline", width: 0.8, color: "#000000" }, { element: "Dome curve", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5332,7 +5351,7 @@ var NAUTICAL_SYMBOLS = [
5332
5351
  description: "Radar scanner antenna conspicuous from seaward.",
5333
5352
  s52PlRef: "LNDMRK12",
5334
5353
  attributeKey: "CATLMK",
5335
- attributeValue: 9,
5354
+ attributeValue: 16,
5336
5355
  renderSize: "32x32",
5337
5356
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tower, scanner dish, position circle" }],
5338
5357
  lineStyles: [{ element: "Tower", width: 1.5, color: "#000000" }, { element: "Scanner frame", width: 1.5, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5349,7 +5368,7 @@ var NAUTICAL_SYMBOLS = [
5349
5368
  description: "Satellite dish or parabolic antenna visible from the sea.",
5350
5369
  s52PlRef: "LNDMRK12",
5351
5370
  attributeKey: "CATLMK",
5352
- attributeValue: 12,
5371
+ attributeValue: 4,
5353
5372
  renderSize: "32x32",
5354
5373
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tower, dish, position circle" }],
5355
5374
  lineStyles: [{ element: "Tower", width: 1.5, color: "#000000" }, { element: "Dish curve", width: 1.5, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5364,9 +5383,9 @@ var NAUTICAL_SYMBOLS = [
5364
5383
  getSvg: landmarkWaterTower,
5365
5384
  group: "landmarks",
5366
5385
  description: "Water tower. Elevated tank on supporting structure, conspicuous landmark.",
5367
- s52PlRef: "LNDMRK19",
5368
- attributeKey: "CATLMK",
5369
- attributeValue: 15,
5386
+ s52PlRef: "TOWERS12",
5387
+ attributeKey: "CATSIL",
5388
+ attributeValue: 4,
5370
5389
  renderSize: "32x32",
5371
5390
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tank, legs, position circle" }],
5372
5391
  lineStyles: [{ element: "Leg outlines", width: 1.2, color: "#000000" }, { element: "Tank outline", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5383,7 +5402,7 @@ var NAUTICAL_SYMBOLS = [
5383
5402
  description: "Radio or television transmission mast with horizontal cross-arms.",
5384
5403
  s52PlRef: "LNDMRK10",
5385
5404
  attributeKey: "CATLMK",
5386
- attributeValue: 8,
5405
+ attributeValue: 7,
5387
5406
  renderSize: "32x32",
5388
5407
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Mast, cross-arms, top, position circle" }],
5389
5408
  lineStyles: [{ element: "Main mast", width: 1.5, color: "#000000" }, { element: "Cross-arms", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5400,7 +5419,7 @@ var NAUTICAL_SYMBOLS = [
5400
5419
  description: "Religious cross or calvary conspicuous from seaward.",
5401
5420
  s52PlRef: "LNDMRK05",
5402
5421
  attributeKey: "CATLMK",
5403
- attributeValue: 10,
5422
+ attributeValue: 14,
5404
5423
  renderSize: "32x32",
5405
5424
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Cross arms and position circle" }],
5406
5425
  lineStyles: [{ element: "Vertical arm", width: 2, color: "#000000" }, { element: "Horizontal arm", width: 2, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5417,7 +5436,7 @@ var NAUTICAL_SYMBOLS = [
5417
5436
  description: "General mast (not radio/TV). Pole with spherical top.",
5418
5437
  s52PlRef: "LNDMRK10",
5419
5438
  attributeKey: "CATLMK",
5420
- attributeValue: 14,
5439
+ attributeValue: 7,
5421
5440
  renderSize: "32x32",
5422
5441
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Mast pole, top ball, position circle" }],
5423
5442
  lineStyles: [{ element: "Mast pole", width: 2, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5432,9 +5451,9 @@ var NAUTICAL_SYMBOLS = [
5432
5451
  getSvg: landmarkSilo,
5433
5452
  group: "landmarks",
5434
5453
  description: "Silo, grain elevator, or storage tank conspicuous from the sea.",
5435
- s52PlRef: "LNDMRK17",
5436
- attributeKey: "CATLMK",
5437
- attributeValue: 33,
5454
+ s52PlRef: "SILBUI01",
5455
+ attributeKey: "CATSIL",
5456
+ attributeValue: 1,
5438
5457
  renderSize: "32x32",
5439
5458
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Body, dome top, position circle" }],
5440
5459
  lineStyles: [{ element: "Body outline", width: 0.8, color: "#000000" }, { element: "Dome curve", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5836,27 +5855,18 @@ function getIconExpression(layerName) {
5836
5855
  ];
5837
5856
  }
5838
5857
  if (layerName === "LNDMRK") {
5839
- return [
5840
- "match",
5841
- ["coalesce", ["get", "CATLMK"], ["get", "catlmk"], 0],
5842
- 1,
5843
- "CAIRNS11",
5844
- // Cairn
5845
- 17,
5846
- "BCNTOW01",
5847
- // Tower
5848
- 18,
5849
- "LNDMRK18",
5858
+ return listAttrCase("CATLMK", [
5859
+ ["18", "LNDMRK18"],
5850
5860
  // Windmill (4-vane)
5851
- 19,
5852
- "LNDMRK19",
5861
+ ["19", "LNDMRK19"],
5853
5862
  // Wind motor / turbine (3-blade)
5854
- 20,
5855
- "BCNTOW01",
5863
+ ["1", "CAIRNS11"],
5864
+ // Cairn
5865
+ ["17", "BCNTOW01"],
5866
+ // Tower
5867
+ ["20", "BCNTOW01"]
5856
5868
  // Spire → tower
5857
- "BCNTOW01"
5858
- // Default: tower
5859
- ];
5869
+ ], "BCNTOW01");
5860
5870
  }
5861
5871
  if (layerName === "DAYMAR") {
5862
5872
  return [
@@ -5996,18 +6006,12 @@ function getIconExpression(layerName) {
5996
6006
  ];
5997
6007
  }
5998
6008
  if (layerName === "LIGHTS") {
5999
- return [
6000
- "match",
6001
- ["coalesce", ["get", "CATLIT"], ["get", "catlit"], 0],
6002
- 8,
6003
- "LIGHTS82",
6004
- // Aero light
6005
- 9,
6006
- "LIGHTS82",
6007
- // Air obstruction light
6008
- "LIGHTS11"
6009
- // Default: major light
6010
- ];
6009
+ return listAttrCase("CATLIT", [
6010
+ ["8", "LIGHTS82"],
6011
+ // Floodlight
6012
+ ["9", "LIGHTS82"]
6013
+ // Strip light
6014
+ ], "LIGHTS11");
6011
6015
  }
6012
6016
  return SYMBOL_MAP[layerName] ?? "";
6013
6017
  }
@@ -6699,6 +6703,11 @@ var LABEL_BEHAVIOR = {
6699
6703
  function getLabelBehavior(layerName) {
6700
6704
  return LABEL_BEHAVIOR[layerName] ?? "feature-band-gated";
6701
6705
  }
6706
+ var LABEL_ANCHOR_FILTER = [
6707
+ "!=",
6708
+ ["get", "_label_anchor"],
6709
+ false
6710
+ ];
6702
6711
  function getLabelConfig(layerName, opts = {}) {
6703
6712
  const ct = opts.colorTable ?? "DAY";
6704
6713
  switch (layerName) {
@@ -7490,6 +7499,18 @@ function preprocessSoundings(fc) {
7490
7499
  }
7491
7500
  return { type: "FeatureCollection", features };
7492
7501
  }
7502
+ function firstListCode(raw) {
7503
+ if (raw == null) return NaN;
7504
+ if (Array.isArray(raw)) return Number(raw[0]);
7505
+ if (typeof raw === "string" && raw.startsWith("[")) {
7506
+ try {
7507
+ const arr = JSON.parse(raw);
7508
+ if (Array.isArray(arr)) return Number(arr[0]);
7509
+ } catch {
7510
+ }
7511
+ }
7512
+ return Number(raw);
7513
+ }
7493
7514
  function preprocessLights(fc) {
7494
7515
  return {
7495
7516
  type: "FeatureCollection",
@@ -7498,7 +7519,7 @@ function preprocessLights(fc) {
7498
7519
  const parts = [];
7499
7520
  const litchr = Number(props.LITCHR);
7500
7521
  if (litchr && LITCHR_ABBR[litchr]) parts.push(LITCHR_ABBR[litchr]);
7501
- const colour = Number(props.COLOUR);
7522
+ const colour = firstListCode(props.COLOUR);
7502
7523
  if (colour && COLOUR_ABBR[colour]) parts.push(COLOUR_ABBR[colour]);
7503
7524
  const sigper = Number(props.SIGPER);
7504
7525
  if (sigper && sigper > 0) parts.push(sigper + "s");
@@ -7572,7 +7593,7 @@ function preprocessNavAids(fc) {
7572
7593
  const match = objnam.match(/(\d+[A-Z]?)\s*$/);
7573
7594
  if (!match) return f;
7574
7595
  const designation = match[1];
7575
- const colourCode = Number(props.COLOUR);
7596
+ const colourCode = firstListCode(props.COLOUR);
7576
7597
  const prefix = NAV_COLOUR_PREFIX[colourCode];
7577
7598
  const label = prefix ? `${prefix} "${designation}"` : `"${designation}"`;
7578
7599
  return {
@@ -9651,23 +9672,30 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION) {
9651
9672
  }
9652
9673
  if (objectClass === "LNDMRK" && resolved.type === "symbol") {
9653
9674
  const baseFilterParts = layer.filter && layer.filter[0] === "all" ? layer.filter.slice(1) : layer.filter ? [layer.filter] : [];
9654
- const catlmk = ["coalesce", ["get", "CATLMK"], ["get", "catlmk"], 0];
9655
- const isWind = ["any", ["==", catlmk, 18], ["==", catlmk, 19]];
9656
- const isLighthouse = ["==", catlmk, 17];
9675
+ const isWind = listAttrHas("CATLMK", ["18", "19"]);
9676
+ const isLighthouse = listAttrHas("CATLMK", ["17"]);
9657
9677
  const scaminFloor = scaminToMinZoom(entry?.scamin);
9658
9678
  const windLayer = {
9659
9679
  ...layer,
9660
9680
  id: `s52-${objectClass}-wind-symbol`,
9661
- filter: ["all", ...baseFilterParts, isWind]
9681
+ filter: ["all", ...baseFilterParts, isWind],
9682
+ // Explicit, not inherited: turbines share exact coordinates with
9683
+ // their aviation-light LIGHTS feature; without allow-overlap the
9684
+ // turbine icon loses collision to the LIGHTS flare and vanishes.
9685
+ // (The value currently also arrives via the entry-layout
9686
+ // spread-last chain, but that chain is fragile — see s52-lookup
9687
+ // LNDMRK entry — so the intent is pinned here.)
9688
+ layout: { ...layer.layout ?? {}, "icon-allow-overlap": true }
9662
9689
  };
9663
9690
  delete windLayer.minzoom;
9664
9691
  const lighthouseLayer = {
9665
9692
  ...layer,
9666
9693
  id: `s52-${objectClass}-lighthouse-symbol`,
9667
- filter: ["all", ...baseFilterParts, isLighthouse],
9694
+ filter: ["all", ...baseFilterParts, isLighthouse, ["!", isWind]],
9668
9695
  layout: {
9669
9696
  ...layer.layout ?? {},
9670
- "icon-image": "LIGHTHOUSE01"
9697
+ "icon-image": "LIGHTHOUSE01",
9698
+ "icon-allow-overlap": true
9671
9699
  }
9672
9700
  };
9673
9701
  delete lighthouseLayer.minzoom;
@@ -10548,7 +10576,7 @@ function buildLabelLayer2(objectClass, ct, sourceId = DEFAULT_REGION, depthUnits
10548
10576
  delete layer.filter;
10549
10577
  }
10550
10578
  if (getLabelBehavior(objectClass) === "orientation-cross-band") {
10551
- delete layer.filter;
10579
+ layer.filter = LABEL_ANCHOR_FILTER;
10552
10580
  }
10553
10581
  return layer;
10554
10582
  }