maplibre-gl 3.3.1 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +1 -1
  2. package/dist/maplibre-gl-csp-worker.js +1 -1
  3. package/dist/maplibre-gl-csp-worker.js.map +1 -1
  4. package/dist/maplibre-gl-csp.js +1 -1
  5. package/dist/maplibre-gl-csp.js.map +1 -1
  6. package/dist/maplibre-gl-dev.js +430 -128
  7. package/dist/maplibre-gl-dev.js.map +1 -1
  8. package/dist/maplibre-gl.d.ts +18 -9
  9. package/dist/maplibre-gl.js +4 -4
  10. package/dist/maplibre-gl.js.map +1 -1
  11. package/package.json +41 -41
  12. package/src/data/dem_data.test.ts +120 -165
  13. package/src/data/dem_data.ts +38 -18
  14. package/src/render/glyph_manager.test.ts +10 -9
  15. package/src/render/glyph_manager.ts +17 -10
  16. package/src/source/image_source.test.ts +17 -24
  17. package/src/source/raster_dem_tile_source.ts +36 -11
  18. package/src/source/raster_dem_tile_worker_source.ts +9 -26
  19. package/src/source/raster_tile_source.test.ts +1 -1
  20. package/src/source/raster_tile_source.ts +1 -1
  21. package/src/source/terrain_source_cache.test.ts +1 -1
  22. package/src/source/vector_tile_source.test.ts +1 -1
  23. package/src/source/vector_tile_worker_source.test.ts +45 -1
  24. package/src/source/vector_tile_worker_source.ts +19 -6
  25. package/src/source/worker_source.ts +6 -2
  26. package/src/style/load_glyph_range.test.ts +6 -8
  27. package/src/style/load_sprite.test.ts +48 -71
  28. package/src/style/style.test.ts +19 -49
  29. package/src/style/style.ts +3 -0
  30. package/src/style/style_glyph.ts +4 -3
  31. package/src/style/style_layer/line_style_layer.test.ts +50 -0
  32. package/src/style/style_layer/line_style_layer.ts +8 -4
  33. package/src/symbol/quads.ts +4 -2
  34. package/src/ui/handler/scroll_zoom.ts +6 -0
  35. package/src/ui/handler_manager.ts +2 -1
  36. package/src/ui/map.test.ts +17 -0
  37. package/src/ui/map.ts +1 -0
  38. package/src/ui/marker.test.ts +25 -0
  39. package/src/ui/marker.ts +8 -1
  40. package/src/util/ajax.test.ts +1 -1
  41. package/src/util/image_request.test.ts +1 -1
  42. package/src/util/offscreen_canvas_distorted.test.ts +13 -0
  43. package/src/util/offscreen_canvas_distorted.ts +39 -0
  44. package/src/util/test/util.ts +12 -0
  45. package/src/util/util.test.ts +171 -1
  46. package/src/util/util.ts +150 -0
@@ -1,4 +1,4 @@
1
- /* MapLibre GL JS is licensed under the 3-Clause BSD License. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v3.3.1/LICENSE.txt */
1
+ /* MapLibre GL JS is licensed under the 3-Clause BSD License. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v3.4.1/LICENSE.txt */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4
4
  typeof define === 'function' && define.amd ? define(factory) :
@@ -465,6 +465,52 @@ UnitBezier.prototype = {
465
465
 
466
466
  var UnitBezier$1 = /*@__PURE__*/getDefaultExportFromCjs(unitbezier);
467
467
 
468
+ let supportsOffscreenCanvas;
469
+ function offscreenCanvasSupported() {
470
+ if (supportsOffscreenCanvas == null) {
471
+ supportsOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' &&
472
+ new OffscreenCanvas(1, 1).getContext('2d') &&
473
+ typeof createImageBitmap === 'function';
474
+ }
475
+ return supportsOffscreenCanvas;
476
+ }
477
+
478
+ let offscreenCanvasDistorted;
479
+ /**
480
+ * Some browsers don't return the exact pixels from a canvas to prevent user fingerprinting (see #3185).
481
+ * This function writes pixels to an OffscreenCanvas and reads them back using getImageData, returning false
482
+ * if they don't match.
483
+ *
484
+ * @returns true if the browser supports OffscreenCanvas but it distorts getImageData results, false otherwise.
485
+ */
486
+ function isOffscreenCanvasDistorted() {
487
+ if (offscreenCanvasDistorted == null) {
488
+ offscreenCanvasDistorted = false;
489
+ if (offscreenCanvasSupported()) {
490
+ const size = 5;
491
+ const canvas = new OffscreenCanvas(size, size);
492
+ const context = canvas.getContext('2d', { willReadFrequently: true });
493
+ if (context) {
494
+ // fill each pixel with an RGB value that should make the byte at index i equal to i (except alpha channel):
495
+ // [0, 1, 2, 255, 4, 5, 6, 255, 8, 9, 10, 255, ...]
496
+ for (let i = 0; i < size * size; i++) {
497
+ const base = i * 4;
498
+ context.fillStyle = `rgb(${base},${base + 1},${base + 2})`;
499
+ context.fillRect(i % size, Math.floor(i / size), 1, 1);
500
+ }
501
+ const data = context.getImageData(0, 0, size, size).data;
502
+ for (let i = 0; i < size * size * 4; i++) {
503
+ if (i % 4 !== 3 && data[i] !== i) {
504
+ offscreenCanvasDistorted = true;
505
+ break;
506
+ }
507
+ }
508
+ }
509
+ }
510
+ }
511
+ return offscreenCanvasDistorted || false;
512
+ }
513
+
468
514
  /**
469
515
  * Given a value `t` that varies between 0 and 1, return
470
516
  * an interpolation function that eases between 0 and 1 in a pleasing
@@ -934,6 +980,139 @@ function arrayBufferToImage(data, callback) {
934
980
  const blob = new Blob([new Uint8Array(data)], { type: 'image/png' });
935
981
  img.src = data.byteLength ? URL.createObjectURL(blob) : transparentPngUrl;
936
982
  }
983
+ /**
984
+ * Computes the webcodecs VideoFrame API options to select a rectangle out of
985
+ * an image and write it into the destination rectangle.
986
+ *
987
+ * Rect (x/y/width/height) select the overlapping rectangle from the source image
988
+ * and layout (offset/stride) write that overlapping rectangle to the correct place
989
+ * in the destination image.
990
+ *
991
+ * Offset is the byte offset in the dest image that the first pixel appears at
992
+ * and stride is the number of bytes to the start of the next row:
993
+ * ┌───────────┐
994
+ * │ dest │
995
+ * │ ┌───┼───────┐
996
+ * │offset→│▓▓▓│ source│
997
+ * │ │▓▓▓│ │
998
+ * │ └───┼───────┘
999
+ * │stride ⇠╌╌╌│
1000
+ * │╌╌╌╌╌╌→ │
1001
+ * └───────────┘
1002
+ *
1003
+ * @param image - source image containing a width and height attribute
1004
+ * @param x - top-left x coordinate to read from the image
1005
+ * @param y - top-left y coordinate to read from the image
1006
+ * @param width - width of the rectangle to read from the image
1007
+ * @param height - height of the rectangle to read from the image
1008
+ * @returns the layout and rect options to pass into VideoFrame API
1009
+ */
1010
+ function computeVideoFrameParameters(image, x, y, width, height) {
1011
+ const destRowOffset = Math.max(-x, 0) * 4;
1012
+ const firstSourceRow = Math.max(0, y);
1013
+ const firstDestRow = firstSourceRow - y;
1014
+ const offset = firstDestRow * width * 4 + destRowOffset;
1015
+ const stride = width * 4;
1016
+ const sourceLeft = Math.max(0, x);
1017
+ const sourceTop = Math.max(0, y);
1018
+ const sourceRight = Math.min(image.width, x + width);
1019
+ const sourceBottom = Math.min(image.height, y + height);
1020
+ return {
1021
+ rect: {
1022
+ x: sourceLeft,
1023
+ y: sourceTop,
1024
+ width: sourceRight - sourceLeft,
1025
+ height: sourceBottom - sourceTop
1026
+ },
1027
+ layout: [{ offset, stride }]
1028
+ };
1029
+ }
1030
+ /**
1031
+ * Reads pixels from an ImageBitmap/Image/canvas using webcodec VideoFrame API.
1032
+ *
1033
+ * @param data - image, imagebitmap, or canvas to parse
1034
+ * @param x - top-left x coordinate to read from the image
1035
+ * @param y - top-left y coordinate to read from the image
1036
+ * @param width - width of the rectangle to read from the image
1037
+ * @param height - height of the rectangle to read from the image
1038
+ * @returns a promise containing the parsed RGBA pixel values of the image, or the error if an error occurred
1039
+ */
1040
+ async function readImageUsingVideoFrame(image, x, y, width, height) {
1041
+ if (typeof VideoFrame === 'undefined') {
1042
+ throw new Error('VideoFrame not supported');
1043
+ }
1044
+ const frame = new VideoFrame(image, { timestamp: 0 });
1045
+ try {
1046
+ const format = frame === null || frame === void 0 ? void 0 : frame.format;
1047
+ if (!format || !(format.startsWith('BGR') || format.startsWith('RGB'))) {
1048
+ throw new Error(`Unrecognized format ${format}`);
1049
+ }
1050
+ const swapBR = format.startsWith('BGR');
1051
+ const result = new Uint8ClampedArray(width * height * 4);
1052
+ await frame.copyTo(result, computeVideoFrameParameters(image, x, y, width, height));
1053
+ if (swapBR) {
1054
+ for (let i = 0; i < result.length; i += 4) {
1055
+ const tmp = result[i];
1056
+ result[i] = result[i + 2];
1057
+ result[i + 2] = tmp;
1058
+ }
1059
+ }
1060
+ return result;
1061
+ }
1062
+ finally {
1063
+ frame.close();
1064
+ }
1065
+ }
1066
+ let offscreenCanvas;
1067
+ let offscreenCanvasContext;
1068
+ /**
1069
+ * Reads pixels from an ImageBitmap/Image/canvas using OffscreenCanvas
1070
+ *
1071
+ * @param data - image, imagebitmap, or canvas to parse
1072
+ * @param x - top-left x coordinate to read from the image
1073
+ * @param y - top-left y coordinate to read from the image
1074
+ * @param width - width of the rectangle to read from the image
1075
+ * @param height - height of the rectangle to read from the image
1076
+ * @returns a promise containing the parsed RGBA pixel values of the image, or the error if an error occurred
1077
+ */
1078
+ function readImageDataUsingOffscreenCanvas(imgBitmap, x, y, width, height) {
1079
+ const origWidth = imgBitmap.width;
1080
+ const origHeight = imgBitmap.height;
1081
+ // Lazily initialize OffscreenCanvas
1082
+ if (!offscreenCanvas || !offscreenCanvasContext) {
1083
+ // Dem tiles are typically 256x256
1084
+ offscreenCanvas = new OffscreenCanvas(origWidth, origHeight);
1085
+ offscreenCanvasContext = offscreenCanvas.getContext('2d', { willReadFrequently: true });
1086
+ }
1087
+ offscreenCanvas.width = origWidth;
1088
+ offscreenCanvas.height = origHeight;
1089
+ offscreenCanvasContext.drawImage(imgBitmap, 0, 0, origWidth, origHeight);
1090
+ const imgData = offscreenCanvasContext.getImageData(x, y, width, height);
1091
+ offscreenCanvasContext.clearRect(0, 0, origWidth, origHeight);
1092
+ return imgData.data;
1093
+ }
1094
+ /**
1095
+ * Reads RGBA pixels from an preferring OffscreenCanvas, but falling back to VideoFrame if supported and
1096
+ * the browser is mangling OffscreenCanvas getImageData results.
1097
+ *
1098
+ * @param data - image, imagebitmap, or canvas to parse
1099
+ * @param x - top-left x coordinate to read from the image
1100
+ * @param y - top-left y coordinate to read from the image
1101
+ * @param width - width of the rectangle to read from the image
1102
+ * @param height - height of the rectangle to read from the image
1103
+ * @returns a promise containing the parsed RGBA pixel values of the image
1104
+ */
1105
+ async function getImageData(image, x, y, width, height) {
1106
+ if (isOffscreenCanvasDistorted()) {
1107
+ try {
1108
+ return await readImageUsingVideoFrame(image, x, y, width, height);
1109
+ }
1110
+ catch (e) {
1111
+ // fall back to OffscreenCanvas
1112
+ }
1113
+ }
1114
+ return readImageDataUsingOffscreenCanvas(image, x, y, width, height);
1115
+ }
937
1116
 
938
1117
  const now = typeof performance !== 'undefined' && performance && performance.now ?
939
1118
  performance.now.bind(performance) :
@@ -1577,10 +1756,28 @@ var source_raster_dem = {
1577
1756
  terrarium: {
1578
1757
  },
1579
1758
  mapbox: {
1759
+ },
1760
+ custom: {
1580
1761
  }
1581
1762
  },
1582
1763
  "default": "mapbox"
1583
1764
  },
1765
+ redFactor: {
1766
+ type: "number",
1767
+ "default": 1
1768
+ },
1769
+ blueFactor: {
1770
+ type: "number",
1771
+ "default": 1
1772
+ },
1773
+ greenFactor: {
1774
+ type: "number",
1775
+ "default": 1
1776
+ },
1777
+ baseShift: {
1778
+ type: "number",
1779
+ "default": 0
1780
+ },
1584
1781
  volatile: {
1585
1782
  type: "boolean",
1586
1783
  "default": false
@@ -8878,6 +9075,9 @@ class ZoomDependentExpression {
8878
9075
  }
8879
9076
  }
8880
9077
  }
9078
+ function isZoomExpression(expression) {
9079
+ return expression._styleExpression !== undefined;
9080
+ }
8881
9081
  function createPropertyExpression(expressionInput, propertySpec) {
8882
9082
  const expression = createExpression(expressionInput, propertySpec);
8883
9083
  if (expression.result === 'error') {
@@ -10392,6 +10592,9 @@ function validateLayer(options) {
10392
10592
  else if (sourceType === 'vector' && type === 'raster') {
10393
10593
  errors.push(new ValidationError(key, layer.source, `layer "${layer.id}" requires a raster source`));
10394
10594
  }
10595
+ else if (sourceType !== 'raster-dem' && type === 'hillshade') {
10596
+ errors.push(new ValidationError(key, layer.source, `layer "${layer.id}" requires a raster-dem source`));
10597
+ }
10395
10598
  else if (sourceType === 'raster' && type !== 'raster') {
10396
10599
  errors.push(new ValidationError(key, layer.source, `layer "${layer.id}" requires a vector source`));
10397
10600
  }
@@ -10478,6 +10681,47 @@ function validateString(options) {
10478
10681
  return [];
10479
10682
  }
10480
10683
 
10684
+ function validateRasterDEMSource(options) {
10685
+ var _a;
10686
+ const sourceName = (_a = options.sourceName) !== null && _a !== void 0 ? _a : '';
10687
+ const rasterDEM = options.value;
10688
+ const styleSpec = options.styleSpec;
10689
+ const rasterDEMSpec = styleSpec.source_raster_dem;
10690
+ const style = options.style;
10691
+ let errors = [];
10692
+ const rootType = getType(rasterDEM);
10693
+ if (rasterDEM === undefined) {
10694
+ return errors;
10695
+ }
10696
+ else if (rootType !== 'object') {
10697
+ errors.push(new ValidationError('source_raster_dem', rasterDEM, `object expected, ${rootType} found`));
10698
+ return errors;
10699
+ }
10700
+ const encoding = unbundle(rasterDEM.encoding);
10701
+ const isCustomEncoding = encoding === 'custom';
10702
+ const customEncodingKeys = ['redFactor', 'greenFactor', 'blueFactor', 'baseShift'];
10703
+ const encodingName = options.value.encoding ? `"${options.value.encoding}"` : 'Default';
10704
+ for (const key in rasterDEM) {
10705
+ if (!isCustomEncoding && customEncodingKeys.includes(key)) {
10706
+ errors.push(new ValidationError(key, rasterDEM[key], `In "${sourceName}": "${key}" is only valid when "encoding" is set to "custom". ${encodingName} encoding found`));
10707
+ }
10708
+ else if (rasterDEMSpec[key]) {
10709
+ errors = errors.concat(options.validateSpec({
10710
+ key,
10711
+ value: rasterDEM[key],
10712
+ valueSpec: rasterDEMSpec[key],
10713
+ validateSpec: options.validateSpec,
10714
+ style,
10715
+ styleSpec
10716
+ }));
10717
+ }
10718
+ else {
10719
+ errors.push(new ValidationError(key, rasterDEM[key], `unknown property "${key}"`));
10720
+ }
10721
+ }
10722
+ return errors;
10723
+ }
10724
+
10481
10725
  const objectElementValidators = {
10482
10726
  promoteId: validatePromoteId
10483
10727
  };
@@ -10495,7 +10739,6 @@ function validateSource$1(options) {
10495
10739
  switch (type) {
10496
10740
  case 'vector':
10497
10741
  case 'raster':
10498
- case 'raster-dem':
10499
10742
  errors = validateObject({
10500
10743
  key,
10501
10744
  value,
@@ -10506,6 +10749,15 @@ function validateSource$1(options) {
10506
10749
  validateSpec,
10507
10750
  });
10508
10751
  return errors;
10752
+ case 'raster-dem':
10753
+ errors = validateRasterDEMSource({
10754
+ sourceName: key,
10755
+ value,
10756
+ style: options.style,
10757
+ styleSpec,
10758
+ validateSpec,
10759
+ });
10760
+ return errors;
10509
10761
  case 'geojson':
10510
10762
  errors = validateObject({
10511
10763
  key,
@@ -10922,6 +11174,7 @@ const expression = {
10922
11174
  createPropertyExpression,
10923
11175
  isExpression,
10924
11176
  isExpressionFilter,
11177
+ isZoomExpression,
10925
11178
  normalizePropertyExpression,
10926
11179
  };
10927
11180
  const styleFunction = {
@@ -25473,8 +25726,13 @@ class LineStyleLayer extends StyleLayer {
25473
25726
  }
25474
25727
  _handleSpecialPaintPropertyUpdate(name) {
25475
25728
  if (name === 'line-gradient') {
25476
- const expression = this._transitionablePaint._values['line-gradient'].value.expression;
25477
- this.stepInterpolant = expression._styleExpression.expression instanceof Step;
25729
+ const expression = this.gradientExpression();
25730
+ if (isZoomExpression(expression)) {
25731
+ this.stepInterpolant = expression._styleExpression.expression instanceof Step;
25732
+ }
25733
+ else {
25734
+ this.stepInterpolant = false;
25735
+ }
25478
25736
  this.gradientVersion = (this.gradientVersion + 1) % Number.MAX_SAFE_INTEGER;
25479
25737
  }
25480
25738
  }
@@ -29150,29 +29408,45 @@ function getQuadkey(z, x, y) {
29150
29408
  register('CanonicalTileID', CanonicalTileID);
29151
29409
  register('OverscaledTileID', OverscaledTileID, { omit: ['posMatrix'] });
29152
29410
 
29153
- // DEMData is a data structure for decoding, backfilling, and storing elevation data for processing in the hillshade shaders
29154
- // data can be populated either from a pngraw image tile or from serliazed data sent back from a worker. When data is initially
29155
- // loaded from a image tile, we decode the pixel values using the appropriate decoding formula, but we store the
29156
- // elevation data as an Int32 value. we add 65536 (2^16) to eliminate negative values and enable the use of
29157
- // integer overflow when creating the texture used in the hillshadePrepare step.
29158
- // DEMData also handles the backfilling of data from a tile's neighboring tiles. This is necessary because we use a pixel's 8
29159
- // surrounding pixel values to compute the slope at that pixel, and we cannot accurately calculate the slope at pixels on a
29160
- // tile's edge without backfilling from neighboring tiles.
29161
29411
  class DEMData {
29162
29412
  // RGBAImage data has uniform 1px padding on all sides: square tile edge size defines stride
29163
29413
  // and dim is calculated as stride - 2.
29164
- constructor(uid, data, encoding) {
29414
+ constructor(uid, data, encoding, redFactor = 1.0, greenFactor = 1.0, blueFactor = 1.0, baseShift = 0.0) {
29165
29415
  this.uid = uid;
29166
29416
  if (data.height !== data.width)
29167
29417
  throw new RangeError('DEM tiles must be square');
29168
- if (encoding && encoding !== 'mapbox' && encoding !== 'terrarium') {
29169
- warnOnce(`"${encoding}" is not a valid encoding type. Valid types include "mapbox" and "terrarium".`);
29418
+ if (encoding && !['mapbox', 'terrarium', 'custom'].includes(encoding)) {
29419
+ warnOnce(`"${encoding}" is not a valid encoding type. Valid types include "mapbox", "terrarium" and "custom".`);
29170
29420
  return;
29171
29421
  }
29172
29422
  this.stride = data.height;
29173
29423
  const dim = this.dim = data.height - 2;
29174
29424
  this.data = new Uint32Array(data.data.buffer);
29175
- this.encoding = encoding || 'mapbox';
29425
+ switch (encoding) {
29426
+ case 'terrarium':
29427
+ // unpacking formula for mapzen terrarium:
29428
+ // https://aws.amazon.com/public-datasets/terrain/
29429
+ this.redFactor = 256.0;
29430
+ this.greenFactor = 1.0;
29431
+ this.blueFactor = 1.0 / 256.0;
29432
+ this.baseShift = 32768.0;
29433
+ break;
29434
+ case 'custom':
29435
+ this.redFactor = redFactor;
29436
+ this.greenFactor = greenFactor;
29437
+ this.blueFactor = blueFactor;
29438
+ this.baseShift = baseShift;
29439
+ break;
29440
+ case 'mapbox':
29441
+ default:
29442
+ // unpacking formula for mapbox.terrain-rgb:
29443
+ // https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb
29444
+ this.redFactor = 6553.6;
29445
+ this.greenFactor = 25.6;
29446
+ this.blueFactor = 0.1;
29447
+ this.baseShift = 10000.0;
29448
+ break;
29449
+ }
29176
29450
  // in order to avoid flashing seams between tiles, here we are initially populating a 1px border of pixels around the image
29177
29451
  // with the data of the nearest pixel from the image. this data is eventually replaced when the tile's neighboring
29178
29452
  // tiles are loaded and the accurate data can be backfilled using DEMData#backfillBorder
@@ -29207,26 +29481,18 @@ class DEMData {
29207
29481
  get(x, y) {
29208
29482
  const pixels = new Uint8Array(this.data.buffer);
29209
29483
  const index = this._idx(x, y) * 4;
29210
- const unpack = this.encoding === 'terrarium' ? this._unpackTerrarium : this._unpackMapbox;
29211
- return unpack(pixels[index], pixels[index + 1], pixels[index + 2]);
29484
+ return this.unpack(pixels[index], pixels[index + 1], pixels[index + 2]);
29212
29485
  }
29213
29486
  getUnpackVector() {
29214
- return this.encoding === 'terrarium' ? [256.0, 1.0, 1.0 / 256.0, 32768.0] : [6553.6, 25.6, 0.1, 10000.0];
29487
+ return [this.redFactor, this.greenFactor, this.blueFactor, this.baseShift];
29215
29488
  }
29216
29489
  _idx(x, y) {
29217
29490
  if (x < -1 || x >= this.dim + 1 || y < -1 || y >= this.dim + 1)
29218
29491
  throw new RangeError('out of range source coordinates for DEM data');
29219
29492
  return (y + 1) * this.stride + (x + 1);
29220
29493
  }
29221
- _unpackMapbox(r, g, b) {
29222
- // unpacking formula for mapbox.terrain-rgb:
29223
- // https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb
29224
- return ((r * 256 * 256 + g * 256.0 + b) / 10.0 - 10000.0);
29225
- }
29226
- _unpackTerrarium(r, g, b) {
29227
- // unpacking formula for mapzen terrarium:
29228
- // https://aws.amazon.com/public-datasets/terrain/
29229
- return ((r * 256 + g + b / 256) - 32768.0);
29494
+ unpack(r, g, b) {
29495
+ return (r * this.redFactor + g * this.greenFactor + b * this.blueFactor - this.baseShift);
29230
29496
  }
29231
29497
  getPixels() {
29232
29498
  return new RGBAImage({ width: this.stride, height: this.stride }, new Uint8Array(this.data.buffer));
@@ -29911,10 +30177,11 @@ function getGlyphQuads(anchor, shaping, textOffset, layer, alongLine, feature, i
29911
30177
  verticalizedLabelOffset = builtInOffset;
29912
30178
  builtInOffset = [0, 0];
29913
30179
  }
30180
+ const textureScale = positionedGlyph.metrics.isDoubleResolution ? 2 : 1;
29914
30181
  const x1 = (positionedGlyph.metrics.left - rectBuffer) * positionedGlyph.scale - halfAdvance + builtInOffset[0];
29915
30182
  const y1 = (-positionedGlyph.metrics.top - rectBuffer) * positionedGlyph.scale + builtInOffset[1];
29916
- const x2 = x1 + textureRect.w * positionedGlyph.scale / pixelRatio;
29917
- const y2 = y1 + textureRect.h * positionedGlyph.scale / pixelRatio;
30183
+ const x2 = x1 + textureRect.w / textureScale * positionedGlyph.scale / pixelRatio;
30184
+ const y2 = y1 + textureRect.h / textureScale * positionedGlyph.scale / pixelRatio;
29918
30185
  const tl = new Point$2(x1, y1);
29919
30186
  const tr = new Point$2(x2, y1);
29920
30187
  const bl = new Point$2(x1, y2);
@@ -31316,6 +31583,7 @@ exports.getAnchorAlignment = getAnchorAlignment;
31316
31583
  exports.getAnchorJustification = getAnchorJustification;
31317
31584
  exports.getArrayBuffer = getArrayBuffer;
31318
31585
  exports.getDefaultExportFromCjs = getDefaultExportFromCjs;
31586
+ exports.getImageData = getImageData;
31319
31587
  exports.getJSON = getJSON;
31320
31588
  exports.getOverlapMode = getOverlapMode;
31321
31589
  exports.getProtocolAction = getProtocolAction;
@@ -31327,6 +31595,7 @@ exports.identity = identity$2;
31327
31595
  exports.interpolate = interpolate;
31328
31596
  exports.invert = invert$2;
31329
31597
  exports.isImageBitmap = isImageBitmap;
31598
+ exports.isOffscreenCanvasDistorted = isOffscreenCanvasDistorted;
31330
31599
  exports.isSafari = isSafari;
31331
31600
  exports.isWorker = isWorker;
31332
31601
  exports.keysDifference = keysDifference;
@@ -31341,6 +31610,7 @@ exports.mul$1 = mul$3;
31341
31610
  exports.multiply = multiply$5;
31342
31611
  exports.nextPowerOfTwo = nextPowerOfTwo;
31343
31612
  exports.normalize = normalize$4;
31613
+ exports.offscreenCanvasSupported = offscreenCanvasSupported;
31344
31614
  exports.operations = operations;
31345
31615
  exports.ortho = ortho;
31346
31616
  exports.parseCacheControl = parseCacheControl;
@@ -31353,6 +31623,7 @@ exports.plugin = plugin;
31353
31623
  exports.pointGeometry = pointGeometry;
31354
31624
  exports.polygonIntersectsPolygon = polygonIntersectsPolygon;
31355
31625
  exports.potpack = potpack;
31626
+ exports.readImageUsingVideoFrame = readImageUsingVideoFrame;
31356
31627
  exports.register = register;
31357
31628
  exports.registerForPluginStateChange = registerForPluginStateChange;
31358
31629
  exports.renderColorRamp = renderColorRamp;
@@ -31667,12 +31938,27 @@ function loadVectorTile(params, callback) {
31667
31938
  callback(err);
31668
31939
  }
31669
31940
  else if (data) {
31670
- callback(null, {
31671
- vectorTile: new performance.vectorTile.VectorTile(new performance.Protobuf(data)),
31672
- rawData: data,
31673
- cacheControl,
31674
- expires
31675
- });
31941
+ try {
31942
+ const vectorTile = new performance.vectorTile.VectorTile(new performance.Protobuf(data));
31943
+ callback(null, {
31944
+ vectorTile,
31945
+ rawData: data,
31946
+ cacheControl,
31947
+ expires
31948
+ });
31949
+ }
31950
+ catch (ex) {
31951
+ const bytes = new Uint8Array(data);
31952
+ const isGzipped = bytes[0] === 0x1f && bytes[1] === 0x8b;
31953
+ let errorMessage = `Unable to parse the tile at ${params.request.url}, `;
31954
+ if (isGzipped) {
31955
+ errorMessage += 'please make sure the data is not gzipped and that you have configured the relevant header in the server';
31956
+ }
31957
+ else {
31958
+ errorMessage += `got error: ${ex.messge}`;
31959
+ }
31960
+ callback(new Error(errorMessage));
31961
+ }
31676
31962
  }
31677
31963
  });
31678
31964
  return () => {
@@ -31820,30 +32106,18 @@ class RasterDEMTileWorkerSource {
31820
32106
  constructor() {
31821
32107
  this.loaded = {};
31822
32108
  }
31823
- loadTile(params, callback) {
31824
- const { uid, encoding, rawImageData } = params;
31825
- // Main thread will transfer ImageBitmap if offscreen decode with OffscreenCanvas is supported, else it will transfer an already decoded image.
31826
- const imagePixels = performance.isImageBitmap(rawImageData) ? this.getImageData(rawImageData) : rawImageData;
31827
- const dem = new performance.DEMData(uid, imagePixels, encoding);
32109
+ async loadTile(params, callback) {
32110
+ const { uid, encoding, rawImageData, redFactor, greenFactor, blueFactor, baseShift } = params;
32111
+ const width = rawImageData.width + 2;
32112
+ const height = rawImageData.height + 2;
32113
+ const imagePixels = performance.isImageBitmap(rawImageData) ?
32114
+ new performance.RGBAImage({ width, height }, await performance.getImageData(rawImageData, -1, -1, width, height)) :
32115
+ rawImageData;
32116
+ const dem = new performance.DEMData(uid, imagePixels, encoding, redFactor, greenFactor, blueFactor, baseShift);
31828
32117
  this.loaded = this.loaded || {};
31829
32118
  this.loaded[uid] = dem;
31830
32119
  callback(null, dem);
31831
32120
  }
31832
- getImageData(imgBitmap) {
31833
- // Lazily initialize OffscreenCanvas
31834
- if (!this.offscreenCanvas || !this.offscreenCanvasContext) {
31835
- // Dem tiles are typically 256x256
31836
- this.offscreenCanvas = new OffscreenCanvas(imgBitmap.width, imgBitmap.height);
31837
- this.offscreenCanvasContext = this.offscreenCanvas.getContext('2d', { willReadFrequently: true });
31838
- }
31839
- this.offscreenCanvas.width = imgBitmap.width;
31840
- this.offscreenCanvas.height = imgBitmap.height;
31841
- this.offscreenCanvasContext.drawImage(imgBitmap, 0, 0, imgBitmap.width, imgBitmap.height);
31842
- // Insert an additional 1px padding around the image to allow backfilling for neighboring data.
31843
- const imgData = this.offscreenCanvasContext.getImageData(-1, -1, imgBitmap.width + 2, imgBitmap.height + 2);
31844
- this.offscreenCanvasContext.clearRect(0, 0, this.offscreenCanvas.width, this.offscreenCanvas.height);
31845
- return new performance.RGBAImage({ width: imgData.width, height: imgData.height }, imgData.data);
31846
- }
31847
32121
  removeTile(params) {
31848
32122
  const loaded = this.loaded, uid = params.uid;
31849
32123
  if (loaded && loaded[uid]) {
@@ -34029,7 +34303,7 @@ define(['./shared'], (function (performance) { 'use strict';
34029
34303
 
34030
34304
  var name = "maplibre-gl";
34031
34305
  var description = "BSD licensed community fork of mapbox-gl, a WebGL interactive maps library";
34032
- var version$2 = "3.3.1";
34306
+ var version$2 = "3.4.1";
34033
34307
  var main = "dist/maplibre-gl.js";
34034
34308
  var style = "dist/maplibre-gl.css";
34035
34309
  var license = "BSD-3-Clause";
@@ -34048,12 +34322,12 @@ var dependencies = {
34048
34322
  "@mapbox/unitbezier": "^0.0.1",
34049
34323
  "@mapbox/vector-tile": "^1.3.1",
34050
34324
  "@mapbox/whoots-js": "^3.1.0",
34051
- "@maplibre/maplibre-gl-style-spec": "^19.3.0",
34052
- "@types/geojson": "^7946.0.10",
34325
+ "@maplibre/maplibre-gl-style-spec": "^19.3.2",
34326
+ "@types/geojson": "^7946.0.11",
34053
34327
  "@types/mapbox__point-geometry": "^0.1.2",
34054
- "@types/mapbox__vector-tile": "^1.3.0",
34055
- "@types/pbf": "^3.0.2",
34056
- "@types/supercluster": "^7.1.0",
34328
+ "@types/mapbox__vector-tile": "^1.3.1",
34329
+ "@types/pbf": "^3.0.3",
34330
+ "@types/supercluster": "^7.1.1",
34057
34331
  earcut: "^2.2.4",
34058
34332
  "geojson-vt": "^3.2.1",
34059
34333
  "gl-matrix": "^3.4.3",
@@ -34070,56 +34344,56 @@ var dependencies = {
34070
34344
  var devDependencies = {
34071
34345
  "@mapbox/mapbox-gl-rtl-text": "^0.2.3",
34072
34346
  "@mapbox/mvt-fixtures": "^3.10.0",
34073
- "@rollup/plugin-commonjs": "^25.0.4",
34074
- "@rollup/plugin-json": "^6.0.0",
34075
- "@rollup/plugin-node-resolve": "^15.2.1",
34076
- "@rollup/plugin-replace": "^5.0.2",
34077
- "@rollup/plugin-strip": "^3.0.2",
34078
- "@rollup/plugin-terser": "^0.4.3",
34079
- "@rollup/plugin-typescript": "^11.1.3",
34080
- "@types/benchmark": "^2.1.2",
34347
+ "@rollup/plugin-commonjs": "^25.0.5",
34348
+ "@rollup/plugin-json": "^6.0.1",
34349
+ "@rollup/plugin-node-resolve": "^15.2.3",
34350
+ "@rollup/plugin-replace": "^5.0.3",
34351
+ "@rollup/plugin-strip": "^3.0.3",
34352
+ "@rollup/plugin-terser": "^0.4.4",
34353
+ "@rollup/plugin-typescript": "^11.1.5",
34354
+ "@types/benchmark": "^2.1.3",
34081
34355
  "@types/cssnano": "^5.0.0",
34082
- "@types/d3": "^7.4.0",
34083
- "@types/diff": "^5.0.3",
34084
- "@types/earcut": "^2.1.1",
34085
- "@types/eslint": "^8.44.2",
34086
- "@types/gl": "^6.0.2",
34356
+ "@types/d3": "^7.4.1",
34357
+ "@types/diff": "^5.0.5",
34358
+ "@types/earcut": "^2.1.2",
34359
+ "@types/eslint": "^8.44.3",
34360
+ "@types/gl": "^6.0.3",
34087
34361
  "@types/glob": "^8.1.0",
34088
34362
  "@types/jest": "^29.5.3",
34089
- "@types/jsdom": "^21.1.2",
34090
- "@types/minimist": "^1.2.2",
34363
+ "@types/jsdom": "^21.1.3",
34364
+ "@types/minimist": "^1.2.3",
34091
34365
  "@types/murmurhash-js": "^1.0.4",
34092
- "@types/nise": "^1.4.1",
34093
- "@types/node": "^20.5.7",
34094
- "@types/offscreencanvas": "^2019.7.0",
34366
+ "@types/nise": "^1.4.2",
34367
+ "@types/node": "^20.8.3",
34368
+ "@types/offscreencanvas": "^2019.7.1",
34095
34369
  "@types/pixelmatch": "^5.2.4",
34096
- "@types/pngjs": "^6.0.1",
34097
- "@types/react": "^18.2.21",
34098
- "@types/react-dom": "^18.2.7",
34099
- "@types/request": "^2.48.8",
34370
+ "@types/pngjs": "^6.0.2",
34371
+ "@types/react": "^18.2.25",
34372
+ "@types/react-dom": "^18.2.11",
34373
+ "@types/request": "^2.48.9",
34100
34374
  "@types/shuffle-seed": "^1.1.0",
34101
34375
  "@types/window-or-global": "^1.0.4",
34102
- "@typescript-eslint/eslint-plugin": "^6.4.1",
34103
- "@typescript-eslint/parser": "^6.4.1",
34104
- address: "^1.2.2",
34376
+ "@typescript-eslint/eslint-plugin": "^6.7.4",
34377
+ "@typescript-eslint/parser": "^6.7.4",
34378
+ address: "^2.0.1",
34105
34379
  benchmark: "^2.1.4",
34106
34380
  canvas: "^2.11.2",
34107
34381
  cssnano: "^6.0.1",
34108
34382
  d3: "^7.8.5",
34109
34383
  "d3-queue": "^3.0.7",
34110
- "devtools-protocol": "^0.0.1188743",
34384
+ "devtools-protocol": "^0.0.1206220",
34111
34385
  diff: "^5.1.0",
34112
34386
  "dts-bundle-generator": "^8.0.1",
34113
- eslint: "^8.48.0",
34387
+ eslint: "^8.51.0",
34114
34388
  "eslint-config-mourner": "^3.0.0",
34115
34389
  "eslint-plugin-html": "^7.1.0",
34116
34390
  "eslint-plugin-import": "^2.28.1",
34117
- "eslint-plugin-jest": "^27.2.3",
34391
+ "eslint-plugin-jest": "^27.4.2",
34118
34392
  "eslint-plugin-react": "^7.33.2",
34119
34393
  "eslint-plugin-tsdoc": "0.2.17",
34120
- expect: "^29.6.4",
34394
+ expect: "^29.7.0",
34121
34395
  gl: "^6.0.2",
34122
- glob: "^10.3.3",
34396
+ glob: "^10.3.10",
34123
34397
  "is-builtin-module": "^3.2.1",
34124
34398
  jest: "^29.6.2",
34125
34399
  "jest-canvas-mock": "^2.5.2",
@@ -34135,14 +34409,14 @@ var devDependencies = {
34135
34409
  "pdf-merger-js": "^4.3.0",
34136
34410
  pixelmatch: "^5.3.0",
34137
34411
  pngjs: "^7.0.0",
34138
- postcss: "^8.4.28",
34412
+ postcss: "^8.4.31",
34139
34413
  "postcss-cli": "^10.1.0",
34140
34414
  "postcss-inline-svg": "^6.0.0",
34141
34415
  "pretty-bytes": "^6.1.1",
34142
- puppeteer: "^21.1.0",
34416
+ puppeteer: "^21.3.8",
34143
34417
  react: "^18.2.0",
34144
34418
  "react-dom": "^18.2.0",
34145
- rollup: "^3.28.1",
34419
+ rollup: "^4.0.2",
34146
34420
  "rollup-plugin-sourcemaps": "^0.6.3",
34147
34421
  rw: "^1.3.3",
34148
34422
  semver: "^7.5.4",
@@ -34154,10 +34428,10 @@ var devDependencies = {
34154
34428
  "ts-jest": "^29.1.1",
34155
34429
  "ts-node": "^10.9.1",
34156
34430
  tslib: "^2.6.2",
34157
- typedoc: "^0.24.8",
34431
+ typedoc: "^0.25.2",
34158
34432
  "typedoc-plugin-markdown": "^3.16.0",
34159
34433
  "typedoc-plugin-missing-exports": "^2.1.0",
34160
- typescript: "^5.1.6"
34434
+ typescript: "^5.2.2"
34161
34435
  };
34162
34436
  var overrides = {
34163
34437
  "postcss-inline-svg": {
@@ -35354,6 +35628,9 @@ class GlyphManager {
35354
35628
  if (!this._doesCharSupportLocalGlyph(id)) {
35355
35629
  return;
35356
35630
  }
35631
+ // Client-generated glyphs are rendered at 2x texture scale,
35632
+ // because CJK glyphs are more detailed than others.
35633
+ const textureScale = 2;
35357
35634
  let tinySDF = entry.tinySDF;
35358
35635
  if (!tinySDF) {
35359
35636
  let fontWeight = '400';
@@ -35367,9 +35644,9 @@ class GlyphManager {
35367
35644
  fontWeight = '200';
35368
35645
  }
35369
35646
  tinySDF = entry.tinySDF = new GlyphManager.TinySDF({
35370
- fontSize: 24,
35371
- buffer: 3,
35372
- radius: 8,
35647
+ fontSize: 24 * textureScale,
35648
+ buffer: 3 * textureScale,
35649
+ radius: 8 * textureScale,
35373
35650
  cutoff: 0.25,
35374
35651
  fontFamily,
35375
35652
  fontWeight
@@ -35389,16 +35666,18 @@ class GlyphManager {
35389
35666
  * To approximately align TinySDF glyphs with server-provided glyphs, we use this baseline adjustment
35390
35667
  * factor calibrated to be in between DIN Pro and Arial Unicode (but closer to Arial Unicode)
35391
35668
  */
35392
- const topAdjustment = 27;
35669
+ const topAdjustment = 27.5;
35670
+ const leftAdjustment = 0.5;
35393
35671
  return {
35394
35672
  id,
35395
- bitmap: new performance.AlphaImage({ width: char.width || 30, height: char.height || 30 }, char.data),
35673
+ bitmap: new performance.AlphaImage({ width: char.width || 30 * textureScale, height: char.height || 30 * textureScale }, char.data),
35396
35674
  metrics: {
35397
- width: char.glyphWidth || 24,
35398
- height: char.glyphHeight || 24,
35399
- left: char.glyphLeft || 0,
35400
- top: char.glyphTop - topAdjustment || -8,
35401
- advance: char.glyphAdvance || 24
35675
+ width: char.glyphWidth / textureScale || 24,
35676
+ height: char.glyphHeight / textureScale || 24,
35677
+ left: (char.glyphLeft / textureScale + leftAdjustment) || 0,
35678
+ top: char.glyphTop / textureScale - topAdjustment || -8,
35679
+ advance: char.glyphAdvance / textureScale || 24,
35680
+ isDoubleResolution: true
35402
35681
  }
35403
35682
  };
35404
35683
  }
@@ -36229,7 +36508,7 @@ class VectorTileSource extends performance.Evented {
36229
36508
  * ```ts
36230
36509
  * map.addSource('raster-source', {
36231
36510
  * 'type': 'raster',
36232
- * 'tiles': ['https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg'],
36511
+ * 'tiles': ['https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg'],
36233
36512
  * 'tileSize': 256,
36234
36513
  * });
36235
36514
  * ```
@@ -36355,16 +36634,6 @@ class RasterTileSource extends performance.Evented {
36355
36634
  }
36356
36635
  }
36357
36636
 
36358
- let supportsOffscreenCanvas;
36359
- function offscreenCanvasSupported() {
36360
- if (supportsOffscreenCanvas == null) {
36361
- supportsOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' &&
36362
- new OffscreenCanvas(1, 1).getContext('2d') &&
36363
- typeof createImageBitmap === 'function';
36364
- }
36365
- return supportsOffscreenCanvas;
36366
- }
36367
-
36368
36637
  /**
36369
36638
  * A source containing raster DEM tiles (See the [Style Specification](https://maplibre.org/maplibre-style-spec/) for detailed documentation of options.)
36370
36639
  * This source can be used to show hillshading and 3D terrain
@@ -36388,12 +36657,16 @@ class RasterDEMTileSource extends RasterTileSource {
36388
36657
  this.maxzoom = 22;
36389
36658
  this._options = performance.extend({ type: 'raster-dem' }, options);
36390
36659
  this.encoding = options.encoding || 'mapbox';
36660
+ this.redFactor = options.redFactor;
36661
+ this.greenFactor = options.greenFactor;
36662
+ this.blueFactor = options.blueFactor;
36663
+ this.baseShift = options.baseShift;
36391
36664
  }
36392
36665
  loadTile(tile, callback) {
36393
36666
  const url = tile.tileID.canonical.url(this.tiles, this.map.getPixelRatio(), this.scheme);
36394
- tile.request = ImageRequest.getImage(this.map._requestManager.transformRequest(url, ResourceType.Tile), imageLoaded.bind(this), this.map._refreshExpiredTiles);
36667
+ const request = this.map._requestManager.transformRequest(url, ResourceType.Tile);
36395
36668
  tile.neighboringTiles = this._getNeighboringTiles(tile.tileID);
36396
- function imageLoaded(err, img) {
36669
+ tile.request = ImageRequest.getImage(request, async (err, img, expiry) => {
36397
36670
  delete tile.request;
36398
36671
  if (tile.aborted) {
36399
36672
  tile.state = 'unloaded';
@@ -36405,23 +36678,38 @@ class RasterDEMTileSource extends RasterTileSource {
36405
36678
  }
36406
36679
  else if (img) {
36407
36680
  if (this.map._refreshExpiredTiles)
36408
- tile.setExpiryData(img);
36409
- delete img.cacheControl;
36410
- delete img.expires;
36411
- const transfer = performance.isImageBitmap(img) && offscreenCanvasSupported();
36412
- const rawImageData = transfer ? img : performance.browser.getImageData(img, 1);
36681
+ tile.setExpiryData(expiry);
36682
+ const transfer = performance.isImageBitmap(img) && performance.offscreenCanvasSupported();
36683
+ const rawImageData = transfer ? img : await readImageNow(img);
36413
36684
  const params = {
36414
36685
  uid: tile.uid,
36415
36686
  coord: tile.tileID,
36416
36687
  source: this.id,
36417
36688
  rawImageData,
36418
- encoding: this.encoding
36689
+ encoding: this.encoding,
36690
+ redFactor: this.redFactor,
36691
+ greenFactor: this.greenFactor,
36692
+ blueFactor: this.blueFactor,
36693
+ baseShift: this.baseShift
36419
36694
  };
36420
36695
  if (!tile.actor || tile.state === 'expired') {
36421
36696
  tile.actor = this.dispatcher.getActor();
36422
- tile.actor.send('loadDEMTile', params, done.bind(this));
36697
+ tile.actor.send('loadDEMTile', params, done);
36698
+ }
36699
+ }
36700
+ }, this.map._refreshExpiredTiles);
36701
+ async function readImageNow(img) {
36702
+ if (typeof VideoFrame !== 'undefined' && performance.isOffscreenCanvasDistorted()) {
36703
+ const width = img.width + 2;
36704
+ const height = img.height + 2;
36705
+ try {
36706
+ return new performance.RGBAImage({ width, height }, await performance.readImageUsingVideoFrame(img, -1, -1, width, height));
36707
+ }
36708
+ catch (e) {
36709
+ // fall-back to browser canvas decoding
36423
36710
  }
36424
36711
  }
36712
+ return performance.browser.getImageData(img, 1);
36425
36713
  }
36426
36714
  function done(err, data) {
36427
36715
  if (err) {
@@ -41955,6 +42243,8 @@ class Style extends performance.Evented {
41955
42243
  this[op.command].apply(this, op.args);
41956
42244
  }
41957
42245
  this.stylesheet = nextState;
42246
+ // reset serialization field, to be populated only when needed
42247
+ this._serializedLayers = null;
41958
42248
  return true;
41959
42249
  }
41960
42250
  addImage(id, image) {
@@ -49369,6 +49659,12 @@ class ScrollZoomHandler {
49369
49659
  }
49370
49660
  reset() {
49371
49661
  this._active = false;
49662
+ this._zooming = false;
49663
+ delete this._targetZoom;
49664
+ if (this._finishTimeout) {
49665
+ clearTimeout(this._finishTimeout);
49666
+ delete this._finishTimeout;
49667
+ }
49372
49668
  }
49373
49669
  }
49374
49670
 
@@ -50148,7 +50444,7 @@ class HandlerManager {
50148
50444
  this._updatingCamera = true;
50149
50445
  const inertialEase = this._inertia._onMoveEnd(this._map.dragPan._inertiaOptions);
50150
50446
  const shouldSnapToNorth = bearing => bearing !== 0 && -this._bearingSnap < bearing && bearing < this._bearingSnap;
50151
- if (inertialEase) {
50447
+ if (inertialEase && (inertialEase.essential || !performance.browser.prefersReducedMotion)) {
50152
50448
  if (shouldSnapToNorth(inertialEase.bearing || this._map.getBearing())) {
50153
50449
  inertialEase.bearing = 0;
50154
50450
  }
@@ -53974,6 +54270,7 @@ let Map$1 = class Map extends Camera {
53974
54270
  * @param name - The name of the paint property to set.
53975
54271
  * @param value - The value of the paint property to set.
53976
54272
  * Must be of a type appropriate for the property, as defined in the [MapLibre Style Specification](https://maplibre.org/maplibre-style-spec/).
54273
+ * Pass `null` to unset the existing value.
53977
54274
  * @param options - Options object.
53978
54275
  * @returns `this`
53979
54276
  * @example
@@ -55131,6 +55428,10 @@ class Marker extends performance.Evented {
55131
55428
  this._update = (e) => {
55132
55429
  if (!this._map)
55133
55430
  return;
55431
+ const isFullyLoaded = this._map.loaded() && !this._map.isMoving();
55432
+ if ((e === null || e === void 0 ? void 0 : e.type) === 'terrain' || ((e === null || e === void 0 ? void 0 : e.type) === 'render' && !isFullyLoaded)) {
55433
+ this._map.once('render', this._update);
55434
+ }
55134
55435
  if (this._map.transform.renderWorldCopies) {
55135
55436
  this._lngLat = smartWrap(this._lngLat, this._pos, this._map.transform);
55136
55437
  }
@@ -55354,6 +55655,7 @@ class Marker extends performance.Evented {
55354
55655
  map.getCanvasContainer().appendChild(this._element);
55355
55656
  map.on('move', this._update);
55356
55657
  map.on('moveend', this._update);
55658
+ map.on('terrain', this._update);
55357
55659
  this.setDraggable(this._draggable);
55358
55660
  this._update();
55359
55661
  // If we attached the `click` listener to the marker element, the popup