map-2d-base 1.0.0

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.
@@ -0,0 +1,3260 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ var __async = (__this, __arguments, generator) => {
5
+ return new Promise((resolve, reject) => {
6
+ var fulfilled = (value) => {
7
+ try {
8
+ step(generator.next(value));
9
+ } catch (e) {
10
+ reject(e);
11
+ }
12
+ };
13
+ var rejected = (value) => {
14
+ try {
15
+ step(generator.throw(value));
16
+ } catch (e) {
17
+ reject(e);
18
+ }
19
+ };
20
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
21
+ step((generator = generator.apply(__this, __arguments)).next());
22
+ });
23
+ };
24
+ import { s as listenOnce, E as EventType, u as unlistenByKey, T as Target, B as BaseObject, c as clear, i as abstract, j as getUid, b as assert } from "./asserts-B5CSgOpZ.js";
25
+ import { c as clamp, b as toFixed } from "./math-CtjJ8U9C.js";
26
+ const ua = typeof navigator !== "undefined" && typeof navigator.userAgent !== "undefined" ? navigator.userAgent.toLowerCase() : "";
27
+ const SAFARI = ua.includes("safari") && !ua.includes("chrom");
28
+ SAFARI && (ua.includes("version/15.4") || /cpu (os|iphone os) 15_4 like mac os x/.test(ua));
29
+ const WEBKIT = ua.includes("webkit") && !ua.includes("edge");
30
+ const MAC = ua.includes("macintosh");
31
+ const DEVICE_PIXEL_RATIO = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
32
+ const WORKER_OFFSCREEN_CANVAS = typeof WorkerGlobalScope !== "undefined" && typeof OffscreenCanvas !== "undefined" && self instanceof WorkerGlobalScope;
33
+ const IMAGE_DECODE = typeof Image !== "undefined" && Image.prototype.decode;
34
+ const PASSIVE_EVENT_LISTENERS = (function() {
35
+ let passive = false;
36
+ try {
37
+ const options = Object.defineProperty({}, "passive", {
38
+ get: function() {
39
+ passive = true;
40
+ }
41
+ });
42
+ window.addEventListener("_", null, options);
43
+ window.removeEventListener("_", null, options);
44
+ } catch (e) {
45
+ }
46
+ return passive;
47
+ })();
48
+ const CLASS_HIDDEN = "ol-hidden";
49
+ const CLASS_SELECTABLE = "ol-selectable";
50
+ const CLASS_UNSELECTABLE = "ol-unselectable";
51
+ const CLASS_CONTROL = "ol-control";
52
+ const CLASS_COLLAPSED = "ol-collapsed";
53
+ const fontRegEx = new RegExp(
54
+ [
55
+ "^\\s*(?=(?:(?:[-a-z]+\\s*){0,2}(italic|oblique))?)",
56
+ "(?=(?:(?:[-a-z]+\\s*){0,2}(small-caps))?)",
57
+ "(?=(?:(?:[-a-z]+\\s*){0,2}(bold(?:er)?|lighter|[1-9]00 ))?)",
58
+ "(?:(?:normal|\\1|\\2|\\3)\\s*){0,3}((?:xx?-)?",
59
+ "(?:small|large)|medium|smaller|larger|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx]))",
60
+ "(?:\\s*\\/\\s*(normal|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx])?))",
61
+ `?\\s*([-,\\"\\'\\sa-z0-9]+?)\\s*$`
62
+ ].join(""),
63
+ "i"
64
+ );
65
+ const fontRegExMatchIndex = [
66
+ "style",
67
+ "variant",
68
+ "weight",
69
+ "size",
70
+ "lineHeight",
71
+ "family"
72
+ ];
73
+ const fontWeights = {
74
+ normal: 400,
75
+ bold: 700
76
+ };
77
+ const getFontParameters = function(fontSpec) {
78
+ const match = fontSpec.match(fontRegEx);
79
+ if (!match) {
80
+ return null;
81
+ }
82
+ const style = (
83
+ /** @type {FontParameters} */
84
+ {
85
+ lineHeight: "normal",
86
+ size: "1.2em",
87
+ style: "normal",
88
+ weight: "400",
89
+ variant: "normal"
90
+ }
91
+ );
92
+ for (let i = 0, ii = fontRegExMatchIndex.length; i < ii; ++i) {
93
+ const value = match[i + 1];
94
+ if (value !== void 0) {
95
+ style[fontRegExMatchIndex[i]] = typeof value === "string" ? value.trim() : value;
96
+ }
97
+ }
98
+ if (isNaN(Number(style.weight)) && style.weight in fontWeights) {
99
+ style.weight = fontWeights[style.weight];
100
+ }
101
+ style.families = style.family.split(/,\s?/).map((f) => f.trim().replace(/^['"]|['"]$/g, ""));
102
+ return style;
103
+ };
104
+ function createCanvasContext2D(width, height, canvasPool, settings) {
105
+ let canvas;
106
+ if (canvasPool && canvasPool.length) {
107
+ canvas = /** @type {HTMLCanvasElement} */
108
+ canvasPool.shift();
109
+ } else if (WORKER_OFFSCREEN_CANVAS) {
110
+ canvas = new class extends OffscreenCanvas {
111
+ constructor() {
112
+ super(...arguments);
113
+ __publicField(this, "style", {});
114
+ }
115
+ }(width != null ? width : 300, height != null ? height : 150);
116
+ } else {
117
+ canvas = document.createElement("canvas");
118
+ }
119
+ if (width) {
120
+ canvas.width = width;
121
+ }
122
+ if (height) {
123
+ canvas.height = height;
124
+ }
125
+ return (
126
+ /** @type {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} */
127
+ canvas.getContext("2d", settings)
128
+ );
129
+ }
130
+ let sharedCanvasContext;
131
+ function getSharedCanvasContext2D() {
132
+ if (!sharedCanvasContext) {
133
+ sharedCanvasContext = createCanvasContext2D(1, 1);
134
+ }
135
+ return sharedCanvasContext;
136
+ }
137
+ function releaseCanvas(context) {
138
+ const canvas = context.canvas;
139
+ canvas.width = 1;
140
+ canvas.height = 1;
141
+ context.clearRect(0, 0, 1, 1);
142
+ }
143
+ function outerWidth(element) {
144
+ let width = element.offsetWidth;
145
+ const style = getComputedStyle(element);
146
+ width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);
147
+ return width;
148
+ }
149
+ function outerHeight(element) {
150
+ let height = element.offsetHeight;
151
+ const style = getComputedStyle(element);
152
+ height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);
153
+ return height;
154
+ }
155
+ function replaceNode(newNode, oldNode) {
156
+ const parent = oldNode.parentNode;
157
+ if (parent) {
158
+ parent.replaceChild(newNode, oldNode);
159
+ }
160
+ }
161
+ function removeChildren(node) {
162
+ while (node.lastChild) {
163
+ node.lastChild.remove();
164
+ }
165
+ }
166
+ function replaceChildren(node, children) {
167
+ const oldChildren = node.childNodes;
168
+ for (let i = 0; true; ++i) {
169
+ const oldChild = oldChildren[i];
170
+ const newChild = children[i];
171
+ if (!oldChild && !newChild) {
172
+ break;
173
+ }
174
+ if (oldChild === newChild) {
175
+ continue;
176
+ }
177
+ if (!oldChild) {
178
+ node.appendChild(newChild);
179
+ continue;
180
+ }
181
+ if (!newChild) {
182
+ node.removeChild(oldChild);
183
+ --i;
184
+ continue;
185
+ }
186
+ node.insertBefore(newChild, oldChild);
187
+ }
188
+ }
189
+ function createMockDiv() {
190
+ const mockedDiv = new Proxy(
191
+ {
192
+ /**
193
+ * @type {Array<HTMLElement>}
194
+ */
195
+ childNodes: [],
196
+ /**
197
+ * @param {HTMLElement} node html node.
198
+ * @return {HTMLElement} html node.
199
+ */
200
+ appendChild: function(node) {
201
+ this.childNodes.push(node);
202
+ return node;
203
+ },
204
+ /**
205
+ * dummy function, as this structure is not supposed to have a parent.
206
+ */
207
+ remove: function() {
208
+ },
209
+ /**
210
+ * @param {HTMLElement} node html node.
211
+ * @return {HTMLElement} html node.
212
+ */
213
+ removeChild: function(node) {
214
+ const index = this.childNodes.indexOf(node);
215
+ if (index === -1) {
216
+ throw new Error("Node to remove was not found");
217
+ }
218
+ this.childNodes.splice(index, 1);
219
+ return node;
220
+ },
221
+ /**
222
+ * @param {HTMLElement} newNode new html node.
223
+ * @param {HTMLElement} referenceNode reference html node.
224
+ * @return {HTMLElement} new html node.
225
+ */
226
+ insertBefore: function(newNode, referenceNode) {
227
+ const index = this.childNodes.indexOf(referenceNode);
228
+ if (index === -1) {
229
+ throw new Error("Reference node not found");
230
+ }
231
+ this.childNodes.splice(index, 0, newNode);
232
+ return newNode;
233
+ },
234
+ style: {}
235
+ },
236
+ {
237
+ get(target, prop, receiver) {
238
+ if (prop === "firstElementChild") {
239
+ return target.childNodes.length > 0 ? target.childNodes[0] : null;
240
+ }
241
+ return Reflect.get(target, prop, receiver);
242
+ }
243
+ }
244
+ );
245
+ return (
246
+ /** @type {HTMLDivElement} */
247
+ /** @type {*} */
248
+ mockedDiv
249
+ );
250
+ }
251
+ function isCanvas(obj) {
252
+ return typeof HTMLCanvasElement !== "undefined" && obj instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && obj instanceof OffscreenCanvas;
253
+ }
254
+ const NO_COLOR = [NaN, NaN, NaN, 0];
255
+ let colorParseContext;
256
+ function getColorParseContext() {
257
+ if (!colorParseContext) {
258
+ colorParseContext = createCanvasContext2D(1, 1, void 0, {
259
+ willReadFrequently: true,
260
+ desynchronized: true
261
+ });
262
+ }
263
+ return colorParseContext;
264
+ }
265
+ const rgbModernRegEx = /^rgba?\(\s*(\d+%?)\s+(\d+%?)\s+(\d+%?)(?:\s*\/\s*(\d+%|\d*\.\d+|[01]))?\s*\)$/i;
266
+ const rgbLegacyAbsoluteRegEx = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*(\d+%|\d*\.\d+|[01]))?\s*\)$/i;
267
+ const rgbLegacyPercentageRegEx = /^rgba?\(\s*(\d+%)\s*,\s*(\d+%)\s*,\s*(\d+%)(?:\s*,\s*(\d+%|\d*\.\d+|[01]))?\s*\)$/i;
268
+ const hexRegEx = /^#([\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/i;
269
+ function toColorComponent(s, divider) {
270
+ return s.endsWith("%") ? Number(s.substring(0, s.length - 1)) / divider : Number(s);
271
+ }
272
+ function throwInvalidColor(color) {
273
+ throw new Error('failed to parse "' + color + '" as color');
274
+ }
275
+ function parseRgba(color) {
276
+ if (color.toLowerCase().startsWith("rgb")) {
277
+ const rgb = color.match(rgbLegacyAbsoluteRegEx) || color.match(rgbModernRegEx) || color.match(rgbLegacyPercentageRegEx);
278
+ if (rgb) {
279
+ const alpha = rgb[4];
280
+ const rgbDivider = 100 / 255;
281
+ return [
282
+ clamp(toColorComponent(rgb[1], rgbDivider) + 0.5 | 0, 0, 255),
283
+ clamp(toColorComponent(rgb[2], rgbDivider) + 0.5 | 0, 0, 255),
284
+ clamp(toColorComponent(rgb[3], rgbDivider) + 0.5 | 0, 0, 255),
285
+ alpha !== void 0 ? clamp(toColorComponent(alpha, 100), 0, 1) : 1
286
+ ];
287
+ }
288
+ throwInvalidColor(color);
289
+ }
290
+ if (color.startsWith("#")) {
291
+ if (hexRegEx.test(color)) {
292
+ const hex = color.substring(1);
293
+ const step = hex.length <= 4 ? 1 : 2;
294
+ const colorFromHex = [0, 0, 0, 255];
295
+ for (let i = 0, ii = hex.length; i < ii; i += step) {
296
+ let colorComponent = parseInt(hex.substring(i, i + step), 16);
297
+ if (step === 1) {
298
+ colorComponent += colorComponent << 4;
299
+ }
300
+ colorFromHex[i / step] = colorComponent;
301
+ }
302
+ colorFromHex[3] = colorFromHex[3] / 255;
303
+ return colorFromHex;
304
+ }
305
+ throwInvalidColor(color);
306
+ }
307
+ const context = getColorParseContext();
308
+ context.fillStyle = "#abcdef";
309
+ let invalidCheckFillStyle = context.fillStyle;
310
+ context.fillStyle = color;
311
+ if (context.fillStyle === invalidCheckFillStyle) {
312
+ context.fillStyle = "#fedcba";
313
+ invalidCheckFillStyle = context.fillStyle;
314
+ context.fillStyle = color;
315
+ if (context.fillStyle === invalidCheckFillStyle) {
316
+ throwInvalidColor(color);
317
+ }
318
+ }
319
+ const colorString = context.fillStyle;
320
+ if (colorString.startsWith("#") || colorString.startsWith("rgba")) {
321
+ return parseRgba(colorString);
322
+ }
323
+ context.clearRect(0, 0, 1, 1);
324
+ context.fillRect(0, 0, 1, 1);
325
+ const colorFromImage = Array.from(context.getImageData(0, 0, 1, 1).data);
326
+ colorFromImage[3] = toFixed(colorFromImage[3] / 255, 3);
327
+ return colorFromImage;
328
+ }
329
+ function asString(color) {
330
+ if (typeof color === "string") {
331
+ return color;
332
+ }
333
+ return toString(color);
334
+ }
335
+ const MAX_CACHE_SIZE = 1024;
336
+ const cache = {};
337
+ let cacheSize = 0;
338
+ function withAlpha(color) {
339
+ if (color.length === 4) {
340
+ return color;
341
+ }
342
+ const output = color.slice();
343
+ output[3] = 1;
344
+ return output;
345
+ }
346
+ function b1(v) {
347
+ return v > 31308e-7 ? Math.pow(v, 1 / 2.4) * 269.025 - 14.025 : v * 3294.6;
348
+ }
349
+ function b2(v) {
350
+ return v > 0.2068965 ? Math.pow(v, 3) : (v - 4 / 29) * (108 / 841);
351
+ }
352
+ function a1(v) {
353
+ return v > 10.314724 ? Math.pow((v + 14.025) / 269.025, 2.4) : v / 3294.6;
354
+ }
355
+ function a2(v) {
356
+ return v > 88564e-7 ? Math.pow(v, 1 / 3) : v / (108 / 841) + 4 / 29;
357
+ }
358
+ function rgbaToLcha(color) {
359
+ const r = a1(color[0]);
360
+ const g = a1(color[1]);
361
+ const b = a1(color[2]);
362
+ const y = a2(r * 0.222488403 + g * 0.716873169 + b * 0.06060791);
363
+ const l = 500 * (a2(r * 0.452247074 + g * 0.399439023 + b * 0.148375274) - y);
364
+ const q = 200 * (y - a2(r * 0.016863605 + g * 0.117638439 + b * 0.865350722));
365
+ const h = Math.atan2(q, l) * (180 / Math.PI);
366
+ return [
367
+ 116 * y - 16,
368
+ Math.sqrt(l * l + q * q),
369
+ h < 0 ? h + 360 : h,
370
+ color[3]
371
+ ];
372
+ }
373
+ function lchaToRgba(color) {
374
+ const l = (color[0] + 16) / 116;
375
+ const c = color[1];
376
+ const h = color[2] * Math.PI / 180;
377
+ const y = b2(l);
378
+ const x = b2(l + c / 500 * Math.cos(h));
379
+ const z = b2(l - c / 200 * Math.sin(h));
380
+ const r = b1(x * 3.021973625 - y * 1.617392459 - z * 0.404875592);
381
+ const g = b1(x * -0.943766287 + y * 1.916279586 + z * 0.027607165);
382
+ const b = b1(x * 0.069407491 - y * 0.22898585 + z * 1.159737864);
383
+ return [
384
+ clamp(r + 0.5 | 0, 0, 255),
385
+ clamp(g + 0.5 | 0, 0, 255),
386
+ clamp(b + 0.5 | 0, 0, 255),
387
+ color[3]
388
+ ];
389
+ }
390
+ function fromString(s) {
391
+ if (s === "none") {
392
+ return NO_COLOR;
393
+ }
394
+ if (cache.hasOwnProperty(s)) {
395
+ return cache[s];
396
+ }
397
+ if (cacheSize >= MAX_CACHE_SIZE) {
398
+ let i = 0;
399
+ for (const key in cache) {
400
+ if ((i++ & 3) === 0) {
401
+ delete cache[key];
402
+ --cacheSize;
403
+ }
404
+ }
405
+ }
406
+ const color = parseRgba(s);
407
+ if (color.length !== 4) {
408
+ throwInvalidColor(s);
409
+ }
410
+ for (const c of color) {
411
+ if (isNaN(c)) {
412
+ throwInvalidColor(s);
413
+ }
414
+ }
415
+ cache[s] = color;
416
+ ++cacheSize;
417
+ return color;
418
+ }
419
+ function asArray(color) {
420
+ if (Array.isArray(color)) {
421
+ return color;
422
+ }
423
+ return fromString(color);
424
+ }
425
+ function toString(color) {
426
+ let r = color[0];
427
+ if (r != (r | 0)) {
428
+ r = r + 0.5 | 0;
429
+ }
430
+ let g = color[1];
431
+ if (g != (g | 0)) {
432
+ g = g + 0.5 | 0;
433
+ }
434
+ let b = color[2];
435
+ if (b != (b | 0)) {
436
+ b = b + 0.5 | 0;
437
+ }
438
+ const a = color[3] === void 0 ? 1 : Math.round(color[3] * 1e3) / 1e3;
439
+ return "rgba(" + r + "," + g + "," + b + "," + a + ")";
440
+ }
441
+ function hasArea(size) {
442
+ return size[0] > 0 && size[1] > 0;
443
+ }
444
+ function scale(size, ratio, dest) {
445
+ if (dest === void 0) {
446
+ dest = [0, 0];
447
+ }
448
+ dest[0] = size[0] * ratio + 0.5 | 0;
449
+ dest[1] = size[1] * ratio + 0.5 | 0;
450
+ return dest;
451
+ }
452
+ function toSize(size, dest) {
453
+ if (Array.isArray(size)) {
454
+ return size;
455
+ }
456
+ if (dest === void 0) {
457
+ dest = [size, size];
458
+ } else {
459
+ dest[0] = size;
460
+ dest[1] = size;
461
+ }
462
+ return dest;
463
+ }
464
+ const ImageState = {
465
+ IDLE: 0,
466
+ LOADING: 1,
467
+ LOADED: 2,
468
+ ERROR: 3
469
+ };
470
+ function listenImage(image, loadHandler, errorHandler) {
471
+ const img = (
472
+ /** @type {HTMLImageElement} */
473
+ image
474
+ );
475
+ let listening = true;
476
+ let decoding = false;
477
+ let loaded = false;
478
+ const listenerKeys = [
479
+ listenOnce(img, EventType.LOAD, function() {
480
+ loaded = true;
481
+ if (!decoding) {
482
+ loadHandler();
483
+ }
484
+ })
485
+ ];
486
+ if (img.src && IMAGE_DECODE) {
487
+ decoding = true;
488
+ img.decode().then(function() {
489
+ if (listening) {
490
+ loadHandler();
491
+ }
492
+ }).catch(function(error) {
493
+ if (listening) {
494
+ if (loaded) {
495
+ loadHandler();
496
+ } else {
497
+ errorHandler();
498
+ }
499
+ }
500
+ });
501
+ } else {
502
+ listenerKeys.push(listenOnce(img, EventType.ERROR, errorHandler));
503
+ }
504
+ return function unlisten() {
505
+ listening = false;
506
+ listenerKeys.forEach(unlistenByKey);
507
+ };
508
+ }
509
+ function load(image, src) {
510
+ return new Promise((resolve, reject) => {
511
+ function handleLoad() {
512
+ unlisten();
513
+ resolve(image);
514
+ }
515
+ function handleError() {
516
+ unlisten();
517
+ reject(new Error("Image load error"));
518
+ }
519
+ function unlisten() {
520
+ image.removeEventListener("load", handleLoad);
521
+ image.removeEventListener("error", handleError);
522
+ }
523
+ image.addEventListener("load", handleLoad);
524
+ image.addEventListener("error", handleError);
525
+ });
526
+ }
527
+ function decodeFallback(image, src) {
528
+ if (src) {
529
+ image.src = src;
530
+ }
531
+ return image.src && IMAGE_DECODE ? new Promise(
532
+ (resolve, reject) => image.decode().then(() => resolve(image)).catch(
533
+ (e) => image.complete && image.width ? resolve(image) : reject(e)
534
+ )
535
+ ) : load(image);
536
+ }
537
+ class IconImageCache {
538
+ constructor() {
539
+ this.cache_ = {};
540
+ this.patternCache_ = {};
541
+ this.cacheSize_ = 0;
542
+ this.maxCacheSize_ = 1024;
543
+ }
544
+ /**
545
+ * FIXME empty description for jsdoc
546
+ */
547
+ clear() {
548
+ this.cache_ = {};
549
+ this.patternCache_ = {};
550
+ this.cacheSize_ = 0;
551
+ }
552
+ /**
553
+ * @return {boolean} Can expire cache.
554
+ */
555
+ canExpireCache() {
556
+ return this.cacheSize_ > this.maxCacheSize_;
557
+ }
558
+ /**
559
+ * FIXME empty description for jsdoc
560
+ */
561
+ expire() {
562
+ if (this.canExpireCache()) {
563
+ let i = 0;
564
+ for (const key in this.cache_) {
565
+ const iconImage = this.cache_[key];
566
+ if ((i++ & 3) === 0 && !iconImage.hasListener()) {
567
+ delete this.cache_[key];
568
+ delete this.patternCache_[key];
569
+ --this.cacheSize_;
570
+ }
571
+ }
572
+ }
573
+ }
574
+ /**
575
+ * @param {string} src Src.
576
+ * @param {?string} crossOrigin Cross origin.
577
+ * @param {import("../color.js").Color|string|null} color Color.
578
+ * @return {import("./IconImage.js").default} Icon image.
579
+ */
580
+ get(src, crossOrigin, color) {
581
+ const key = getCacheKey(src, crossOrigin, color);
582
+ return key in this.cache_ ? this.cache_[key] : null;
583
+ }
584
+ /**
585
+ * @param {string} src Src.
586
+ * @param {?string} crossOrigin Cross origin.
587
+ * @param {import("../color.js").Color|string|null} color Color.
588
+ * @return {CanvasPattern} Icon image.
589
+ */
590
+ getPattern(src, crossOrigin, color) {
591
+ const key = getCacheKey(src, crossOrigin, color);
592
+ return key in this.patternCache_ ? this.patternCache_[key] : null;
593
+ }
594
+ /**
595
+ * @param {string} src Src.
596
+ * @param {?string} crossOrigin Cross origin.
597
+ * @param {import("../color.js").Color|string|null} color Color.
598
+ * @param {import("./IconImage.js").default|null} iconImage Icon image.
599
+ * @param {boolean} [pattern] Also cache a `'repeat'` pattern with this `iconImage`.
600
+ */
601
+ set(src, crossOrigin, color, iconImage, pattern) {
602
+ const key = getCacheKey(src, crossOrigin, color);
603
+ const update = key in this.cache_;
604
+ this.cache_[key] = iconImage;
605
+ if (pattern) {
606
+ if (iconImage.getImageState() === ImageState.IDLE) {
607
+ iconImage.load();
608
+ }
609
+ if (iconImage.getImageState() === ImageState.LOADING) {
610
+ iconImage.ready().then(() => {
611
+ this.patternCache_[key] = getSharedCanvasContext2D().createPattern(
612
+ iconImage.getImage(1),
613
+ "repeat"
614
+ );
615
+ });
616
+ } else {
617
+ this.patternCache_[key] = getSharedCanvasContext2D().createPattern(
618
+ iconImage.getImage(1),
619
+ "repeat"
620
+ );
621
+ }
622
+ }
623
+ if (!update) {
624
+ ++this.cacheSize_;
625
+ }
626
+ }
627
+ /**
628
+ * Set the cache size of the icon cache. Default is `1024`. Change this value when
629
+ * your map uses more than 1024 different icon images and you are not caching icon
630
+ * styles on the application level.
631
+ * @param {number} maxCacheSize Cache max size.
632
+ * @api
633
+ */
634
+ setSize(maxCacheSize) {
635
+ this.maxCacheSize_ = maxCacheSize;
636
+ this.expire();
637
+ }
638
+ }
639
+ function getCacheKey(src, crossOrigin, color) {
640
+ const colorString = color ? asArray(color) : "null";
641
+ return crossOrigin + ":" + src + ":" + colorString;
642
+ }
643
+ const shared = new IconImageCache();
644
+ let taintedTestContext = null;
645
+ class IconImage extends Target {
646
+ /**
647
+ * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap|null} image Image.
648
+ * @param {string|undefined} src Src.
649
+ * @param {?string} crossOrigin Cross origin.
650
+ * @param {import("../ImageState.js").default|undefined} imageState Image state.
651
+ * @param {import("../color.js").Color|string|null} color Color.
652
+ */
653
+ constructor(image, src, crossOrigin, imageState, color) {
654
+ super();
655
+ this.hitDetectionImage_ = null;
656
+ this.image_ = image;
657
+ this.crossOrigin_ = crossOrigin;
658
+ this.canvas_ = {};
659
+ this.color_ = color;
660
+ this.imageState_ = imageState === void 0 ? ImageState.IDLE : imageState;
661
+ this.size_ = image && image.width && image.height ? [image.width, image.height] : null;
662
+ this.src_ = src;
663
+ this.tainted_;
664
+ this.ready_ = null;
665
+ }
666
+ /**
667
+ * @private
668
+ */
669
+ initializeImage_() {
670
+ this.image_ = new Image();
671
+ if (this.crossOrigin_ !== null) {
672
+ this.image_.crossOrigin = this.crossOrigin_;
673
+ }
674
+ }
675
+ /**
676
+ * @private
677
+ * @return {boolean} The image canvas is tainted.
678
+ */
679
+ isTainted_() {
680
+ if (this.tainted_ === void 0 && this.imageState_ === ImageState.LOADED) {
681
+ if (!taintedTestContext) {
682
+ taintedTestContext = createCanvasContext2D(1, 1, void 0, {
683
+ willReadFrequently: true
684
+ });
685
+ }
686
+ taintedTestContext.drawImage(this.image_, 0, 0);
687
+ try {
688
+ taintedTestContext.getImageData(0, 0, 1, 1);
689
+ this.tainted_ = false;
690
+ } catch (e) {
691
+ taintedTestContext = null;
692
+ this.tainted_ = true;
693
+ }
694
+ }
695
+ return this.tainted_ === true;
696
+ }
697
+ /**
698
+ * @private
699
+ */
700
+ dispatchChangeEvent_() {
701
+ this.dispatchEvent(EventType.CHANGE);
702
+ }
703
+ /**
704
+ * @private
705
+ */
706
+ handleImageError_() {
707
+ this.imageState_ = ImageState.ERROR;
708
+ this.dispatchChangeEvent_();
709
+ }
710
+ /**
711
+ * @private
712
+ */
713
+ handleImageLoad_() {
714
+ this.imageState_ = ImageState.LOADED;
715
+ this.size_ = [this.image_.width, this.image_.height];
716
+ this.dispatchChangeEvent_();
717
+ }
718
+ /**
719
+ * @param {number} pixelRatio Pixel ratio.
720
+ * @return {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap} Image or Canvas element or image bitmap.
721
+ */
722
+ getImage(pixelRatio) {
723
+ if (!this.image_) {
724
+ this.initializeImage_();
725
+ }
726
+ this.replaceColor_(pixelRatio);
727
+ return this.canvas_[pixelRatio] ? this.canvas_[pixelRatio] : this.image_;
728
+ }
729
+ /**
730
+ * @param {number} pixelRatio Pixel ratio.
731
+ * @return {number} Image or Canvas element.
732
+ */
733
+ getPixelRatio(pixelRatio) {
734
+ this.replaceColor_(pixelRatio);
735
+ return this.canvas_[pixelRatio] ? pixelRatio : 1;
736
+ }
737
+ /**
738
+ * @return {import("../ImageState.js").default} Image state.
739
+ */
740
+ getImageState() {
741
+ return this.imageState_;
742
+ }
743
+ /**
744
+ * @return {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap} Image element.
745
+ */
746
+ getHitDetectionImage() {
747
+ if (!this.image_) {
748
+ this.initializeImage_();
749
+ }
750
+ if (!this.hitDetectionImage_) {
751
+ if (this.isTainted_()) {
752
+ const width = this.size_[0];
753
+ const height = this.size_[1];
754
+ const context = createCanvasContext2D(width, height);
755
+ context.fillRect(0, 0, width, height);
756
+ this.hitDetectionImage_ = context.canvas;
757
+ } else {
758
+ this.hitDetectionImage_ = this.image_;
759
+ }
760
+ }
761
+ return this.hitDetectionImage_;
762
+ }
763
+ /**
764
+ * Get the size of the icon (in pixels).
765
+ * @return {import("../size.js").Size} Image size.
766
+ */
767
+ getSize() {
768
+ return this.size_;
769
+ }
770
+ /**
771
+ * @return {string|undefined} Image src.
772
+ */
773
+ getSrc() {
774
+ return this.src_;
775
+ }
776
+ /**
777
+ * Load not yet loaded URI.
778
+ */
779
+ load() {
780
+ if (this.imageState_ !== ImageState.IDLE) {
781
+ return;
782
+ }
783
+ if (!this.image_) {
784
+ this.initializeImage_();
785
+ }
786
+ this.imageState_ = ImageState.LOADING;
787
+ try {
788
+ if (this.src_ !== void 0) {
789
+ this.image_.src = this.src_;
790
+ }
791
+ } catch (e) {
792
+ this.handleImageError_();
793
+ }
794
+ if (this.image_ instanceof HTMLImageElement) {
795
+ decodeFallback(this.image_, this.src_).then((image) => {
796
+ this.image_ = image;
797
+ this.handleImageLoad_();
798
+ }).catch(this.handleImageError_.bind(this));
799
+ }
800
+ }
801
+ /**
802
+ * @param {number} pixelRatio Pixel ratio.
803
+ * @private
804
+ */
805
+ replaceColor_(pixelRatio) {
806
+ if (!this.color_ || this.canvas_[pixelRatio] || this.imageState_ !== ImageState.LOADED) {
807
+ return;
808
+ }
809
+ const image = this.image_;
810
+ const ctx = createCanvasContext2D(
811
+ Math.ceil(image.width * pixelRatio),
812
+ Math.ceil(image.height * pixelRatio)
813
+ );
814
+ const canvas = ctx.canvas;
815
+ ctx.scale(pixelRatio, pixelRatio);
816
+ ctx.drawImage(image, 0, 0);
817
+ ctx.globalCompositeOperation = "multiply";
818
+ ctx.fillStyle = asString(this.color_);
819
+ ctx.fillRect(0, 0, canvas.width / pixelRatio, canvas.height / pixelRatio);
820
+ ctx.globalCompositeOperation = "destination-in";
821
+ ctx.drawImage(image, 0, 0);
822
+ this.canvas_[pixelRatio] = canvas;
823
+ }
824
+ /**
825
+ * @return {Promise<void>} Promise that resolves when the image is loaded.
826
+ */
827
+ ready() {
828
+ if (!this.ready_) {
829
+ this.ready_ = new Promise((resolve) => {
830
+ if (this.imageState_ === ImageState.LOADED || this.imageState_ === ImageState.ERROR) {
831
+ resolve();
832
+ } else {
833
+ const onChange = () => {
834
+ if (this.imageState_ === ImageState.LOADED || this.imageState_ === ImageState.ERROR) {
835
+ this.removeEventListener(EventType.CHANGE, onChange);
836
+ resolve();
837
+ }
838
+ };
839
+ this.addEventListener(EventType.CHANGE, onChange);
840
+ }
841
+ });
842
+ }
843
+ return this.ready_;
844
+ }
845
+ }
846
+ function get(image, cacheKey, crossOrigin, imageState, color, pattern) {
847
+ let iconImage = cacheKey === void 0 ? void 0 : shared.get(cacheKey, crossOrigin, color);
848
+ if (!iconImage) {
849
+ iconImage = new IconImage(
850
+ image,
851
+ image && "src" in image ? image.src || void 0 : cacheKey,
852
+ crossOrigin,
853
+ imageState,
854
+ color
855
+ );
856
+ shared.set(cacheKey, crossOrigin, color, iconImage, pattern);
857
+ }
858
+ if (pattern && iconImage && !shared.getPattern(cacheKey, crossOrigin, color)) {
859
+ shared.set(cacheKey, crossOrigin, color, iconImage, pattern);
860
+ }
861
+ return iconImage;
862
+ }
863
+ function asColorLike(color) {
864
+ if (!color) {
865
+ return null;
866
+ }
867
+ if (Array.isArray(color)) {
868
+ return toString(color);
869
+ }
870
+ if (typeof color === "object" && "src" in color) {
871
+ return asCanvasPattern(color);
872
+ }
873
+ return color;
874
+ }
875
+ function asCanvasPattern(pattern) {
876
+ if (!pattern.offset || !pattern.size) {
877
+ return shared.getPattern(pattern.src, "anonymous", pattern.color);
878
+ }
879
+ const cacheKey = pattern.src + ":" + pattern.offset;
880
+ const canvasPattern = shared.getPattern(
881
+ cacheKey,
882
+ void 0,
883
+ pattern.color
884
+ );
885
+ if (canvasPattern) {
886
+ return canvasPattern;
887
+ }
888
+ const iconImage = shared.get(pattern.src, "anonymous", null);
889
+ if (iconImage.getImageState() !== ImageState.LOADED) {
890
+ return null;
891
+ }
892
+ const patternCanvasContext = createCanvasContext2D(
893
+ pattern.size[0],
894
+ pattern.size[1]
895
+ );
896
+ patternCanvasContext.drawImage(
897
+ iconImage.getImage(1),
898
+ pattern.offset[0],
899
+ pattern.offset[1],
900
+ pattern.size[0],
901
+ pattern.size[1],
902
+ 0,
903
+ 0,
904
+ pattern.size[0],
905
+ pattern.size[1]
906
+ );
907
+ get(
908
+ patternCanvasContext.canvas,
909
+ cacheKey,
910
+ void 0,
911
+ ImageState.LOADED,
912
+ pattern.color,
913
+ true
914
+ );
915
+ return shared.getPattern(cacheKey, void 0, pattern.color);
916
+ }
917
+ const defaultFont = "10px sans-serif";
918
+ const defaultFillStyle = "#000";
919
+ const defaultLineCap = "round";
920
+ const defaultLineDash = [];
921
+ const defaultLineDashOffset = 0;
922
+ const defaultLineJoin = "round";
923
+ const defaultMiterLimit = 10;
924
+ const defaultStrokeStyle = "#000";
925
+ const defaultTextAlign = "center";
926
+ const defaultTextBaseline = "middle";
927
+ const defaultPadding = [0, 0, 0, 0];
928
+ const defaultLineWidth = 1;
929
+ const checkedFonts = new BaseObject();
930
+ let measureContext = null;
931
+ let measureFont;
932
+ const textHeights = {};
933
+ const genericFontFamilies = /* @__PURE__ */ new Set([
934
+ "serif",
935
+ "sans-serif",
936
+ "monospace",
937
+ "cursive",
938
+ "fantasy",
939
+ "system-ui",
940
+ "ui-serif",
941
+ "ui-sans-serif",
942
+ "ui-monospace",
943
+ "ui-rounded",
944
+ "emoji",
945
+ "math",
946
+ "fangsong"
947
+ ]);
948
+ function getFontKey(style, weight, family) {
949
+ return `${style} ${weight} 16px "${family}"`;
950
+ }
951
+ const registerFont = /* @__PURE__ */ (function() {
952
+ const retries = 100;
953
+ let timeout, fontFaceSet;
954
+ function isAvailable(fontSpec) {
955
+ return __async(this, null, function* () {
956
+ yield fontFaceSet.ready;
957
+ const fontFaces = yield fontFaceSet.load(fontSpec);
958
+ if (fontFaces.length === 0) {
959
+ return false;
960
+ }
961
+ const font = getFontParameters(fontSpec);
962
+ const checkFamily = font.families[0].toLowerCase();
963
+ const checkWeight = font.weight;
964
+ return fontFaces.some(
965
+ /**
966
+ * @param {import('../css.js').FontParameters} f Font.
967
+ * @return {boolean} Font matches.
968
+ */
969
+ (f) => {
970
+ const family = f.family.replace(/^['"]|['"]$/g, "").toLowerCase();
971
+ const weight = fontWeights[f.weight] || f.weight;
972
+ return family === checkFamily && f.style === font.style && weight == checkWeight;
973
+ }
974
+ );
975
+ });
976
+ }
977
+ function check() {
978
+ return __async(this, null, function* () {
979
+ yield fontFaceSet.ready;
980
+ let done = true;
981
+ const checkedFontsProperties = checkedFonts.getProperties();
982
+ const fonts = Object.keys(checkedFontsProperties).filter(
983
+ (key) => checkedFontsProperties[key] < retries
984
+ );
985
+ for (let i = fonts.length - 1; i >= 0; --i) {
986
+ const font = fonts[i];
987
+ let currentRetries = checkedFontsProperties[font];
988
+ if (currentRetries < retries) {
989
+ if (yield isAvailable(font)) {
990
+ clear(textHeights);
991
+ checkedFonts.set(font, retries);
992
+ } else {
993
+ currentRetries += 10;
994
+ checkedFonts.set(font, currentRetries, true);
995
+ if (currentRetries < retries) {
996
+ done = false;
997
+ }
998
+ }
999
+ }
1000
+ }
1001
+ timeout = void 0;
1002
+ if (!done) {
1003
+ timeout = setTimeout(check, 100);
1004
+ }
1005
+ });
1006
+ }
1007
+ return function(fontSpec) {
1008
+ return __async(this, null, function* () {
1009
+ if (!fontFaceSet) {
1010
+ fontFaceSet = WORKER_OFFSCREEN_CANVAS ? self.fonts : document.fonts;
1011
+ }
1012
+ const font = getFontParameters(fontSpec);
1013
+ if (!font) {
1014
+ return;
1015
+ }
1016
+ const families = font.families;
1017
+ let needCheck = false;
1018
+ for (const family of families) {
1019
+ if (genericFontFamilies.has(family)) {
1020
+ continue;
1021
+ }
1022
+ const key = getFontKey(font.style, font.weight, family);
1023
+ if (checkedFonts.get(key) !== void 0) {
1024
+ continue;
1025
+ }
1026
+ checkedFonts.set(key, 0, true);
1027
+ needCheck = true;
1028
+ }
1029
+ if (needCheck) {
1030
+ clearTimeout(timeout);
1031
+ timeout = setTimeout(check, 100);
1032
+ }
1033
+ });
1034
+ };
1035
+ })();
1036
+ const measureTextHeight = /* @__PURE__ */ (function() {
1037
+ let measureElement;
1038
+ return function(fontSpec) {
1039
+ let height = textHeights[fontSpec];
1040
+ if (height == void 0) {
1041
+ if (WORKER_OFFSCREEN_CANVAS) {
1042
+ const font = getFontParameters(fontSpec);
1043
+ const metrics = measureText(fontSpec, "Žg");
1044
+ const lineHeight = isNaN(Number(font.lineHeight)) ? 1.2 : Number(font.lineHeight);
1045
+ height = lineHeight * (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent);
1046
+ } else {
1047
+ if (!measureElement) {
1048
+ measureElement = document.createElement("div");
1049
+ measureElement.innerHTML = "M";
1050
+ measureElement.style.minHeight = "0";
1051
+ measureElement.style.maxHeight = "none";
1052
+ measureElement.style.height = "auto";
1053
+ measureElement.style.padding = "0";
1054
+ measureElement.style.border = "none";
1055
+ measureElement.style.position = "absolute";
1056
+ measureElement.style.display = "block";
1057
+ measureElement.style.left = "-99999px";
1058
+ }
1059
+ measureElement.style.font = fontSpec;
1060
+ document.body.appendChild(measureElement);
1061
+ height = measureElement.offsetHeight;
1062
+ document.body.removeChild(measureElement);
1063
+ }
1064
+ textHeights[fontSpec] = height;
1065
+ }
1066
+ return height;
1067
+ };
1068
+ })();
1069
+ function measureText(font, text) {
1070
+ if (!measureContext) {
1071
+ measureContext = createCanvasContext2D(1, 1);
1072
+ }
1073
+ if (font != measureFont) {
1074
+ measureContext.font = font;
1075
+ measureFont = measureContext.font;
1076
+ }
1077
+ return measureContext.measureText(text);
1078
+ }
1079
+ function measureTextWidth(font, text) {
1080
+ return measureText(font, text).width;
1081
+ }
1082
+ function measureAndCacheTextWidth(font, text, cache2) {
1083
+ if (text in cache2) {
1084
+ return cache2[text];
1085
+ }
1086
+ const width = text.split("\n").reduce((prev, curr) => Math.max(prev, measureTextWidth(font, curr)), 0);
1087
+ cache2[text] = width;
1088
+ return width;
1089
+ }
1090
+ function getTextDimensions(baseStyle, chunks) {
1091
+ const widths = [];
1092
+ const heights = [];
1093
+ const lineWidths = [];
1094
+ let width = 0;
1095
+ let lineWidth = 0;
1096
+ let height = 0;
1097
+ let lineHeight = 0;
1098
+ for (let i = 0, ii = chunks.length; i <= ii; i += 2) {
1099
+ const text = chunks[i];
1100
+ if (text === "\n" || i === ii) {
1101
+ width = Math.max(width, lineWidth);
1102
+ lineWidths.push(lineWidth);
1103
+ lineWidth = 0;
1104
+ height += lineHeight;
1105
+ lineHeight = 0;
1106
+ continue;
1107
+ }
1108
+ const font = chunks[i + 1] || baseStyle.font;
1109
+ const currentWidth = measureTextWidth(font, text);
1110
+ widths.push(currentWidth);
1111
+ lineWidth += currentWidth;
1112
+ const currentHeight = measureTextHeight(font);
1113
+ heights.push(currentHeight);
1114
+ lineHeight = Math.max(lineHeight, currentHeight);
1115
+ }
1116
+ return { width, height, widths, heights, lineWidths };
1117
+ }
1118
+ function drawImageOrLabel(context, transform, opacity, labelOrImage, originX, originY, w, h, x, y, scale2) {
1119
+ context.save();
1120
+ if (opacity !== 1) {
1121
+ if (context.globalAlpha === void 0) {
1122
+ context.globalAlpha = (context2) => context2.globalAlpha *= opacity;
1123
+ } else {
1124
+ context.globalAlpha *= opacity;
1125
+ }
1126
+ }
1127
+ if (transform) {
1128
+ context.transform.apply(context, transform);
1129
+ }
1130
+ if (
1131
+ /** @type {*} */
1132
+ labelOrImage.contextInstructions
1133
+ ) {
1134
+ context.translate(x, y);
1135
+ context.scale(scale2[0], scale2[1]);
1136
+ executeLabelInstructions(
1137
+ /** @type {Label} */
1138
+ labelOrImage,
1139
+ context
1140
+ );
1141
+ } else if (scale2[0] < 0 || scale2[1] < 0) {
1142
+ context.translate(x, y);
1143
+ context.scale(scale2[0], scale2[1]);
1144
+ context.drawImage(
1145
+ /** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */
1146
+ labelOrImage,
1147
+ originX,
1148
+ originY,
1149
+ w,
1150
+ h,
1151
+ 0,
1152
+ 0,
1153
+ w,
1154
+ h
1155
+ );
1156
+ } else {
1157
+ context.drawImage(
1158
+ /** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */
1159
+ labelOrImage,
1160
+ originX,
1161
+ originY,
1162
+ w,
1163
+ h,
1164
+ x,
1165
+ y,
1166
+ w * scale2[0],
1167
+ h * scale2[1]
1168
+ );
1169
+ }
1170
+ context.restore();
1171
+ }
1172
+ function executeLabelInstructions(label, context) {
1173
+ const contextInstructions = label.contextInstructions;
1174
+ for (let i = 0, ii = contextInstructions.length; i < ii; i += 2) {
1175
+ if (Array.isArray(contextInstructions[i + 1])) {
1176
+ context[contextInstructions[i]].apply(
1177
+ context,
1178
+ contextInstructions[i + 1]
1179
+ );
1180
+ } else {
1181
+ context[contextInstructions[i]] = contextInstructions[i + 1];
1182
+ }
1183
+ }
1184
+ }
1185
+ class ImageStyle {
1186
+ /**
1187
+ * @param {Options} options Options.
1188
+ */
1189
+ constructor(options) {
1190
+ this.opacity_ = options.opacity;
1191
+ this.rotateWithView_ = options.rotateWithView;
1192
+ this.rotation_ = options.rotation;
1193
+ this.scale_ = options.scale;
1194
+ this.scaleArray_ = toSize(options.scale);
1195
+ this.displacement_ = options.displacement;
1196
+ this.declutterMode_ = options.declutterMode;
1197
+ }
1198
+ /**
1199
+ * Clones the style.
1200
+ * @return {ImageStyle} The cloned style.
1201
+ * @api
1202
+ */
1203
+ clone() {
1204
+ const scale2 = this.getScale();
1205
+ return new ImageStyle({
1206
+ opacity: this.getOpacity(),
1207
+ scale: Array.isArray(scale2) ? scale2.slice() : scale2,
1208
+ rotation: this.getRotation(),
1209
+ rotateWithView: this.getRotateWithView(),
1210
+ displacement: this.getDisplacement().slice(),
1211
+ declutterMode: this.getDeclutterMode()
1212
+ });
1213
+ }
1214
+ /**
1215
+ * Get the symbolizer opacity.
1216
+ * @return {number} Opacity.
1217
+ * @api
1218
+ */
1219
+ getOpacity() {
1220
+ return this.opacity_;
1221
+ }
1222
+ /**
1223
+ * Determine whether the symbolizer rotates with the map.
1224
+ * @return {boolean} Rotate with map.
1225
+ * @api
1226
+ */
1227
+ getRotateWithView() {
1228
+ return this.rotateWithView_;
1229
+ }
1230
+ /**
1231
+ * Get the symoblizer rotation.
1232
+ * @return {number} Rotation.
1233
+ * @api
1234
+ */
1235
+ getRotation() {
1236
+ return this.rotation_;
1237
+ }
1238
+ /**
1239
+ * Get the symbolizer scale.
1240
+ * @return {number|import("../size.js").Size} Scale.
1241
+ * @api
1242
+ */
1243
+ getScale() {
1244
+ return this.scale_;
1245
+ }
1246
+ /**
1247
+ * Get the symbolizer scale array.
1248
+ * @return {import("../size.js").Size} Scale array.
1249
+ */
1250
+ getScaleArray() {
1251
+ return this.scaleArray_;
1252
+ }
1253
+ /**
1254
+ * Get the displacement of the shape
1255
+ * @return {Array<number>} Shape's center displacement
1256
+ * @api
1257
+ */
1258
+ getDisplacement() {
1259
+ return this.displacement_;
1260
+ }
1261
+ /**
1262
+ * Get the declutter mode of the shape
1263
+ * @return {import("./Style.js").DeclutterMode} Shape's declutter mode
1264
+ * @api
1265
+ */
1266
+ getDeclutterMode() {
1267
+ return this.declutterMode_;
1268
+ }
1269
+ /**
1270
+ * Get the anchor point in pixels. The anchor determines the center point for the
1271
+ * symbolizer.
1272
+ * @abstract
1273
+ * @return {Array<number>} Anchor.
1274
+ */
1275
+ getAnchor() {
1276
+ return abstract();
1277
+ }
1278
+ /**
1279
+ * Get the image element for the symbolizer.
1280
+ * @abstract
1281
+ * @param {number} pixelRatio Pixel ratio.
1282
+ * @return {import('../DataTile.js').ImageLike} Image element.
1283
+ */
1284
+ getImage(pixelRatio) {
1285
+ return abstract();
1286
+ }
1287
+ /**
1288
+ * @abstract
1289
+ * @return {import('../DataTile.js').ImageLike} Image element.
1290
+ */
1291
+ getHitDetectionImage() {
1292
+ return abstract();
1293
+ }
1294
+ /**
1295
+ * Get the image pixel ratio.
1296
+ * @param {number} pixelRatio Pixel ratio.
1297
+ * @return {number} Pixel ratio.
1298
+ */
1299
+ getPixelRatio(pixelRatio) {
1300
+ return 1;
1301
+ }
1302
+ /**
1303
+ * @abstract
1304
+ * @return {import("../ImageState.js").default} Image state.
1305
+ */
1306
+ getImageState() {
1307
+ return abstract();
1308
+ }
1309
+ /**
1310
+ * @abstract
1311
+ * @return {import("../size.js").Size} Image size.
1312
+ */
1313
+ getImageSize() {
1314
+ return abstract();
1315
+ }
1316
+ /**
1317
+ * Get the origin of the symbolizer.
1318
+ * @abstract
1319
+ * @return {Array<number>} Origin.
1320
+ */
1321
+ getOrigin() {
1322
+ return abstract();
1323
+ }
1324
+ /**
1325
+ * Get the size of the symbolizer (in pixels).
1326
+ * @abstract
1327
+ * @return {import("../size.js").Size} Size.
1328
+ */
1329
+ getSize() {
1330
+ return abstract();
1331
+ }
1332
+ /**
1333
+ * Set the displacement.
1334
+ *
1335
+ * @param {Array<number>} displacement Displacement.
1336
+ * @api
1337
+ */
1338
+ setDisplacement(displacement) {
1339
+ this.displacement_ = displacement;
1340
+ }
1341
+ /**
1342
+ * Set the opacity.
1343
+ *
1344
+ * @param {number} opacity Opacity.
1345
+ * @api
1346
+ */
1347
+ setOpacity(opacity) {
1348
+ this.opacity_ = opacity;
1349
+ }
1350
+ /**
1351
+ * Set whether to rotate the style with the view.
1352
+ *
1353
+ * @param {boolean} rotateWithView Rotate with map.
1354
+ * @api
1355
+ */
1356
+ setRotateWithView(rotateWithView) {
1357
+ this.rotateWithView_ = rotateWithView;
1358
+ }
1359
+ /**
1360
+ * Set the rotation.
1361
+ *
1362
+ * @param {number} rotation Rotation.
1363
+ * @api
1364
+ */
1365
+ setRotation(rotation) {
1366
+ this.rotation_ = rotation;
1367
+ }
1368
+ /**
1369
+ * Set the scale.
1370
+ *
1371
+ * @param {number|import("../size.js").Size} scale Scale.
1372
+ * @api
1373
+ */
1374
+ setScale(scale2) {
1375
+ this.scale_ = scale2;
1376
+ this.scaleArray_ = toSize(scale2);
1377
+ }
1378
+ /**
1379
+ * @abstract
1380
+ * @param {function(import("../events/Event.js").default): void} listener Listener function.
1381
+ */
1382
+ listenImageChange(listener) {
1383
+ abstract();
1384
+ }
1385
+ /**
1386
+ * Load not yet loaded URI.
1387
+ * @abstract
1388
+ */
1389
+ load() {
1390
+ abstract();
1391
+ }
1392
+ /**
1393
+ * @abstract
1394
+ * @param {function(import("../events/Event.js").default): void} listener Listener function.
1395
+ */
1396
+ unlistenImageChange(listener) {
1397
+ abstract();
1398
+ }
1399
+ /**
1400
+ * @return {Promise<void>} `false` or Promise that resolves when the style is ready to use.
1401
+ */
1402
+ ready() {
1403
+ return Promise.resolve();
1404
+ }
1405
+ }
1406
+ class RegularShape extends ImageStyle {
1407
+ /**
1408
+ * @param {Options} options Options.
1409
+ */
1410
+ constructor(options) {
1411
+ super({
1412
+ opacity: 1,
1413
+ rotateWithView: options.rotateWithView !== void 0 ? options.rotateWithView : false,
1414
+ rotation: options.rotation !== void 0 ? options.rotation : 0,
1415
+ scale: options.scale !== void 0 ? options.scale : 1,
1416
+ displacement: options.displacement !== void 0 ? options.displacement : [0, 0],
1417
+ declutterMode: options.declutterMode
1418
+ });
1419
+ this.hitDetectionCanvas_ = null;
1420
+ this.fill_ = options.fill !== void 0 ? options.fill : null;
1421
+ this.origin_ = [0, 0];
1422
+ this.points_ = options.points;
1423
+ this.radius = options.radius;
1424
+ this.radius2_ = options.radius2;
1425
+ this.angle_ = options.angle !== void 0 ? options.angle : 0;
1426
+ this.stroke_ = options.stroke !== void 0 ? options.stroke : null;
1427
+ this.size_;
1428
+ this.renderOptions_;
1429
+ this.imageState_ = this.fill_ && this.fill_.loading() ? ImageState.LOADING : ImageState.LOADED;
1430
+ if (this.imageState_ === ImageState.LOADING) {
1431
+ this.ready().then(() => this.imageState_ = ImageState.LOADED);
1432
+ }
1433
+ this.render();
1434
+ }
1435
+ /**
1436
+ * Clones the style.
1437
+ * @return {RegularShape} The cloned style.
1438
+ * @api
1439
+ * @override
1440
+ */
1441
+ clone() {
1442
+ const scale2 = this.getScale();
1443
+ const style = new RegularShape({
1444
+ fill: this.getFill() ? this.getFill().clone() : void 0,
1445
+ points: this.getPoints(),
1446
+ radius: this.getRadius(),
1447
+ radius2: this.getRadius2(),
1448
+ angle: this.getAngle(),
1449
+ stroke: this.getStroke() ? this.getStroke().clone() : void 0,
1450
+ rotation: this.getRotation(),
1451
+ rotateWithView: this.getRotateWithView(),
1452
+ scale: Array.isArray(scale2) ? scale2.slice() : scale2,
1453
+ displacement: this.getDisplacement().slice(),
1454
+ declutterMode: this.getDeclutterMode()
1455
+ });
1456
+ style.setOpacity(this.getOpacity());
1457
+ return style;
1458
+ }
1459
+ /**
1460
+ * Get the anchor point in pixels. The anchor determines the center point for the
1461
+ * symbolizer.
1462
+ * @return {Array<number>} Anchor.
1463
+ * @api
1464
+ * @override
1465
+ */
1466
+ getAnchor() {
1467
+ const size = this.size_;
1468
+ const displacement = this.getDisplacement();
1469
+ const scale2 = this.getScaleArray();
1470
+ return [
1471
+ size[0] / 2 - displacement[0] / scale2[0],
1472
+ size[1] / 2 + displacement[1] / scale2[1]
1473
+ ];
1474
+ }
1475
+ /**
1476
+ * Get the angle used in generating the shape.
1477
+ * @return {number} Shape's rotation in radians.
1478
+ * @api
1479
+ */
1480
+ getAngle() {
1481
+ return this.angle_;
1482
+ }
1483
+ /**
1484
+ * Get the fill style for the shape.
1485
+ * @return {import("./Fill.js").default|null} Fill style.
1486
+ * @api
1487
+ */
1488
+ getFill() {
1489
+ return this.fill_;
1490
+ }
1491
+ /**
1492
+ * Set the fill style.
1493
+ * @param {import("./Fill.js").default|null} fill Fill style.
1494
+ * @api
1495
+ */
1496
+ setFill(fill) {
1497
+ this.fill_ = fill;
1498
+ this.render();
1499
+ }
1500
+ /**
1501
+ * @return {HTMLCanvasElement|OffscreenCanvas} Image element.
1502
+ * @override
1503
+ */
1504
+ getHitDetectionImage() {
1505
+ if (!this.hitDetectionCanvas_) {
1506
+ this.hitDetectionCanvas_ = this.createHitDetectionCanvas_(
1507
+ this.renderOptions_
1508
+ );
1509
+ }
1510
+ return this.hitDetectionCanvas_;
1511
+ }
1512
+ /**
1513
+ * Get the image icon.
1514
+ * @param {number} pixelRatio Pixel ratio.
1515
+ * @return {HTMLCanvasElement|OffscreenCanvas} Image or Canvas element.
1516
+ * @api
1517
+ * @override
1518
+ */
1519
+ getImage(pixelRatio) {
1520
+ var _a, _b;
1521
+ const fillKey = (_a = this.fill_) == null ? void 0 : _a.getKey();
1522
+ const cacheKey = `${pixelRatio},${this.angle_},${this.radius},${this.radius2_},${this.points_},${fillKey}` + Object.values(this.renderOptions_).join(",");
1523
+ let image = (
1524
+ /** @type {HTMLCanvasElement|OffscreenCanvas} */
1525
+ (_b = shared.get(cacheKey, null, null)) == null ? void 0 : _b.getImage(1)
1526
+ );
1527
+ if (!image) {
1528
+ const renderOptions = this.renderOptions_;
1529
+ const size = Math.ceil(renderOptions.size * pixelRatio);
1530
+ const context = createCanvasContext2D(size, size);
1531
+ this.draw_(renderOptions, context, pixelRatio);
1532
+ image = context.canvas;
1533
+ shared.set(
1534
+ cacheKey,
1535
+ null,
1536
+ null,
1537
+ new IconImage(image, void 0, null, ImageState.LOADED, null)
1538
+ );
1539
+ }
1540
+ return image;
1541
+ }
1542
+ /**
1543
+ * Get the image pixel ratio.
1544
+ * @param {number} pixelRatio Pixel ratio.
1545
+ * @return {number} Pixel ratio.
1546
+ * @override
1547
+ */
1548
+ getPixelRatio(pixelRatio) {
1549
+ return pixelRatio;
1550
+ }
1551
+ /**
1552
+ * @return {import("../size.js").Size} Image size.
1553
+ * @override
1554
+ */
1555
+ getImageSize() {
1556
+ return this.size_;
1557
+ }
1558
+ /**
1559
+ * @return {import("../ImageState.js").default} Image state.
1560
+ * @override
1561
+ */
1562
+ getImageState() {
1563
+ return this.imageState_;
1564
+ }
1565
+ /**
1566
+ * Get the origin of the symbolizer.
1567
+ * @return {Array<number>} Origin.
1568
+ * @api
1569
+ * @override
1570
+ */
1571
+ getOrigin() {
1572
+ return this.origin_;
1573
+ }
1574
+ /**
1575
+ * Get the number of points for generating the shape.
1576
+ * @return {number} Number of points for stars and regular polygons.
1577
+ * @api
1578
+ */
1579
+ getPoints() {
1580
+ return this.points_;
1581
+ }
1582
+ /**
1583
+ * Get the (primary) radius for the shape.
1584
+ * @return {number} Radius.
1585
+ * @api
1586
+ */
1587
+ getRadius() {
1588
+ return this.radius;
1589
+ }
1590
+ /**
1591
+ * Get the secondary radius for the shape.
1592
+ * @return {number|undefined} Radius2.
1593
+ * @api
1594
+ */
1595
+ getRadius2() {
1596
+ return this.radius2_;
1597
+ }
1598
+ /**
1599
+ * Get the size of the symbolizer (in pixels).
1600
+ * @return {import("../size.js").Size} Size.
1601
+ * @api
1602
+ * @override
1603
+ */
1604
+ getSize() {
1605
+ return this.size_;
1606
+ }
1607
+ /**
1608
+ * Get the stroke style for the shape.
1609
+ * @return {import("./Stroke.js").default|null} Stroke style.
1610
+ * @api
1611
+ */
1612
+ getStroke() {
1613
+ return this.stroke_;
1614
+ }
1615
+ /**
1616
+ * Set the stroke style.
1617
+ * @param {import("./Stroke.js").default|null} stroke Stroke style.
1618
+ * @api
1619
+ */
1620
+ setStroke(stroke) {
1621
+ this.stroke_ = stroke;
1622
+ this.render();
1623
+ }
1624
+ /**
1625
+ * @param {function(import("../events/Event.js").default): void} listener Listener function.
1626
+ * @override
1627
+ */
1628
+ listenImageChange(listener) {
1629
+ }
1630
+ /**
1631
+ * Load not yet loaded URI.
1632
+ * @override
1633
+ */
1634
+ load() {
1635
+ }
1636
+ /**
1637
+ * @param {function(import("../events/Event.js").default): void} listener Listener function.
1638
+ * @override
1639
+ */
1640
+ unlistenImageChange(listener) {
1641
+ }
1642
+ /**
1643
+ * Calculate additional canvas size needed for the miter.
1644
+ * @param {string} lineJoin Line join
1645
+ * @param {number} strokeWidth Stroke width
1646
+ * @param {number} miterLimit Miter limit
1647
+ * @return {number} Additional canvas size needed
1648
+ * @private
1649
+ */
1650
+ calculateLineJoinSize_(lineJoin, strokeWidth, miterLimit) {
1651
+ if (strokeWidth === 0 || this.points_ === Infinity || lineJoin !== "bevel" && lineJoin !== "miter") {
1652
+ return strokeWidth;
1653
+ }
1654
+ let r1 = this.radius;
1655
+ let r2 = this.radius2_ === void 0 ? r1 : this.radius2_;
1656
+ if (r1 < r2) {
1657
+ const tmp = r1;
1658
+ r1 = r2;
1659
+ r2 = tmp;
1660
+ }
1661
+ const points = this.radius2_ === void 0 ? this.points_ : this.points_ * 2;
1662
+ const alpha = 2 * Math.PI / points;
1663
+ const a = r2 * Math.sin(alpha);
1664
+ const b = Math.sqrt(r2 * r2 - a * a);
1665
+ const d = r1 - b;
1666
+ const e = Math.sqrt(a * a + d * d);
1667
+ const miterRatio = e / a;
1668
+ if (lineJoin === "miter" && miterRatio <= miterLimit) {
1669
+ return miterRatio * strokeWidth;
1670
+ }
1671
+ const k = strokeWidth / 2 / miterRatio;
1672
+ const l = strokeWidth / 2 * (d / e);
1673
+ const maxr = Math.sqrt((r1 + k) * (r1 + k) + l * l);
1674
+ const bevelAdd = maxr - r1;
1675
+ if (this.radius2_ === void 0 || lineJoin === "bevel") {
1676
+ return bevelAdd * 2;
1677
+ }
1678
+ const aa = r1 * Math.sin(alpha);
1679
+ const bb = Math.sqrt(r1 * r1 - aa * aa);
1680
+ const dd = r2 - bb;
1681
+ const ee = Math.sqrt(aa * aa + dd * dd);
1682
+ const innerMiterRatio = ee / aa;
1683
+ if (innerMiterRatio <= miterLimit) {
1684
+ const innerLength = innerMiterRatio * strokeWidth / 2 - r2 - r1;
1685
+ return 2 * Math.max(bevelAdd, innerLength);
1686
+ }
1687
+ return bevelAdd * 2;
1688
+ }
1689
+ /**
1690
+ * @return {RenderOptions} The render options
1691
+ * @protected
1692
+ */
1693
+ createRenderOptions() {
1694
+ var _a, _b, _c, _d, _e, _f;
1695
+ let lineCap = defaultLineCap;
1696
+ let lineJoin = defaultLineJoin;
1697
+ let miterLimit = 0;
1698
+ let lineDash = null;
1699
+ let lineDashOffset = 0;
1700
+ let strokeStyle;
1701
+ let strokeWidth = 0;
1702
+ if (this.stroke_) {
1703
+ strokeStyle = asColorLike((_a = this.stroke_.getColor()) != null ? _a : defaultStrokeStyle);
1704
+ strokeWidth = (_b = this.stroke_.getWidth()) != null ? _b : defaultLineWidth;
1705
+ lineDash = this.stroke_.getLineDash();
1706
+ lineDashOffset = (_c = this.stroke_.getLineDashOffset()) != null ? _c : 0;
1707
+ lineJoin = (_d = this.stroke_.getLineJoin()) != null ? _d : defaultLineJoin;
1708
+ lineCap = (_e = this.stroke_.getLineCap()) != null ? _e : defaultLineCap;
1709
+ miterLimit = (_f = this.stroke_.getMiterLimit()) != null ? _f : defaultMiterLimit;
1710
+ }
1711
+ const add = this.calculateLineJoinSize_(lineJoin, strokeWidth, miterLimit);
1712
+ const maxRadius = Math.max(this.radius, this.radius2_ || 0);
1713
+ const size = Math.ceil(2 * maxRadius + add);
1714
+ return {
1715
+ strokeStyle,
1716
+ strokeWidth,
1717
+ size,
1718
+ lineCap,
1719
+ lineDash,
1720
+ lineDashOffset,
1721
+ lineJoin,
1722
+ miterLimit
1723
+ };
1724
+ }
1725
+ /**
1726
+ * @protected
1727
+ */
1728
+ render() {
1729
+ this.renderOptions_ = this.createRenderOptions();
1730
+ const size = this.renderOptions_.size;
1731
+ this.hitDetectionCanvas_ = null;
1732
+ this.size_ = [size, size];
1733
+ }
1734
+ /**
1735
+ * @private
1736
+ * @param {RenderOptions} renderOptions Render options.
1737
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context The rendering context.
1738
+ * @param {number} pixelRatio The pixel ratio.
1739
+ */
1740
+ draw_(renderOptions, context, pixelRatio) {
1741
+ context.scale(pixelRatio, pixelRatio);
1742
+ context.translate(renderOptions.size / 2, renderOptions.size / 2);
1743
+ this.createPath_(context);
1744
+ if (this.fill_) {
1745
+ let color = this.fill_.getColor();
1746
+ if (color === null) {
1747
+ color = defaultFillStyle;
1748
+ }
1749
+ context.fillStyle = asColorLike(color);
1750
+ context.fill();
1751
+ }
1752
+ if (renderOptions.strokeStyle) {
1753
+ context.strokeStyle = renderOptions.strokeStyle;
1754
+ context.lineWidth = renderOptions.strokeWidth;
1755
+ if (renderOptions.lineDash) {
1756
+ context.setLineDash(renderOptions.lineDash);
1757
+ context.lineDashOffset = renderOptions.lineDashOffset;
1758
+ }
1759
+ context.lineCap = renderOptions.lineCap;
1760
+ context.lineJoin = renderOptions.lineJoin;
1761
+ context.miterLimit = renderOptions.miterLimit;
1762
+ context.stroke();
1763
+ }
1764
+ }
1765
+ /**
1766
+ * @private
1767
+ * @param {RenderOptions} renderOptions Render options.
1768
+ * @return {HTMLCanvasElement|OffscreenCanvas} Canvas containing the icon
1769
+ */
1770
+ createHitDetectionCanvas_(renderOptions) {
1771
+ let context;
1772
+ if (this.fill_) {
1773
+ let color = this.fill_.getColor();
1774
+ let opacity = 0;
1775
+ if (typeof color === "string") {
1776
+ color = asArray(color);
1777
+ }
1778
+ if (color === null) {
1779
+ opacity = 1;
1780
+ } else if (Array.isArray(color)) {
1781
+ opacity = color.length === 4 ? color[3] : 1;
1782
+ }
1783
+ if (opacity === 0) {
1784
+ context = createCanvasContext2D(renderOptions.size, renderOptions.size);
1785
+ this.drawHitDetectionCanvas_(renderOptions, context);
1786
+ }
1787
+ }
1788
+ return context ? context.canvas : this.getImage(1);
1789
+ }
1790
+ /**
1791
+ * @private
1792
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context The context to draw in.
1793
+ */
1794
+ createPath_(context) {
1795
+ let points = this.points_;
1796
+ const radius = this.radius;
1797
+ if (points === Infinity) {
1798
+ context.arc(0, 0, radius, 0, 2 * Math.PI);
1799
+ } else {
1800
+ const radius2 = this.radius2_ === void 0 ? radius : this.radius2_;
1801
+ if (this.radius2_ !== void 0) {
1802
+ points *= 2;
1803
+ }
1804
+ const startAngle = this.angle_ - Math.PI / 2;
1805
+ const step = 2 * Math.PI / points;
1806
+ for (let i = 0; i < points; i++) {
1807
+ const angle0 = startAngle + i * step;
1808
+ const radiusC = i % 2 === 0 ? radius : radius2;
1809
+ context.lineTo(radiusC * Math.cos(angle0), radiusC * Math.sin(angle0));
1810
+ }
1811
+ context.closePath();
1812
+ }
1813
+ }
1814
+ /**
1815
+ * @private
1816
+ * @param {RenderOptions} renderOptions Render options.
1817
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context The context.
1818
+ */
1819
+ drawHitDetectionCanvas_(renderOptions, context) {
1820
+ context.translate(renderOptions.size / 2, renderOptions.size / 2);
1821
+ this.createPath_(context);
1822
+ context.fillStyle = defaultFillStyle;
1823
+ context.fill();
1824
+ if (renderOptions.strokeStyle) {
1825
+ context.strokeStyle = renderOptions.strokeStyle;
1826
+ context.lineWidth = renderOptions.strokeWidth;
1827
+ if (renderOptions.lineDash) {
1828
+ context.setLineDash(renderOptions.lineDash);
1829
+ context.lineDashOffset = renderOptions.lineDashOffset;
1830
+ }
1831
+ context.lineJoin = renderOptions.lineJoin;
1832
+ context.miterLimit = renderOptions.miterLimit;
1833
+ context.stroke();
1834
+ }
1835
+ }
1836
+ /**
1837
+ * @override
1838
+ */
1839
+ ready() {
1840
+ return this.fill_ ? this.fill_.ready() : Promise.resolve();
1841
+ }
1842
+ }
1843
+ class CircleStyle extends RegularShape {
1844
+ /**
1845
+ * @param {Options} [options] Options.
1846
+ */
1847
+ constructor(options) {
1848
+ options = options ? options : { radius: 5 };
1849
+ super({
1850
+ points: Infinity,
1851
+ fill: options.fill,
1852
+ radius: options.radius,
1853
+ stroke: options.stroke,
1854
+ scale: options.scale !== void 0 ? options.scale : 1,
1855
+ rotation: options.rotation !== void 0 ? options.rotation : 0,
1856
+ rotateWithView: options.rotateWithView !== void 0 ? options.rotateWithView : false,
1857
+ displacement: options.displacement !== void 0 ? options.displacement : [0, 0],
1858
+ declutterMode: options.declutterMode
1859
+ });
1860
+ }
1861
+ /**
1862
+ * Clones the style.
1863
+ * @return {CircleStyle} The cloned style.
1864
+ * @api
1865
+ * @override
1866
+ */
1867
+ clone() {
1868
+ const scale2 = this.getScale();
1869
+ const style = new CircleStyle({
1870
+ fill: this.getFill() ? this.getFill().clone() : void 0,
1871
+ stroke: this.getStroke() ? this.getStroke().clone() : void 0,
1872
+ radius: this.getRadius(),
1873
+ scale: Array.isArray(scale2) ? scale2.slice() : scale2,
1874
+ rotation: this.getRotation(),
1875
+ rotateWithView: this.getRotateWithView(),
1876
+ displacement: this.getDisplacement().slice(),
1877
+ declutterMode: this.getDeclutterMode()
1878
+ });
1879
+ style.setOpacity(this.getOpacity());
1880
+ return style;
1881
+ }
1882
+ /**
1883
+ * Set the circle radius.
1884
+ *
1885
+ * @param {number} radius Circle radius.
1886
+ * @api
1887
+ */
1888
+ setRadius(radius) {
1889
+ this.radius = radius;
1890
+ this.render();
1891
+ }
1892
+ }
1893
+ class Fill {
1894
+ /**
1895
+ * @param {Options} [options] Options.
1896
+ */
1897
+ constructor(options) {
1898
+ options = options || {};
1899
+ this.patternImage_ = null;
1900
+ this.color_ = null;
1901
+ if (options.color !== void 0) {
1902
+ this.setColor(options.color);
1903
+ }
1904
+ }
1905
+ /**
1906
+ * Clones the style. The color is not cloned if it is a {@link module:ol/colorlike~ColorLike}.
1907
+ * @return {Fill} The cloned style.
1908
+ * @api
1909
+ */
1910
+ clone() {
1911
+ const color = this.getColor();
1912
+ return new Fill({
1913
+ color: Array.isArray(color) ? color.slice() : color || void 0
1914
+ });
1915
+ }
1916
+ /**
1917
+ * Get the fill color.
1918
+ * @return {import("../color.js").Color|import("../colorlike.js").ColorLike|import('../colorlike.js').PatternDescriptor|null} Color.
1919
+ * @api
1920
+ */
1921
+ getColor() {
1922
+ return this.color_;
1923
+ }
1924
+ /**
1925
+ * Set the color.
1926
+ *
1927
+ * @param {import("../color.js").Color|import("../colorlike.js").ColorLike|import('../colorlike.js').PatternDescriptor|null} color Color.
1928
+ * @api
1929
+ */
1930
+ setColor(color) {
1931
+ if (color !== null && typeof color === "object" && "src" in color) {
1932
+ const patternImage = get(
1933
+ null,
1934
+ color.src,
1935
+ "anonymous",
1936
+ void 0,
1937
+ color.offset ? null : color.color ? color.color : null,
1938
+ !(color.offset && color.size)
1939
+ );
1940
+ patternImage.ready().then(() => {
1941
+ this.patternImage_ = null;
1942
+ });
1943
+ if (patternImage.getImageState() === ImageState.IDLE) {
1944
+ patternImage.load();
1945
+ }
1946
+ if (patternImage.getImageState() === ImageState.LOADING) {
1947
+ this.patternImage_ = patternImage;
1948
+ }
1949
+ }
1950
+ this.color_ = color;
1951
+ }
1952
+ /**
1953
+ * @return {string} Key of the fill for cache lookup.
1954
+ */
1955
+ getKey() {
1956
+ const fill = this.getColor();
1957
+ if (!fill) {
1958
+ return "";
1959
+ }
1960
+ return fill instanceof CanvasPattern || fill instanceof CanvasGradient ? getUid(fill) : typeof fill === "object" && "src" in fill ? fill.src + ":" + fill.offset : asArray(fill).toString();
1961
+ }
1962
+ /**
1963
+ * @return {boolean} The fill style is loading an image pattern.
1964
+ */
1965
+ loading() {
1966
+ return !!this.patternImage_;
1967
+ }
1968
+ /**
1969
+ * @return {Promise<void>} `false` or a promise that resolves when the style is ready to use.
1970
+ */
1971
+ ready() {
1972
+ return this.patternImage_ ? this.patternImage_.ready() : Promise.resolve();
1973
+ }
1974
+ }
1975
+ function calculateScale(width, height, wantedWidth, wantedHeight) {
1976
+ if (wantedWidth !== void 0 && wantedHeight !== void 0) {
1977
+ return [wantedWidth / width, wantedHeight / height];
1978
+ }
1979
+ if (wantedWidth !== void 0) {
1980
+ return wantedWidth / width;
1981
+ }
1982
+ if (wantedHeight !== void 0) {
1983
+ return wantedHeight / height;
1984
+ }
1985
+ return 1;
1986
+ }
1987
+ class Icon extends ImageStyle {
1988
+ /**
1989
+ * @param {Options} [options] Options.
1990
+ */
1991
+ constructor(options) {
1992
+ options = options || {};
1993
+ const opacity = options.opacity !== void 0 ? options.opacity : 1;
1994
+ const rotation = options.rotation !== void 0 ? options.rotation : 0;
1995
+ const scale2 = options.scale !== void 0 ? options.scale : 1;
1996
+ const rotateWithView = options.rotateWithView !== void 0 ? options.rotateWithView : false;
1997
+ super({
1998
+ opacity,
1999
+ rotation,
2000
+ scale: scale2,
2001
+ displacement: options.displacement !== void 0 ? options.displacement : [0, 0],
2002
+ rotateWithView,
2003
+ declutterMode: options.declutterMode
2004
+ });
2005
+ this.anchor_ = options.anchor !== void 0 ? options.anchor : [0.5, 0.5];
2006
+ this.normalizedAnchor_ = null;
2007
+ this.anchorOrigin_ = options.anchorOrigin !== void 0 ? options.anchorOrigin : "top-left";
2008
+ this.anchorXUnits_ = options.anchorXUnits !== void 0 ? options.anchorXUnits : "fraction";
2009
+ this.anchorYUnits_ = options.anchorYUnits !== void 0 ? options.anchorYUnits : "fraction";
2010
+ this.crossOrigin_ = options.crossOrigin !== void 0 ? options.crossOrigin : null;
2011
+ const image = options.img !== void 0 ? options.img : null;
2012
+ let cacheKey = options.src;
2013
+ assert(
2014
+ !(cacheKey !== void 0 && image),
2015
+ "`image` and `src` cannot be provided at the same time"
2016
+ );
2017
+ if ((cacheKey === void 0 || cacheKey.length === 0) && image) {
2018
+ cacheKey = /** @type {HTMLImageElement} */
2019
+ image.src || getUid(image);
2020
+ }
2021
+ assert(
2022
+ cacheKey !== void 0 && cacheKey.length > 0,
2023
+ "A defined and non-empty `src` or `image` must be provided"
2024
+ );
2025
+ assert(
2026
+ !((options.width !== void 0 || options.height !== void 0) && options.scale !== void 0),
2027
+ "`width` or `height` cannot be provided together with `scale`"
2028
+ );
2029
+ let imageState;
2030
+ if (options.src !== void 0) {
2031
+ imageState = ImageState.IDLE;
2032
+ } else if (image !== void 0) {
2033
+ if ("complete" in image) {
2034
+ if (image.complete) {
2035
+ imageState = image.src ? ImageState.LOADED : ImageState.IDLE;
2036
+ } else {
2037
+ imageState = ImageState.LOADING;
2038
+ }
2039
+ } else {
2040
+ imageState = ImageState.LOADED;
2041
+ }
2042
+ }
2043
+ this.color_ = options.color !== void 0 ? asArray(options.color) : null;
2044
+ this.iconImage_ = get(
2045
+ image,
2046
+ /** @type {string} */
2047
+ cacheKey,
2048
+ this.crossOrigin_,
2049
+ imageState,
2050
+ this.color_
2051
+ );
2052
+ this.offset_ = options.offset !== void 0 ? options.offset : [0, 0];
2053
+ this.offsetOrigin_ = options.offsetOrigin !== void 0 ? options.offsetOrigin : "top-left";
2054
+ this.origin_ = null;
2055
+ this.size_ = options.size !== void 0 ? options.size : null;
2056
+ this.initialOptions_;
2057
+ if (options.width !== void 0 || options.height !== void 0) {
2058
+ let width, height;
2059
+ if (options.size) {
2060
+ [width, height] = options.size;
2061
+ } else {
2062
+ const image2 = this.getImage(1);
2063
+ if (image2.width && image2.height) {
2064
+ width = image2.width;
2065
+ height = image2.height;
2066
+ } else if (image2 instanceof HTMLImageElement) {
2067
+ this.initialOptions_ = options;
2068
+ const onload = () => {
2069
+ this.unlistenImageChange(onload);
2070
+ if (!this.initialOptions_) {
2071
+ return;
2072
+ }
2073
+ const imageSize = this.iconImage_.getSize();
2074
+ this.setScale(
2075
+ calculateScale(
2076
+ imageSize[0],
2077
+ imageSize[1],
2078
+ options.width,
2079
+ options.height
2080
+ )
2081
+ );
2082
+ };
2083
+ this.listenImageChange(onload);
2084
+ return;
2085
+ }
2086
+ }
2087
+ if (width !== void 0) {
2088
+ this.setScale(
2089
+ calculateScale(width, height, options.width, options.height)
2090
+ );
2091
+ }
2092
+ }
2093
+ }
2094
+ /**
2095
+ * Clones the style. The underlying Image/HTMLCanvasElement is not cloned.
2096
+ * @return {Icon} The cloned style.
2097
+ * @api
2098
+ * @override
2099
+ */
2100
+ clone() {
2101
+ let scale2, width, height;
2102
+ if (this.initialOptions_) {
2103
+ width = this.initialOptions_.width;
2104
+ height = this.initialOptions_.height;
2105
+ } else {
2106
+ scale2 = this.getScale();
2107
+ scale2 = Array.isArray(scale2) ? scale2.slice() : scale2;
2108
+ }
2109
+ return new Icon({
2110
+ anchor: this.anchor_.slice(),
2111
+ anchorOrigin: this.anchorOrigin_,
2112
+ anchorXUnits: this.anchorXUnits_,
2113
+ anchorYUnits: this.anchorYUnits_,
2114
+ color: this.color_ && this.color_.slice ? this.color_.slice() : this.color_ || void 0,
2115
+ crossOrigin: this.crossOrigin_,
2116
+ offset: this.offset_.slice(),
2117
+ offsetOrigin: this.offsetOrigin_,
2118
+ opacity: this.getOpacity(),
2119
+ rotateWithView: this.getRotateWithView(),
2120
+ rotation: this.getRotation(),
2121
+ scale: scale2,
2122
+ width,
2123
+ height,
2124
+ size: this.size_ !== null ? this.size_.slice() : void 0,
2125
+ src: this.getSrc(),
2126
+ displacement: this.getDisplacement().slice(),
2127
+ declutterMode: this.getDeclutterMode()
2128
+ });
2129
+ }
2130
+ /**
2131
+ * Get the anchor point in pixels. The anchor determines the center point for the
2132
+ * symbolizer.
2133
+ * @return {Array<number>} Anchor.
2134
+ * @api
2135
+ * @override
2136
+ */
2137
+ getAnchor() {
2138
+ let anchor = this.normalizedAnchor_;
2139
+ if (!anchor) {
2140
+ anchor = this.anchor_;
2141
+ const size = this.getSize();
2142
+ if (this.anchorXUnits_ == "fraction" || this.anchorYUnits_ == "fraction") {
2143
+ if (!size) {
2144
+ return null;
2145
+ }
2146
+ anchor = this.anchor_.slice();
2147
+ if (this.anchorXUnits_ == "fraction") {
2148
+ anchor[0] *= size[0];
2149
+ }
2150
+ if (this.anchorYUnits_ == "fraction") {
2151
+ anchor[1] *= size[1];
2152
+ }
2153
+ }
2154
+ if (this.anchorOrigin_ != "top-left") {
2155
+ if (!size) {
2156
+ return null;
2157
+ }
2158
+ if (anchor === this.anchor_) {
2159
+ anchor = this.anchor_.slice();
2160
+ }
2161
+ if (this.anchorOrigin_ == "top-right" || this.anchorOrigin_ == "bottom-right") {
2162
+ anchor[0] = -anchor[0] + size[0];
2163
+ }
2164
+ if (this.anchorOrigin_ == "bottom-left" || this.anchorOrigin_ == "bottom-right") {
2165
+ anchor[1] = -anchor[1] + size[1];
2166
+ }
2167
+ }
2168
+ this.normalizedAnchor_ = anchor;
2169
+ }
2170
+ const displacement = this.getDisplacement();
2171
+ const scale2 = this.getScaleArray();
2172
+ return [
2173
+ anchor[0] - displacement[0] / scale2[0],
2174
+ anchor[1] + displacement[1] / scale2[1]
2175
+ ];
2176
+ }
2177
+ /**
2178
+ * Set the anchor point. The anchor determines the center point for the
2179
+ * symbolizer.
2180
+ *
2181
+ * @param {Array<number>} anchor Anchor.
2182
+ * @api
2183
+ */
2184
+ setAnchor(anchor) {
2185
+ this.anchor_ = anchor;
2186
+ this.normalizedAnchor_ = null;
2187
+ }
2188
+ /**
2189
+ * Get the icon color.
2190
+ * @return {import("../color.js").Color} Color.
2191
+ * @api
2192
+ */
2193
+ getColor() {
2194
+ return this.color_;
2195
+ }
2196
+ /**
2197
+ * Get the image icon.
2198
+ * @param {number} pixelRatio Pixel ratio.
2199
+ * @return {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap} Image or Canvas element. If the Icon
2200
+ * style was configured with `src` or with a not let loaded `img`, an `ImageBitmap` will be returned.
2201
+ * @api
2202
+ * @override
2203
+ */
2204
+ getImage(pixelRatio) {
2205
+ return this.iconImage_.getImage(pixelRatio);
2206
+ }
2207
+ /**
2208
+ * Get the pixel ratio.
2209
+ * @param {number} pixelRatio Pixel ratio.
2210
+ * @return {number} The pixel ratio of the image.
2211
+ * @api
2212
+ * @override
2213
+ */
2214
+ getPixelRatio(pixelRatio) {
2215
+ return this.iconImage_.getPixelRatio(pixelRatio);
2216
+ }
2217
+ /**
2218
+ * @return {import("../size.js").Size} Image size.
2219
+ * @override
2220
+ */
2221
+ getImageSize() {
2222
+ return this.iconImage_.getSize();
2223
+ }
2224
+ /**
2225
+ * @return {import("../ImageState.js").default} Image state.
2226
+ * @override
2227
+ */
2228
+ getImageState() {
2229
+ return this.iconImage_.getImageState();
2230
+ }
2231
+ /**
2232
+ * @return {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap} Image element.
2233
+ * @override
2234
+ */
2235
+ getHitDetectionImage() {
2236
+ return this.iconImage_.getHitDetectionImage();
2237
+ }
2238
+ /**
2239
+ * Get the origin of the symbolizer.
2240
+ * @return {Array<number>} Origin.
2241
+ * @api
2242
+ * @override
2243
+ */
2244
+ getOrigin() {
2245
+ if (this.origin_) {
2246
+ return this.origin_;
2247
+ }
2248
+ let offset = this.offset_;
2249
+ if (this.offsetOrigin_ != "top-left") {
2250
+ const size = this.getSize();
2251
+ const iconImageSize = this.iconImage_.getSize();
2252
+ if (!size || !iconImageSize) {
2253
+ return null;
2254
+ }
2255
+ offset = offset.slice();
2256
+ if (this.offsetOrigin_ == "top-right" || this.offsetOrigin_ == "bottom-right") {
2257
+ offset[0] = iconImageSize[0] - size[0] - offset[0];
2258
+ }
2259
+ if (this.offsetOrigin_ == "bottom-left" || this.offsetOrigin_ == "bottom-right") {
2260
+ offset[1] = iconImageSize[1] - size[1] - offset[1];
2261
+ }
2262
+ }
2263
+ this.origin_ = offset;
2264
+ return this.origin_;
2265
+ }
2266
+ /**
2267
+ * Get the image URL.
2268
+ * @return {string|undefined} Image src.
2269
+ * @api
2270
+ */
2271
+ getSrc() {
2272
+ return this.iconImage_.getSrc();
2273
+ }
2274
+ /**
2275
+ * Set the image URI
2276
+ * @param {string} src Image source URI
2277
+ * @api
2278
+ */
2279
+ setSrc(src) {
2280
+ this.iconImage_ = get(
2281
+ null,
2282
+ src,
2283
+ this.crossOrigin_,
2284
+ ImageState.IDLE,
2285
+ this.color_
2286
+ );
2287
+ }
2288
+ /**
2289
+ * Get the size of the icon (in pixels).
2290
+ * @return {import("../size.js").Size} Image size.
2291
+ * @api
2292
+ * @override
2293
+ */
2294
+ getSize() {
2295
+ return !this.size_ ? this.iconImage_.getSize() : this.size_;
2296
+ }
2297
+ /**
2298
+ * Get the width of the icon (in pixels). Will return undefined when the icon image is not yet loaded.
2299
+ * @return {number} Icon width (in pixels).
2300
+ * @api
2301
+ */
2302
+ getWidth() {
2303
+ const scale2 = this.getScaleArray();
2304
+ if (this.size_) {
2305
+ return this.size_[0] * scale2[0];
2306
+ }
2307
+ if (this.iconImage_.getImageState() == ImageState.LOADED) {
2308
+ return this.iconImage_.getSize()[0] * scale2[0];
2309
+ }
2310
+ return void 0;
2311
+ }
2312
+ /**
2313
+ * Get the height of the icon (in pixels). Will return undefined when the icon image is not yet loaded.
2314
+ * @return {number} Icon height (in pixels).
2315
+ * @api
2316
+ */
2317
+ getHeight() {
2318
+ const scale2 = this.getScaleArray();
2319
+ if (this.size_) {
2320
+ return this.size_[1] * scale2[1];
2321
+ }
2322
+ if (this.iconImage_.getImageState() == ImageState.LOADED) {
2323
+ return this.iconImage_.getSize()[1] * scale2[1];
2324
+ }
2325
+ return void 0;
2326
+ }
2327
+ /**
2328
+ * Set the scale.
2329
+ *
2330
+ * @param {number|import("../size.js").Size} scale Scale.
2331
+ * @api
2332
+ * @override
2333
+ */
2334
+ setScale(scale2) {
2335
+ delete this.initialOptions_;
2336
+ super.setScale(scale2);
2337
+ }
2338
+ /**
2339
+ * @param {function(import("../events/Event.js").default): void} listener Listener function.
2340
+ * @override
2341
+ */
2342
+ listenImageChange(listener) {
2343
+ this.iconImage_.addEventListener(EventType.CHANGE, listener);
2344
+ }
2345
+ /**
2346
+ * Load not yet loaded URI.
2347
+ * When rendering a feature with an icon style, the vector renderer will
2348
+ * automatically call this method. However, you might want to call this
2349
+ * method yourself for preloading or other purposes.
2350
+ * @api
2351
+ * @override
2352
+ */
2353
+ load() {
2354
+ this.iconImage_.load();
2355
+ }
2356
+ /**
2357
+ * @param {function(import("../events/Event.js").default): void} listener Listener function.
2358
+ * @override
2359
+ */
2360
+ unlistenImageChange(listener) {
2361
+ this.iconImage_.removeEventListener(EventType.CHANGE, listener);
2362
+ }
2363
+ /**
2364
+ * @override
2365
+ */
2366
+ ready() {
2367
+ return this.iconImage_.ready();
2368
+ }
2369
+ }
2370
+ class Stroke {
2371
+ /**
2372
+ * @param {Options} [options] Options.
2373
+ */
2374
+ constructor(options) {
2375
+ options = options || {};
2376
+ this.color_ = options.color !== void 0 ? options.color : null;
2377
+ this.lineCap_ = options.lineCap;
2378
+ this.lineDash_ = options.lineDash !== void 0 ? options.lineDash : null;
2379
+ this.lineDashOffset_ = options.lineDashOffset;
2380
+ this.lineJoin_ = options.lineJoin;
2381
+ this.miterLimit_ = options.miterLimit;
2382
+ this.width_ = options.width;
2383
+ }
2384
+ /**
2385
+ * Clones the style.
2386
+ * @return {Stroke} The cloned style.
2387
+ * @api
2388
+ */
2389
+ clone() {
2390
+ const color = this.getColor();
2391
+ return new Stroke({
2392
+ color: Array.isArray(color) ? color.slice() : color || void 0,
2393
+ lineCap: this.getLineCap(),
2394
+ lineDash: this.getLineDash() ? this.getLineDash().slice() : void 0,
2395
+ lineDashOffset: this.getLineDashOffset(),
2396
+ lineJoin: this.getLineJoin(),
2397
+ miterLimit: this.getMiterLimit(),
2398
+ width: this.getWidth()
2399
+ });
2400
+ }
2401
+ /**
2402
+ * Get the stroke color.
2403
+ * @return {import("../color.js").Color|import("../colorlike.js").ColorLike} Color.
2404
+ * @api
2405
+ */
2406
+ getColor() {
2407
+ return this.color_;
2408
+ }
2409
+ /**
2410
+ * Get the line cap type for the stroke.
2411
+ * @return {CanvasLineCap|undefined} Line cap.
2412
+ * @api
2413
+ */
2414
+ getLineCap() {
2415
+ return this.lineCap_;
2416
+ }
2417
+ /**
2418
+ * Get the line dash style for the stroke.
2419
+ * @return {Array<number>|null} Line dash.
2420
+ * @api
2421
+ */
2422
+ getLineDash() {
2423
+ return this.lineDash_;
2424
+ }
2425
+ /**
2426
+ * Get the line dash offset for the stroke.
2427
+ * @return {number|undefined} Line dash offset.
2428
+ * @api
2429
+ */
2430
+ getLineDashOffset() {
2431
+ return this.lineDashOffset_;
2432
+ }
2433
+ /**
2434
+ * Get the line join type for the stroke.
2435
+ * @return {CanvasLineJoin|undefined} Line join.
2436
+ * @api
2437
+ */
2438
+ getLineJoin() {
2439
+ return this.lineJoin_;
2440
+ }
2441
+ /**
2442
+ * Get the miter limit for the stroke.
2443
+ * @return {number|undefined} Miter limit.
2444
+ * @api
2445
+ */
2446
+ getMiterLimit() {
2447
+ return this.miterLimit_;
2448
+ }
2449
+ /**
2450
+ * Get the stroke width.
2451
+ * @return {number|undefined} Width.
2452
+ * @api
2453
+ */
2454
+ getWidth() {
2455
+ return this.width_;
2456
+ }
2457
+ /**
2458
+ * Set the color.
2459
+ *
2460
+ * @param {import("../color.js").Color|import("../colorlike.js").ColorLike} color Color.
2461
+ * @api
2462
+ */
2463
+ setColor(color) {
2464
+ this.color_ = color;
2465
+ }
2466
+ /**
2467
+ * Set the line cap.
2468
+ *
2469
+ * @param {CanvasLineCap|undefined} lineCap Line cap.
2470
+ * @api
2471
+ */
2472
+ setLineCap(lineCap) {
2473
+ this.lineCap_ = lineCap;
2474
+ }
2475
+ /**
2476
+ * Set the line dash.
2477
+ *
2478
+ * @param {Array<number>|null} lineDash Line dash.
2479
+ * @api
2480
+ */
2481
+ setLineDash(lineDash) {
2482
+ this.lineDash_ = lineDash;
2483
+ }
2484
+ /**
2485
+ * Set the line dash offset.
2486
+ *
2487
+ * @param {number|undefined} lineDashOffset Line dash offset.
2488
+ * @api
2489
+ */
2490
+ setLineDashOffset(lineDashOffset) {
2491
+ this.lineDashOffset_ = lineDashOffset;
2492
+ }
2493
+ /**
2494
+ * Set the line join.
2495
+ *
2496
+ * @param {CanvasLineJoin|undefined} lineJoin Line join.
2497
+ * @api
2498
+ */
2499
+ setLineJoin(lineJoin) {
2500
+ this.lineJoin_ = lineJoin;
2501
+ }
2502
+ /**
2503
+ * Set the miter limit.
2504
+ *
2505
+ * @param {number|undefined} miterLimit Miter limit.
2506
+ * @api
2507
+ */
2508
+ setMiterLimit(miterLimit) {
2509
+ this.miterLimit_ = miterLimit;
2510
+ }
2511
+ /**
2512
+ * Set the width.
2513
+ *
2514
+ * @param {number|undefined} width Width.
2515
+ * @api
2516
+ */
2517
+ setWidth(width) {
2518
+ this.width_ = width;
2519
+ }
2520
+ }
2521
+ class Style {
2522
+ /**
2523
+ * @param {Options} [options] Style options.
2524
+ */
2525
+ constructor(options) {
2526
+ options = options || {};
2527
+ this.geometry_ = null;
2528
+ this.geometryFunction_ = defaultGeometryFunction;
2529
+ if (options.geometry !== void 0) {
2530
+ this.setGeometry(options.geometry);
2531
+ }
2532
+ this.fill_ = options.fill !== void 0 ? options.fill : null;
2533
+ this.image_ = options.image !== void 0 ? options.image : null;
2534
+ this.renderer_ = options.renderer !== void 0 ? options.renderer : null;
2535
+ this.hitDetectionRenderer_ = options.hitDetectionRenderer !== void 0 ? options.hitDetectionRenderer : null;
2536
+ this.stroke_ = options.stroke !== void 0 ? options.stroke : null;
2537
+ this.text_ = options.text !== void 0 ? options.text : null;
2538
+ this.zIndex_ = options.zIndex;
2539
+ }
2540
+ /**
2541
+ * Clones the style.
2542
+ * @return {Style} The cloned style.
2543
+ * @api
2544
+ */
2545
+ clone() {
2546
+ var _a;
2547
+ let geometry = this.getGeometry();
2548
+ if (geometry && typeof geometry === "object") {
2549
+ geometry = /** @type {import("../geom/Geometry.js").default} */
2550
+ geometry.clone();
2551
+ }
2552
+ return new Style({
2553
+ geometry: geometry != null ? geometry : void 0,
2554
+ fill: this.getFill() ? this.getFill().clone() : void 0,
2555
+ image: this.getImage() ? this.getImage().clone() : void 0,
2556
+ renderer: (_a = this.getRenderer()) != null ? _a : void 0,
2557
+ stroke: this.getStroke() ? this.getStroke().clone() : void 0,
2558
+ text: this.getText() ? this.getText().clone() : void 0,
2559
+ zIndex: this.getZIndex()
2560
+ });
2561
+ }
2562
+ /**
2563
+ * Get the custom renderer function that was configured with
2564
+ * {@link #setRenderer} or the `renderer` constructor option.
2565
+ * @return {RenderFunction|null} Custom renderer function.
2566
+ * @api
2567
+ */
2568
+ getRenderer() {
2569
+ return this.renderer_;
2570
+ }
2571
+ /**
2572
+ * Sets a custom renderer function for this style. When set, `fill`, `stroke`
2573
+ * and `image` options of the style will be ignored.
2574
+ * @param {RenderFunction|null} renderer Custom renderer function.
2575
+ * @api
2576
+ */
2577
+ setRenderer(renderer) {
2578
+ this.renderer_ = renderer;
2579
+ }
2580
+ /**
2581
+ * Sets a custom renderer function for this style used
2582
+ * in hit detection.
2583
+ * @param {RenderFunction|null} renderer Custom renderer function.
2584
+ * @api
2585
+ */
2586
+ setHitDetectionRenderer(renderer) {
2587
+ this.hitDetectionRenderer_ = renderer;
2588
+ }
2589
+ /**
2590
+ * Get the custom renderer function that was configured with
2591
+ * {@link #setHitDetectionRenderer} or the `hitDetectionRenderer` constructor option.
2592
+ * @return {RenderFunction|null} Custom renderer function.
2593
+ * @api
2594
+ */
2595
+ getHitDetectionRenderer() {
2596
+ return this.hitDetectionRenderer_;
2597
+ }
2598
+ /**
2599
+ * Get the geometry to be rendered.
2600
+ * @return {string|import("../geom/Geometry.js").default|GeometryFunction|null}
2601
+ * Feature property or geometry or function that returns the geometry that will
2602
+ * be rendered with this style.
2603
+ * @api
2604
+ */
2605
+ getGeometry() {
2606
+ return this.geometry_;
2607
+ }
2608
+ /**
2609
+ * Get the function used to generate a geometry for rendering.
2610
+ * @return {!GeometryFunction} Function that is called with a feature
2611
+ * and returns the geometry to render instead of the feature's geometry.
2612
+ * @api
2613
+ */
2614
+ getGeometryFunction() {
2615
+ return this.geometryFunction_;
2616
+ }
2617
+ /**
2618
+ * Get the fill style.
2619
+ * @return {import("./Fill.js").default|null} Fill style.
2620
+ * @api
2621
+ */
2622
+ getFill() {
2623
+ return this.fill_;
2624
+ }
2625
+ /**
2626
+ * Set the fill style.
2627
+ * @param {import("./Fill.js").default|null} fill Fill style.
2628
+ * @api
2629
+ */
2630
+ setFill(fill) {
2631
+ this.fill_ = fill;
2632
+ }
2633
+ /**
2634
+ * Get the image style.
2635
+ * @return {import("./Image.js").default|null} Image style.
2636
+ * @api
2637
+ */
2638
+ getImage() {
2639
+ return this.image_;
2640
+ }
2641
+ /**
2642
+ * Set the image style.
2643
+ * @param {import("./Image.js").default} image Image style.
2644
+ * @api
2645
+ */
2646
+ setImage(image) {
2647
+ this.image_ = image;
2648
+ }
2649
+ /**
2650
+ * Get the stroke style.
2651
+ * @return {import("./Stroke.js").default|null} Stroke style.
2652
+ * @api
2653
+ */
2654
+ getStroke() {
2655
+ return this.stroke_;
2656
+ }
2657
+ /**
2658
+ * Set the stroke style.
2659
+ * @param {import("./Stroke.js").default|null} stroke Stroke style.
2660
+ * @api
2661
+ */
2662
+ setStroke(stroke) {
2663
+ this.stroke_ = stroke;
2664
+ }
2665
+ /**
2666
+ * Get the text style.
2667
+ * @return {import("./Text.js").default|null} Text style.
2668
+ * @api
2669
+ */
2670
+ getText() {
2671
+ return this.text_;
2672
+ }
2673
+ /**
2674
+ * Set the text style.
2675
+ * @param {import("./Text.js").default} text Text style.
2676
+ * @api
2677
+ */
2678
+ setText(text) {
2679
+ this.text_ = text;
2680
+ }
2681
+ /**
2682
+ * Get the z-index for the style.
2683
+ * @return {number|undefined} ZIndex.
2684
+ * @api
2685
+ */
2686
+ getZIndex() {
2687
+ return this.zIndex_;
2688
+ }
2689
+ /**
2690
+ * Set a geometry that is rendered instead of the feature's geometry.
2691
+ *
2692
+ * @param {string|import("../geom/Geometry.js").default|GeometryFunction|null} geometry
2693
+ * Feature property or geometry or function returning a geometry to render
2694
+ * for this style.
2695
+ * @api
2696
+ */
2697
+ setGeometry(geometry) {
2698
+ if (typeof geometry === "function") {
2699
+ this.geometryFunction_ = geometry;
2700
+ } else if (typeof geometry === "string") {
2701
+ this.geometryFunction_ = function(feature) {
2702
+ return (
2703
+ /** @type {import("../geom/Geometry.js").default} */
2704
+ feature.get(geometry)
2705
+ );
2706
+ };
2707
+ } else if (!geometry) {
2708
+ this.geometryFunction_ = defaultGeometryFunction;
2709
+ } else if (geometry !== void 0) {
2710
+ this.geometryFunction_ = function() {
2711
+ return (
2712
+ /** @type {import("../geom/Geometry.js").default} */
2713
+ geometry
2714
+ );
2715
+ };
2716
+ }
2717
+ this.geometry_ = geometry;
2718
+ }
2719
+ /**
2720
+ * Set the z-index.
2721
+ *
2722
+ * @param {number|undefined} zIndex ZIndex.
2723
+ * @api
2724
+ */
2725
+ setZIndex(zIndex) {
2726
+ this.zIndex_ = zIndex;
2727
+ }
2728
+ }
2729
+ function toFunction(obj) {
2730
+ let styleFunction;
2731
+ if (typeof obj === "function") {
2732
+ styleFunction = obj;
2733
+ } else {
2734
+ let styles;
2735
+ if (Array.isArray(obj)) {
2736
+ styles = obj;
2737
+ } else {
2738
+ assert(
2739
+ typeof /** @type {?} */
2740
+ obj.getZIndex === "function",
2741
+ "Expected an `Style` or an array of `Style`"
2742
+ );
2743
+ const style = (
2744
+ /** @type {Style} */
2745
+ obj
2746
+ );
2747
+ styles = [style];
2748
+ }
2749
+ styleFunction = function() {
2750
+ return styles;
2751
+ };
2752
+ }
2753
+ return styleFunction;
2754
+ }
2755
+ let defaultStyles = null;
2756
+ function createDefaultStyle(feature, resolution) {
2757
+ if (!defaultStyles) {
2758
+ const fill = new Fill({
2759
+ color: "rgba(255,255,255,0.4)"
2760
+ });
2761
+ const stroke = new Stroke({
2762
+ color: "#3399CC",
2763
+ width: 1.25
2764
+ });
2765
+ defaultStyles = [
2766
+ new Style({
2767
+ image: new CircleStyle({
2768
+ fill,
2769
+ stroke,
2770
+ radius: 5
2771
+ }),
2772
+ fill,
2773
+ stroke
2774
+ })
2775
+ ];
2776
+ }
2777
+ return defaultStyles;
2778
+ }
2779
+ function defaultGeometryFunction(feature) {
2780
+ return feature.getGeometry();
2781
+ }
2782
+ const DEFAULT_FILL_COLOR = "#333";
2783
+ class Text {
2784
+ /**
2785
+ * @param {Options} [options] Options.
2786
+ */
2787
+ constructor(options) {
2788
+ options = options || {};
2789
+ this.font_ = options.font;
2790
+ this.rotation_ = options.rotation;
2791
+ this.rotateWithView_ = options.rotateWithView;
2792
+ this.keepUpright_ = options.keepUpright;
2793
+ this.scale_ = options.scale;
2794
+ this.scaleArray_ = toSize(options.scale !== void 0 ? options.scale : 1);
2795
+ this.text_ = options.text;
2796
+ this.textAlign_ = options.textAlign;
2797
+ this.justify_ = options.justify;
2798
+ this.repeat_ = options.repeat;
2799
+ this.textBaseline_ = options.textBaseline;
2800
+ this.fill_ = options.fill !== void 0 ? options.fill : new Fill({ color: DEFAULT_FILL_COLOR });
2801
+ this.maxAngle_ = options.maxAngle !== void 0 ? options.maxAngle : Math.PI / 4;
2802
+ this.placement_ = options.placement !== void 0 ? options.placement : "point";
2803
+ this.overflow_ = !!options.overflow;
2804
+ this.stroke_ = options.stroke !== void 0 ? options.stroke : null;
2805
+ this.offsetX_ = options.offsetX !== void 0 ? options.offsetX : 0;
2806
+ this.offsetY_ = options.offsetY !== void 0 ? options.offsetY : 0;
2807
+ this.backgroundFill_ = options.backgroundFill ? options.backgroundFill : null;
2808
+ this.backgroundStroke_ = options.backgroundStroke ? options.backgroundStroke : null;
2809
+ this.padding_ = options.padding === void 0 ? null : options.padding;
2810
+ this.declutterMode_ = options.declutterMode;
2811
+ }
2812
+ /**
2813
+ * Clones the style.
2814
+ * @return {Text} The cloned style.
2815
+ * @api
2816
+ */
2817
+ clone() {
2818
+ const scale2 = this.getScale();
2819
+ return new Text({
2820
+ font: this.getFont(),
2821
+ placement: this.getPlacement(),
2822
+ repeat: this.getRepeat(),
2823
+ maxAngle: this.getMaxAngle(),
2824
+ overflow: this.getOverflow(),
2825
+ rotation: this.getRotation(),
2826
+ rotateWithView: this.getRotateWithView(),
2827
+ keepUpright: this.getKeepUpright(),
2828
+ scale: Array.isArray(scale2) ? scale2.slice() : scale2,
2829
+ text: this.getText(),
2830
+ textAlign: this.getTextAlign(),
2831
+ justify: this.getJustify(),
2832
+ textBaseline: this.getTextBaseline(),
2833
+ fill: this.getFill() instanceof Fill ? this.getFill().clone() : this.getFill(),
2834
+ stroke: this.getStroke() ? this.getStroke().clone() : void 0,
2835
+ offsetX: this.getOffsetX(),
2836
+ offsetY: this.getOffsetY(),
2837
+ backgroundFill: this.getBackgroundFill() ? this.getBackgroundFill().clone() : void 0,
2838
+ backgroundStroke: this.getBackgroundStroke() ? this.getBackgroundStroke().clone() : void 0,
2839
+ padding: this.getPadding() || void 0,
2840
+ declutterMode: this.getDeclutterMode()
2841
+ });
2842
+ }
2843
+ /**
2844
+ * Get the `overflow` configuration.
2845
+ * @return {boolean} Let text overflow the length of the path they follow.
2846
+ * @api
2847
+ */
2848
+ getOverflow() {
2849
+ return this.overflow_;
2850
+ }
2851
+ /**
2852
+ * Get the font name.
2853
+ * @return {string|undefined} Font.
2854
+ * @api
2855
+ */
2856
+ getFont() {
2857
+ return this.font_;
2858
+ }
2859
+ /**
2860
+ * Get the maximum angle between adjacent characters.
2861
+ * @return {number} Angle in radians.
2862
+ * @api
2863
+ */
2864
+ getMaxAngle() {
2865
+ return this.maxAngle_;
2866
+ }
2867
+ /**
2868
+ * Get the label placement.
2869
+ * @return {TextPlacement} Text placement.
2870
+ * @api
2871
+ */
2872
+ getPlacement() {
2873
+ return this.placement_;
2874
+ }
2875
+ /**
2876
+ * Get the repeat interval of the text.
2877
+ * @return {number|undefined} Repeat interval in pixels.
2878
+ * @api
2879
+ */
2880
+ getRepeat() {
2881
+ return this.repeat_;
2882
+ }
2883
+ /**
2884
+ * Get the x-offset for the text.
2885
+ * @return {number} Horizontal text offset.
2886
+ * @api
2887
+ */
2888
+ getOffsetX() {
2889
+ return this.offsetX_;
2890
+ }
2891
+ /**
2892
+ * Get the y-offset for the text.
2893
+ * @return {number} Vertical text offset.
2894
+ * @api
2895
+ */
2896
+ getOffsetY() {
2897
+ return this.offsetY_;
2898
+ }
2899
+ /**
2900
+ * Get the fill style for the text.
2901
+ * @return {import("./Fill.js").default|null} Fill style.
2902
+ * @api
2903
+ */
2904
+ getFill() {
2905
+ return this.fill_;
2906
+ }
2907
+ /**
2908
+ * Determine whether the text rotates with the map.
2909
+ * @return {boolean|undefined} Rotate with map.
2910
+ * @api
2911
+ */
2912
+ getRotateWithView() {
2913
+ return this.rotateWithView_;
2914
+ }
2915
+ /**
2916
+ * Determine whether the text can be rendered upside down.
2917
+ * @return {boolean|undefined} Keep text upright.
2918
+ * @api
2919
+ */
2920
+ getKeepUpright() {
2921
+ return this.keepUpright_;
2922
+ }
2923
+ /**
2924
+ * Get the text rotation.
2925
+ * @return {number|undefined} Rotation.
2926
+ * @api
2927
+ */
2928
+ getRotation() {
2929
+ return this.rotation_;
2930
+ }
2931
+ /**
2932
+ * Get the text scale.
2933
+ * @return {number|import("../size.js").Size|undefined} Scale.
2934
+ * @api
2935
+ */
2936
+ getScale() {
2937
+ return this.scale_;
2938
+ }
2939
+ /**
2940
+ * Get the symbolizer scale array.
2941
+ * @return {import("../size.js").Size} Scale array.
2942
+ */
2943
+ getScaleArray() {
2944
+ return this.scaleArray_;
2945
+ }
2946
+ /**
2947
+ * Get the stroke style for the text.
2948
+ * @return {import("./Stroke.js").default|null} Stroke style.
2949
+ * @api
2950
+ */
2951
+ getStroke() {
2952
+ return this.stroke_;
2953
+ }
2954
+ /**
2955
+ * Get the text to be rendered.
2956
+ * @return {string|Array<string>|undefined} Text.
2957
+ * @api
2958
+ */
2959
+ getText() {
2960
+ return this.text_;
2961
+ }
2962
+ /**
2963
+ * Get the text alignment.
2964
+ * @return {CanvasTextAlign|undefined} Text align.
2965
+ * @api
2966
+ */
2967
+ getTextAlign() {
2968
+ return this.textAlign_;
2969
+ }
2970
+ /**
2971
+ * Get the justification.
2972
+ * @return {TextJustify|undefined} Justification.
2973
+ * @api
2974
+ */
2975
+ getJustify() {
2976
+ return this.justify_;
2977
+ }
2978
+ /**
2979
+ * Get the text baseline.
2980
+ * @return {CanvasTextBaseline|undefined} Text baseline.
2981
+ * @api
2982
+ */
2983
+ getTextBaseline() {
2984
+ return this.textBaseline_;
2985
+ }
2986
+ /**
2987
+ * Get the background fill style for the text.
2988
+ * @return {import("./Fill.js").default|null} Fill style.
2989
+ * @api
2990
+ */
2991
+ getBackgroundFill() {
2992
+ return this.backgroundFill_;
2993
+ }
2994
+ /**
2995
+ * Get the background stroke style for the text.
2996
+ * @return {import("./Stroke.js").default|null} Stroke style.
2997
+ * @api
2998
+ */
2999
+ getBackgroundStroke() {
3000
+ return this.backgroundStroke_;
3001
+ }
3002
+ /**
3003
+ * Get the padding for the text.
3004
+ * @return {Array<number>|null} Padding.
3005
+ * @api
3006
+ */
3007
+ getPadding() {
3008
+ return this.padding_;
3009
+ }
3010
+ /**
3011
+ * Get the declutter mode of the shape
3012
+ * @return {import("./Style.js").DeclutterMode} Shape's declutter mode
3013
+ * @api
3014
+ */
3015
+ getDeclutterMode() {
3016
+ return this.declutterMode_;
3017
+ }
3018
+ /**
3019
+ * Set the `overflow` property.
3020
+ *
3021
+ * @param {boolean} overflow Let text overflow the path that it follows.
3022
+ * @api
3023
+ */
3024
+ setOverflow(overflow) {
3025
+ this.overflow_ = overflow;
3026
+ }
3027
+ /**
3028
+ * Set the font.
3029
+ *
3030
+ * @param {string|undefined} font Font.
3031
+ * @api
3032
+ */
3033
+ setFont(font) {
3034
+ this.font_ = font;
3035
+ }
3036
+ /**
3037
+ * Set the maximum angle between adjacent characters.
3038
+ *
3039
+ * @param {number} maxAngle Angle in radians.
3040
+ * @api
3041
+ */
3042
+ setMaxAngle(maxAngle) {
3043
+ this.maxAngle_ = maxAngle;
3044
+ }
3045
+ /**
3046
+ * Set the x offset.
3047
+ *
3048
+ * @param {number} offsetX Horizontal text offset.
3049
+ * @api
3050
+ */
3051
+ setOffsetX(offsetX) {
3052
+ this.offsetX_ = offsetX;
3053
+ }
3054
+ /**
3055
+ * Set the y offset.
3056
+ *
3057
+ * @param {number} offsetY Vertical text offset.
3058
+ * @api
3059
+ */
3060
+ setOffsetY(offsetY) {
3061
+ this.offsetY_ = offsetY;
3062
+ }
3063
+ /**
3064
+ * Set the text placement.
3065
+ *
3066
+ * @param {TextPlacement} placement Placement.
3067
+ * @api
3068
+ */
3069
+ setPlacement(placement) {
3070
+ this.placement_ = placement;
3071
+ }
3072
+ /**
3073
+ * Set the repeat interval of the text.
3074
+ * @param {number|undefined} [repeat] Repeat interval in pixels.
3075
+ * @api
3076
+ */
3077
+ setRepeat(repeat) {
3078
+ this.repeat_ = repeat;
3079
+ }
3080
+ /**
3081
+ * Set whether to rotate the text with the view.
3082
+ *
3083
+ * @param {boolean} rotateWithView Rotate with map.
3084
+ * @api
3085
+ */
3086
+ setRotateWithView(rotateWithView) {
3087
+ this.rotateWithView_ = rotateWithView;
3088
+ }
3089
+ /**
3090
+ * Set whether the text can be rendered upside down.
3091
+ *
3092
+ * @param {boolean} keepUpright Keep text upright.
3093
+ * @api
3094
+ */
3095
+ setKeepUpright(keepUpright) {
3096
+ this.keepUpright_ = keepUpright;
3097
+ }
3098
+ /**
3099
+ * Set the fill.
3100
+ *
3101
+ * @param {import("./Fill.js").default|null} fill Fill style.
3102
+ * @api
3103
+ */
3104
+ setFill(fill) {
3105
+ this.fill_ = fill;
3106
+ }
3107
+ /**
3108
+ * Set the rotation.
3109
+ *
3110
+ * @param {number|undefined} rotation Rotation.
3111
+ * @api
3112
+ */
3113
+ setRotation(rotation) {
3114
+ this.rotation_ = rotation;
3115
+ }
3116
+ /**
3117
+ * Set the scale.
3118
+ *
3119
+ * @param {number|import("../size.js").Size|undefined} scale Scale.
3120
+ * @api
3121
+ */
3122
+ setScale(scale2) {
3123
+ this.scale_ = scale2;
3124
+ this.scaleArray_ = toSize(scale2 !== void 0 ? scale2 : 1);
3125
+ }
3126
+ /**
3127
+ * Set the stroke.
3128
+ *
3129
+ * @param {import("./Stroke.js").default|null} stroke Stroke style.
3130
+ * @api
3131
+ */
3132
+ setStroke(stroke) {
3133
+ this.stroke_ = stroke;
3134
+ }
3135
+ /**
3136
+ * Set the text.
3137
+ *
3138
+ * @param {string|Array<string>|undefined} text Text.
3139
+ * @api
3140
+ */
3141
+ setText(text) {
3142
+ this.text_ = text;
3143
+ }
3144
+ /**
3145
+ * Set the text alignment.
3146
+ *
3147
+ * @param {CanvasTextAlign|undefined} textAlign Text align.
3148
+ * @api
3149
+ */
3150
+ setTextAlign(textAlign) {
3151
+ this.textAlign_ = textAlign;
3152
+ }
3153
+ /**
3154
+ * Set the justification.
3155
+ *
3156
+ * @param {TextJustify|undefined} justify Justification.
3157
+ * @api
3158
+ */
3159
+ setJustify(justify) {
3160
+ this.justify_ = justify;
3161
+ }
3162
+ /**
3163
+ * Set the text baseline.
3164
+ *
3165
+ * @param {CanvasTextBaseline|undefined} textBaseline Text baseline.
3166
+ * @api
3167
+ */
3168
+ setTextBaseline(textBaseline) {
3169
+ this.textBaseline_ = textBaseline;
3170
+ }
3171
+ /**
3172
+ * Set the background fill.
3173
+ *
3174
+ * @param {import("./Fill.js").default|null} fill Fill style.
3175
+ * @api
3176
+ */
3177
+ setBackgroundFill(fill) {
3178
+ this.backgroundFill_ = fill;
3179
+ }
3180
+ /**
3181
+ * Set the background stroke.
3182
+ *
3183
+ * @param {import("./Stroke.js").default|null} stroke Stroke style.
3184
+ * @api
3185
+ */
3186
+ setBackgroundStroke(stroke) {
3187
+ this.backgroundStroke_ = stroke;
3188
+ }
3189
+ /**
3190
+ * Set the padding (`[top, right, bottom, left]`).
3191
+ *
3192
+ * @param {Array<number>|null} padding Padding.
3193
+ * @api
3194
+ */
3195
+ setPadding(padding) {
3196
+ this.padding_ = padding;
3197
+ }
3198
+ }
3199
+ export {
3200
+ asArray as $,
3201
+ defaultLineDash as A,
3202
+ defaultLineDashOffset as B,
3203
+ CLASS_UNSELECTABLE as C,
3204
+ DEVICE_PIXEL_RATIO as D,
3205
+ defaultLineJoin as E,
3206
+ Fill as F,
3207
+ defaultLineWidth as G,
3208
+ defaultMiterLimit as H,
3209
+ Icon as I,
3210
+ defaultPadding as J,
3211
+ defaultTextBaseline as K,
3212
+ defaultTextAlign as L,
3213
+ MAC as M,
3214
+ NO_COLOR as N,
3215
+ defaultFont as O,
3216
+ PASSIVE_EVENT_LISTENERS as P,
3217
+ registerFont as Q,
3218
+ RegularShape as R,
3219
+ Style as S,
3220
+ Text as T,
3221
+ getSharedCanvasContext2D as U,
3222
+ getTextDimensions as V,
3223
+ WEBKIT as W,
3224
+ drawImageOrLabel as X,
3225
+ measureAndCacheTextWidth as Y,
3226
+ createCanvasContext2D as Z,
3227
+ ImageState as _,
3228
+ CLASS_CONTROL as a,
3229
+ releaseCanvas as a0,
3230
+ listenImage as a1,
3231
+ scale as a2,
3232
+ CLASS_SELECTABLE as a3,
3233
+ outerWidth as a4,
3234
+ outerHeight as a5,
3235
+ CLASS_COLLAPSED as b,
3236
+ replaceNode as c,
3237
+ CLASS_HIDDEN as d,
3238
+ toString as e,
3239
+ fromString as f,
3240
+ rgbaToLcha as g,
3241
+ Stroke as h,
3242
+ CircleStyle as i,
3243
+ createDefaultStyle as j,
3244
+ toFunction as k,
3245
+ lchaToRgba as l,
3246
+ checkedFonts as m,
3247
+ createMockDiv as n,
3248
+ WORKER_OFFSCREEN_CANVAS as o,
3249
+ replaceChildren as p,
3250
+ isCanvas as q,
3251
+ removeChildren as r,
3252
+ shared as s,
3253
+ toSize as t,
3254
+ hasArea as u,
3255
+ asColorLike as v,
3256
+ withAlpha as w,
3257
+ defaultFillStyle as x,
3258
+ defaultStrokeStyle as y,
3259
+ defaultLineCap as z
3260
+ };