@orbat-mapper/tactical-draw-adapter-maplibre 0.2.0-alpha.17 → 0.2.0-alpha.19

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.
Files changed (2) hide show
  1. package/dist/index.mjs +102 -29
  2. package/package.json +6 -5
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { project, unproject } from "@orbat-mapper/control-measures";
2
- import { BaseMapAdapter, DEFAULT_TEXT_SIZE_MAX_PIXELS, DEFAULT_TEXT_SIZE_MIN_PIXELS, HATCH_PATTERNS, PointerCallbackHub, TOUCH_HIT_TOLERANCE_PX, bindAbortable, evaluatePickCandidates, fillPatternImageId, makeFillPatternImage, mergeNativeAndCachedPickFeatures, nearestWorldCopyLng, pickHitTolerance, pickPointerType } from "@orbat-mapper/tactical-draw";
2
+ import { BaseMapAdapter, DEFAULT_TEXT_SIZE_MAX_PIXELS, DEFAULT_TEXT_SIZE_MIN_PIXELS, HATCH_PATTERNS, PointerCallbackHub, TEXT_HALO_COLOR, TOUCH_HIT_TOLERANCE_PX, bindAbortable, evaluatePickCandidates, fillPatternImageId, makeFillPatternImage, mergeNativeAndCachedPickFeatures, nearestWorldCopyLng, pickHitTolerance, pickPointerType } from "@orbat-mapper/tactical-draw";
3
3
  //#region src/ml-adapter.ts
4
4
  /** Feature property key for the resolved hatch-pattern image id (see `promoteFeature`). */
5
5
  const FILL_PATTERN_IMAGE_ID_PROPERTY = "_fillPatternImageId";
@@ -103,7 +103,8 @@ function buildIconLayer(id, source) {
103
103
  "icon-rotation-alignment": "viewport",
104
104
  "icon-pitch-alignment": "viewport",
105
105
  "icon-allow-overlap": true,
106
- "icon-ignore-placement": true
106
+ "icon-ignore-placement": true,
107
+ "symbol-z-order": "source"
107
108
  },
108
109
  paint: { "icon-opacity": [
109
110
  "coalesce",
@@ -299,6 +300,74 @@ function buildTextFieldExpression(text) {
299
300
  rawTextField
300
301
  ] : rawTextField;
301
302
  }
303
+ const HAS_TEXT_HALO = [
304
+ "boolean",
305
+ ["get", "textHalo"],
306
+ false
307
+ ];
308
+ const HAS_TEXT_BACKGROUND = [
309
+ "boolean",
310
+ ["get", "textBackground"],
311
+ false
312
+ ];
313
+ /**
314
+ * Per-feature `text-halo-color` value: `textHalo` wins over both the layer's
315
+ * `text.strokeColor` and the `textBackground` halo, matching the OL/Leaflet
316
+ * adapters' precedence. Factored out so `setLayerStyle`'s incremental
317
+ * `text-halo-color` update (below) can reuse it instead of dropping the
318
+ * `textHalo` case.
319
+ */
320
+ function buildTextHaloColorExpression(text) {
321
+ const fallback = text.strokeColor ? text.strokeColor : [
322
+ "case",
323
+ HAS_TEXT_BACKGROUND,
324
+ "#ffffff",
325
+ "rgba(255,255,255,0)"
326
+ ];
327
+ return [
328
+ "case",
329
+ HAS_TEXT_HALO,
330
+ [
331
+ "coalesce",
332
+ ["get", "textHaloColor"],
333
+ TEXT_HALO_COLOR
334
+ ],
335
+ fallback
336
+ ];
337
+ }
338
+ /**
339
+ * Per-feature `text-halo-width` value, mirroring
340
+ * `buildTextHaloColorExpression`'s precedence. MapLibre's `text-halo-width`
341
+ * already extends outward from the glyph edge, matching
342
+ * `resolveTextHaloWidth`'s own outward-depth semantics, so the `textHalo`
343
+ * case uses its formula directly (unlike OpenLayers's straddling canvas
344
+ * stroke, which must double it).
345
+ */
346
+ function buildTextHaloWidthExpression(text) {
347
+ return [
348
+ "case",
349
+ HAS_TEXT_HALO,
350
+ [
351
+ "max",
352
+ 1.5,
353
+ [
354
+ "/",
355
+ [
356
+ "coalesce",
357
+ ["get", "textSizePixels"],
358
+ 24
359
+ ],
360
+ 8
361
+ ]
362
+ ],
363
+ text.strokeColor ? text.strokeWidth ?? 1 : [
364
+ "case",
365
+ HAS_TEXT_BACKGROUND,
366
+ 3,
367
+ 0
368
+ ]
369
+ ];
370
+ }
302
371
  /**
303
372
  * Build the layout and paint objects for a symbol (text) layer.
304
373
  * Centralises the rotation convention so `createLayer` and `setLayerStyle`
@@ -332,11 +401,6 @@ function buildSymbolLayer(symbolId, sourceId, text) {
332
401
  ],
333
402
  "#000"
334
403
  ];
335
- const hasTextBackground = [
336
- "boolean",
337
- ["get", "textBackground"],
338
- false
339
- ];
340
404
  const textAnchor = text.labelProperty ? [
341
405
  "case",
342
406
  [
@@ -398,22 +462,13 @@ function buildSymbolLayer(symbolId, sourceId, text) {
398
462
  "text-max-width": 9999,
399
463
  "text-rotation-alignment": "map",
400
464
  "text-pitch-alignment": "map",
401
- "text-allow-overlap": true
465
+ "text-allow-overlap": true,
466
+ "symbol-z-order": "source"
402
467
  },
403
468
  paint: {
404
469
  "text-color": textColor,
405
- "text-halo-color": text.strokeColor ? text.strokeColor : [
406
- "case",
407
- hasTextBackground,
408
- "#ffffff",
409
- "rgba(255,255,255,0)"
410
- ],
411
- "text-halo-width": text.strokeColor ? text.strokeWidth ?? 1 : [
412
- "case",
413
- hasTextBackground,
414
- 3,
415
- 0
416
- ],
470
+ "text-halo-color": buildTextHaloColorExpression(text),
471
+ "text-halo-width": buildTextHaloWidthExpression(text),
417
472
  "text-opacity": TEXT_OPACITY_EXPRESSION
418
473
  }
419
474
  };
@@ -490,14 +545,25 @@ const FILL_PATTERN_PAINT = {
490
545
  "fill-pattern": ["get", FILL_PATTERN_IMAGE_ID_PROPERTY],
491
546
  "fill-opacity": 1
492
547
  };
548
+ const SOLID_LINE_DASH = [1, 0];
493
549
  function buildLinePaint(style) {
494
550
  const colorDefault = style?.strokeColor ?? DEFAULT_LINE_COLOR;
495
551
  const widthDefault = style?.strokeWidth ?? DEFAULT_LINE_WIDTH;
552
+ const dashDefault = style?.strokeDash?.length ? [...style.strokeDash] : SOLID_LINE_DASH;
496
553
  const styleObj = [
497
554
  "coalesce",
498
555
  ["get", "style"],
499
556
  ["literal", {}]
500
557
  ];
558
+ const dashExpr = [
559
+ "coalesce",
560
+ [
561
+ "get",
562
+ "strokeDash",
563
+ styleObj
564
+ ],
565
+ ["literal", dashDefault]
566
+ ];
501
567
  return {
502
568
  "line-color": [
503
569
  "coalesce",
@@ -517,7 +583,16 @@ function buildLinePaint(style) {
517
583
  ],
518
584
  widthDefault
519
585
  ],
520
- ...style?.strokeDash ? { "line-dasharray": style.strokeDash } : {}
586
+ "line-dasharray": [
587
+ "case",
588
+ [
589
+ ">",
590
+ ["length", dashExpr],
591
+ 0
592
+ ],
593
+ dashExpr,
594
+ ["literal", SOLID_LINE_DASH]
595
+ ]
521
596
  };
522
597
  }
523
598
  var MapLibreAdapter = class extends BaseMapAdapter {
@@ -890,12 +965,10 @@ var MapLibreAdapter = class extends BaseMapAdapter {
890
965
  if (mlId.endsWith("-fill-pattern")) continue;
891
966
  this.map.setPaintProperty(mlId, "fill-color", buildFillPaint(style)["fill-color"]);
892
967
  } else if (type === "line") {
893
- if (style.strokeColor !== void 0 || style.strokeWidth !== void 0) {
894
- const paint = buildLinePaint(style);
895
- if (style.strokeColor !== void 0) this.map.setPaintProperty(mlId, "line-color", paint["line-color"]);
896
- if (style.strokeWidth !== void 0) this.map.setPaintProperty(mlId, "line-width", paint["line-width"]);
897
- }
898
- if (style.strokeDash) this.map.setPaintProperty(mlId, "line-dasharray", style.strokeDash);
968
+ const paint = buildLinePaint(style);
969
+ if (style.strokeColor !== void 0) this.map.setPaintProperty(mlId, "line-color", paint["line-color"]);
970
+ if (style.strokeWidth !== void 0) this.map.setPaintProperty(mlId, "line-width", paint["line-width"]);
971
+ if (style.strokeDash !== void 0) this.map.setPaintProperty(mlId, "line-dasharray", paint["line-dasharray"]);
899
972
  } else if (type === "circle") {
900
973
  const paint = buildCirclePaint(style);
901
974
  this.map.setPaintProperty(mlId, "circle-radius", paint["circle-radius"]);
@@ -906,8 +979,8 @@ var MapLibreAdapter = class extends BaseMapAdapter {
906
979
  } else if (type === "symbol" && style.text) {
907
980
  if (style.text.text || style.text.labelProperty) this.map.setLayoutProperty(mlId, "text-field", buildTextFieldExpression(style.text));
908
981
  if (style.text.fillColor) this.map.setPaintProperty(mlId, "text-color", style.text.fillColor);
909
- if (style.text.strokeColor) this.map.setPaintProperty(mlId, "text-halo-color", style.text.strokeColor);
910
- if (style.text.strokeWidth !== void 0) this.map.setPaintProperty(mlId, "text-halo-width", style.text.strokeWidth);
982
+ if (style.text.strokeColor) this.map.setPaintProperty(mlId, "text-halo-color", buildTextHaloColorExpression(style.text));
983
+ if (style.text.strokeWidth !== void 0) this.map.setPaintProperty(mlId, "text-halo-width", buildTextHaloWidthExpression(style.text));
911
984
  }
912
985
  }
913
986
  if (style.text && !handle.mlLayerIds.some((id) => id.endsWith("-symbol"))) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbat-mapper/tactical-draw-adapter-maplibre",
3
- "version": "0.2.0-alpha.17",
3
+ "version": "0.2.0-alpha.19",
4
4
  "description": "MapLibre GL JS engine adapter for @orbat-mapper/tactical-draw. Draw and edit tactical control measures (MIL-STD-2525 / APP-6) on a MapLibre map.",
5
5
  "license": "MIT",
6
6
  "author": "Orbat Mapper",
@@ -37,17 +37,18 @@
37
37
  "access": "public"
38
38
  },
39
39
  "dependencies": {
40
- "@orbat-mapper/control-measures": "^0.2.0-alpha.24",
41
- "@orbat-mapper/tactical-draw": "^0.2.0-alpha.32"
40
+ "@orbat-mapper/control-measures": "^0.2.0-alpha.25",
41
+ "@orbat-mapper/tactical-draw": "^0.2.0-alpha.34"
42
42
  },
43
43
  "peerDependencies": {
44
- "maplibre-gl": ">=4.0.0 <6.0.0"
44
+ "maplibre-gl": ">=5.8.0 <6.0.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@arethetypeswrong/core": "^0.18.3",
48
+ "@maplibre/maplibre-gl-style-spec": "^24.10.0",
48
49
  "@types/geojson": "^7946.0.16",
49
50
  "jsdom": "^27.4.0",
50
- "maplibre-gl": "^5.18.0",
51
+ "maplibre-gl": "^5.24.0",
51
52
  "publint": "^0.3.21",
52
53
  "tsdown": "^0.22.2",
53
54
  "typescript": "~5.9.3",