@orbat-mapper/tactical-draw-adapter-maplibre 0.2.0-alpha.14 → 0.2.0-alpha.16
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.mjs +134 -15
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -139,19 +139,29 @@ function buildTextSizeExpression(text) {
|
|
|
139
139
|
14
|
|
140
140
|
];
|
|
141
141
|
const sizeAtZoom = (zoom) => {
|
|
142
|
+
const groundPx = [
|
|
143
|
+
"*",
|
|
144
|
+
["get", "textSizeMeters"],
|
|
145
|
+
Math.pow(2, zoom + 9) / WEB_MERCATOR_CIRCUMFERENCE
|
|
146
|
+
];
|
|
142
147
|
return [
|
|
143
148
|
"case",
|
|
144
149
|
["has", "textSizeMeters"],
|
|
145
150
|
[
|
|
146
|
-
"
|
|
147
|
-
|
|
151
|
+
"case",
|
|
152
|
+
["has", "textMaxSizePixels"],
|
|
148
153
|
[
|
|
149
|
-
"
|
|
150
|
-
|
|
154
|
+
"min",
|
|
155
|
+
["get", "textMaxSizePixels"],
|
|
156
|
+
groundPx
|
|
157
|
+
],
|
|
158
|
+
[
|
|
159
|
+
"min",
|
|
160
|
+
maxPx,
|
|
151
161
|
[
|
|
152
|
-
"
|
|
153
|
-
|
|
154
|
-
|
|
162
|
+
"max",
|
|
163
|
+
minPx,
|
|
164
|
+
groundPx
|
|
155
165
|
]
|
|
156
166
|
]
|
|
157
167
|
],
|
|
@@ -166,6 +176,50 @@ function buildTextSizeExpression(text) {
|
|
|
166
176
|
];
|
|
167
177
|
}
|
|
168
178
|
/**
|
|
179
|
+
* Companion to `buildTextSizeExpression` (ADR-0037): drives `text-opacity` to
|
|
180
|
+
* 0 once a ground-anchored Text graphic's derived on-screen size exceeds its
|
|
181
|
+
* `textMaxSizePixels` threshold, 1 otherwise (including every feature without
|
|
182
|
+
* a threshold, e.g. amplifier labels). Layout properties like `text-size`
|
|
183
|
+
* cannot represent "hidden", so hiding is a paint-property concern; `step`
|
|
184
|
+
* (rather than `interpolate`) is enough since opacity only ever needs to
|
|
185
|
+
* flip at a stop, evaluated at the same per-zoom granularity as the size
|
|
186
|
+
* expression.
|
|
187
|
+
*/
|
|
188
|
+
const TEXT_OPACITY_EXPRESSION = (() => {
|
|
189
|
+
const opacityAtZoom = (zoom) => {
|
|
190
|
+
return [
|
|
191
|
+
"case",
|
|
192
|
+
[
|
|
193
|
+
"all",
|
|
194
|
+
["has", "textSizeMeters"],
|
|
195
|
+
["has", "textMaxSizePixels"]
|
|
196
|
+
],
|
|
197
|
+
[
|
|
198
|
+
"case",
|
|
199
|
+
[
|
|
200
|
+
">",
|
|
201
|
+
[
|
|
202
|
+
"*",
|
|
203
|
+
["get", "textSizeMeters"],
|
|
204
|
+
Math.pow(2, zoom + 9) / WEB_MERCATOR_CIRCUMFERENCE
|
|
205
|
+
],
|
|
206
|
+
["get", "textMaxSizePixels"]
|
|
207
|
+
],
|
|
208
|
+
0,
|
|
209
|
+
1
|
|
210
|
+
],
|
|
211
|
+
1
|
|
212
|
+
];
|
|
213
|
+
};
|
|
214
|
+
const stops = Array.from({ length: 25 }, (_, zoom) => zoom);
|
|
215
|
+
return [
|
|
216
|
+
"step",
|
|
217
|
+
["zoom"],
|
|
218
|
+
opacityAtZoom(0),
|
|
219
|
+
...stops.slice(1).flatMap((zoom) => [zoom, opacityAtZoom(zoom)])
|
|
220
|
+
];
|
|
221
|
+
})();
|
|
222
|
+
/**
|
|
169
223
|
* Per-feature icon size, same zoom-stop scheme as `buildTextSizeExpression`:
|
|
170
224
|
* a ground-sized point symbol carries `iconSizeMeters`/`iconOctagonSize` (and
|
|
171
225
|
* optional `iconMinPixels`/`iconMaxPixels`), so the meters→pixels clamp is
|
|
@@ -224,6 +278,26 @@ function buildIconSizeExpression() {
|
|
|
224
278
|
* `properties.style.fillColor` overlay. Mirrors `buildCirclePaint`.
|
|
225
279
|
*/
|
|
226
280
|
/**
|
|
281
|
+
* Per-feature `text-field` value: the layer's literal text, or the feature's
|
|
282
|
+
* `labelProperty` value, uppercased when the feature's `textStyle` is
|
|
283
|
+
* `"caps"`. Factored out of `buildSymbolLayer` so `setLayerStyle`'s
|
|
284
|
+
* incremental `text-field` update (below) can reuse it instead of
|
|
285
|
+
* regressing to a caps-unaware plain `["get", ...]`.
|
|
286
|
+
*/
|
|
287
|
+
function buildTextFieldExpression(text) {
|
|
288
|
+
const rawTextField = text.labelProperty ? ["get", text.labelProperty] : text.text ?? "";
|
|
289
|
+
return text.labelProperty ? [
|
|
290
|
+
"case",
|
|
291
|
+
[
|
|
292
|
+
"==",
|
|
293
|
+
["get", "textStyle"],
|
|
294
|
+
"caps"
|
|
295
|
+
],
|
|
296
|
+
["upcase", rawTextField],
|
|
297
|
+
rawTextField
|
|
298
|
+
] : rawTextField;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
227
301
|
* Build the layout and paint objects for a symbol (text) layer.
|
|
228
302
|
* Centralises the rotation convention so `createLayer` and `setLayerStyle`
|
|
229
303
|
* stay in sync. Rotation follows the OpenLayers convention: `π − r` radians
|
|
@@ -256,6 +330,11 @@ function buildSymbolLayer(symbolId, sourceId, text) {
|
|
|
256
330
|
],
|
|
257
331
|
"#000"
|
|
258
332
|
];
|
|
333
|
+
const hasTextBackground = [
|
|
334
|
+
"boolean",
|
|
335
|
+
["get", "textBackground"],
|
|
336
|
+
false
|
|
337
|
+
];
|
|
259
338
|
const textAnchor = text.labelProperty ? [
|
|
260
339
|
"case",
|
|
261
340
|
[
|
|
@@ -272,16 +351,48 @@ function buildSymbolLayer(symbolId, sourceId, text) {
|
|
|
272
351
|
"right",
|
|
273
352
|
"center"
|
|
274
353
|
] : "center";
|
|
354
|
+
const textJustify = text.labelProperty ? [
|
|
355
|
+
"case",
|
|
356
|
+
[
|
|
357
|
+
"==",
|
|
358
|
+
["get", "textJustify"],
|
|
359
|
+
"left"
|
|
360
|
+
],
|
|
361
|
+
"left",
|
|
362
|
+
[
|
|
363
|
+
"==",
|
|
364
|
+
["get", "textJustify"],
|
|
365
|
+
"right"
|
|
366
|
+
],
|
|
367
|
+
"right",
|
|
368
|
+
"center"
|
|
369
|
+
] : "center";
|
|
275
370
|
return {
|
|
276
371
|
id: symbolId,
|
|
277
372
|
type: "symbol",
|
|
278
373
|
source: sourceId,
|
|
279
374
|
layout: {
|
|
280
|
-
"text-field": text
|
|
281
|
-
"text-font":
|
|
375
|
+
"text-field": buildTextFieldExpression(text),
|
|
376
|
+
"text-font": text.labelProperty ? [
|
|
377
|
+
"case",
|
|
378
|
+
[
|
|
379
|
+
"==",
|
|
380
|
+
["get", "textStyle"],
|
|
381
|
+
"italic"
|
|
382
|
+
],
|
|
383
|
+
["literal", ["Open Sans Italic"]],
|
|
384
|
+
[
|
|
385
|
+
"==",
|
|
386
|
+
["get", "textStyle"],
|
|
387
|
+
"light"
|
|
388
|
+
],
|
|
389
|
+
["literal", ["Open Sans Light"]],
|
|
390
|
+
["literal", ["Open Sans Regular"]]
|
|
391
|
+
] : ["Open Sans Regular"],
|
|
282
392
|
"text-size": buildTextSizeExpression(text),
|
|
283
393
|
"text-rotate": textRotate,
|
|
284
394
|
"text-anchor": textAnchor,
|
|
395
|
+
"text-justify": textJustify,
|
|
285
396
|
"text-max-width": 9999,
|
|
286
397
|
"text-rotation-alignment": "map",
|
|
287
398
|
"text-pitch-alignment": "map",
|
|
@@ -289,10 +400,19 @@ function buildSymbolLayer(symbolId, sourceId, text) {
|
|
|
289
400
|
},
|
|
290
401
|
paint: {
|
|
291
402
|
"text-color": textColor,
|
|
292
|
-
|
|
293
|
-
"
|
|
294
|
-
|
|
295
|
-
|
|
403
|
+
"text-halo-color": text.strokeColor ? text.strokeColor : [
|
|
404
|
+
"case",
|
|
405
|
+
hasTextBackground,
|
|
406
|
+
"#ffffff",
|
|
407
|
+
"rgba(255,255,255,0)"
|
|
408
|
+
],
|
|
409
|
+
"text-halo-width": text.strokeColor ? text.strokeWidth ?? 1 : [
|
|
410
|
+
"case",
|
|
411
|
+
hasTextBackground,
|
|
412
|
+
3,
|
|
413
|
+
0
|
|
414
|
+
],
|
|
415
|
+
"text-opacity": TEXT_OPACITY_EXPRESSION
|
|
296
416
|
}
|
|
297
417
|
};
|
|
298
418
|
}
|
|
@@ -782,8 +902,7 @@ var MapLibreAdapter = class extends BaseMapAdapter {
|
|
|
782
902
|
this.map.setPaintProperty(mlId, "circle-stroke-width", paint["circle-stroke-width"]);
|
|
783
903
|
this.map.setFilter(mlId, buildCirclePointFilter(style));
|
|
784
904
|
} else if (type === "symbol" && style.text) {
|
|
785
|
-
if (style.text.text) this.map.setLayoutProperty(mlId, "text-field", style.text
|
|
786
|
-
else if (style.text.labelProperty) this.map.setLayoutProperty(mlId, "text-field", ["get", style.text.labelProperty]);
|
|
905
|
+
if (style.text.text || style.text.labelProperty) this.map.setLayoutProperty(mlId, "text-field", buildTextFieldExpression(style.text));
|
|
787
906
|
if (style.text.fillColor) this.map.setPaintProperty(mlId, "text-color", style.text.fillColor);
|
|
788
907
|
if (style.text.strokeColor) this.map.setPaintProperty(mlId, "text-halo-color", style.text.strokeColor);
|
|
789
908
|
if (style.text.strokeWidth !== void 0) this.map.setPaintProperty(mlId, "text-halo-width", style.text.strokeWidth);
|
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.
|
|
3
|
+
"version": "0.2.0-alpha.16",
|
|
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,8 +37,8 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@orbat-mapper/control-measures": "^0.2.0-alpha.
|
|
41
|
-
"@orbat-mapper/tactical-draw": "^0.2.0-alpha.
|
|
40
|
+
"@orbat-mapper/control-measures": "^0.2.0-alpha.24",
|
|
41
|
+
"@orbat-mapper/tactical-draw": "^0.2.0-alpha.31"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"maplibre-gl": ">=4.0.0 <6.0.0"
|