maplibre-gl 2.2.0-pre.3 → 2.2.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 (121) hide show
  1. package/README.md +73 -14
  2. package/build/generate-debug-index-file.ts +19 -0
  3. package/build/generate-style-code.ts +6 -1
  4. package/build/generate-style-spec.ts +151 -35
  5. package/build/generate-typings.ts +1 -1
  6. package/build/rollup_plugins.ts +4 -1
  7. package/dist/maplibre-gl-csp-worker.js +1 -1
  8. package/dist/maplibre-gl-csp-worker.js.map +1 -1
  9. package/dist/maplibre-gl-csp.js +1 -1
  10. package/dist/maplibre-gl-csp.js.map +1 -1
  11. package/dist/maplibre-gl-dev.js +364 -3124
  12. package/dist/maplibre-gl.css +1 -1
  13. package/dist/maplibre-gl.d.ts +439 -151
  14. package/dist/maplibre-gl.js +4 -4
  15. package/dist/maplibre-gl.js.map +1 -1
  16. package/package.json +68 -65
  17. package/src/css/maplibre-gl.css +39 -32
  18. package/src/data/bucket/fill_bucket.test.ts +1 -0
  19. package/src/data/bucket/symbol_bucket.test.ts +2 -0
  20. package/src/data/evaluation_feature.ts +1 -1
  21. package/src/data/program_configuration.ts +2 -2
  22. package/src/geo/transform.ts +4 -4
  23. package/src/gl/vertex_buffer.ts +4 -4
  24. package/src/index.ts +1 -1
  25. package/src/render/image_atlas.ts +1 -0
  26. package/src/render/image_manager.ts +1 -0
  27. package/src/render/program/debug_program.ts +1 -1
  28. package/src/render/render_to_texture.ts +3 -0
  29. package/src/render/terrain.ts +21 -21
  30. package/src/shaders/README.md +2 -2
  31. package/src/source/geojson_worker_source.test.ts +2 -2
  32. package/src/source/geojson_wrapper.test.ts +1 -1
  33. package/src/source/image_source.test.ts +8 -8
  34. package/src/source/image_source.ts +1 -1
  35. package/src/source/raster_tile_source.test.ts +1 -1
  36. package/src/source/source_cache.test.ts +12 -12
  37. package/src/source/source_cache.ts +1 -1
  38. package/src/source/terrain_source_cache.ts +3 -3
  39. package/src/source/vector_tile_source.test.ts +1 -1
  40. package/src/source/vector_tile_worker_source.test.ts +1 -1
  41. package/src/source/video_source.test.ts +2 -2
  42. package/src/source/worker.ts +2 -4
  43. package/src/style/light.test.ts +1 -1
  44. package/src/style/style.test.ts +3 -3
  45. package/src/style/style.ts +2 -2
  46. package/src/style/style_layer/background_style_layer_properties.g.ts +1 -0
  47. package/src/style/style_layer/circle_style_layer_properties.g.ts +1 -0
  48. package/src/style/style_layer/fill_extrusion_style_layer_properties.g.ts +1 -0
  49. package/src/style/style_layer/fill_style_layer_properties.g.ts +1 -0
  50. package/src/style/style_layer/heatmap_style_layer_properties.g.ts +1 -0
  51. package/src/style/style_layer/hillshade_style_layer_properties.g.ts +1 -0
  52. package/src/style/style_layer/line_style_layer_properties.g.ts +1 -0
  53. package/src/style/style_layer/raster_style_layer_properties.g.ts +1 -0
  54. package/src/style/style_layer/symbol_style_layer.ts +16 -1
  55. package/src/style/style_layer/symbol_style_layer_properties.g.ts +4 -3
  56. package/src/style-spec/CHANGELOG.md +5 -0
  57. package/src/style-spec/composite.test.ts +2 -0
  58. package/src/style-spec/diff.test.ts +3 -3
  59. package/src/style-spec/empty.ts +3 -2
  60. package/src/style-spec/expression/definitions/coercion.ts +13 -2
  61. package/src/style-spec/expression/definitions/interpolate.ts +1 -0
  62. package/src/style-spec/expression/expression.test.ts +1 -1
  63. package/src/style-spec/expression/expression.ts +3 -0
  64. package/src/style-spec/expression/index.ts +8 -2
  65. package/src/style-spec/expression/parsing_context.ts +2 -0
  66. package/src/style-spec/expression/types.ts +6 -1
  67. package/src/style-spec/expression/values.ts +9 -4
  68. package/src/style-spec/feature_filter/convert.ts +65 -65
  69. package/src/style-spec/feature_filter/feature_filter.test.ts +45 -4
  70. package/src/style-spec/feature_filter/index.ts +2 -1
  71. package/src/style-spec/function/index.test.ts +117 -1
  72. package/src/style-spec/function/index.ts +24 -12
  73. package/src/style-spec/migrate/expressions.ts +1 -1
  74. package/src/style-spec/migrate/v8.test.ts +2 -0
  75. package/src/style-spec/migrate/v9.test.ts +6 -4
  76. package/src/style-spec/migrate.test.ts +3 -1
  77. package/src/style-spec/package.json +1 -1
  78. package/src/style-spec/reference/latest.ts +2 -2
  79. package/src/style-spec/reference/v8.json +9 -6
  80. package/src/style-spec/style-spec.test.ts +2 -1
  81. package/src/style-spec/style-spec.ts +18 -9
  82. package/src/style-spec/types.g.ts +152 -36
  83. package/src/style-spec/util/interpolate.test.ts +5 -0
  84. package/src/style-spec/util/interpolate.ts +12 -0
  85. package/src/style-spec/util/padding.test.ts +27 -0
  86. package/src/style-spec/util/padding.ts +64 -0
  87. package/src/style-spec/validate/validate.ts +3 -1
  88. package/src/style-spec/validate/validate_padding.test.ts +82 -0
  89. package/src/style-spec/validate/validate_padding.ts +36 -0
  90. package/src/style-spec/validate_style.ts +1 -1
  91. package/src/symbol/check_max_angle.test.ts +5 -5
  92. package/src/symbol/collision_feature.test.ts +22 -5
  93. package/src/symbol/collision_feature.ts +7 -5
  94. package/src/symbol/collision_index.ts +1 -1
  95. package/src/symbol/get_anchors.test.ts +4 -4
  96. package/src/symbol/projection.ts +1 -1
  97. package/src/symbol/quads.test.ts +1 -1
  98. package/src/symbol/shaping.ts +10 -10
  99. package/src/symbol/symbol_layout.ts +5 -4
  100. package/src/symbol/symbol_style_layer.test.ts +1 -1
  101. package/src/ui/camera.test.ts +11 -11
  102. package/src/ui/control/geolocate_control.ts +1 -1
  103. package/src/ui/control/terrain_control.ts +4 -4
  104. package/src/ui/handler/cooperative_gestures.test.ts +167 -0
  105. package/src/ui/handler/drag_pan.test.ts +2 -1
  106. package/src/ui/handler/scroll_zoom.ts +7 -0
  107. package/src/ui/handler/touch_pan.ts +22 -2
  108. package/src/ui/handler/touch_zoom_rotate.ts +18 -1
  109. package/src/ui/handler_manager.ts +2 -2
  110. package/src/ui/map.test.ts +16 -16
  111. package/src/ui/map.ts +76 -8
  112. package/src/ui/map_events.test.ts +33 -32
  113. package/src/ui/popup.test.ts +2 -2
  114. package/src/util/ajax.test.ts +5 -5
  115. package/src/util/ajax.ts +1 -1
  116. package/src/util/classify_rings.test.ts +27 -27
  117. package/src/util/primitives.ts +4 -4
  118. package/src/util/resolve_tokens.test.ts +1 -1
  119. package/src/util/tile_request_cache.test.ts +5 -5
  120. package/src/util/util.test.ts +5 -5
  121. package/src/util/util.ts +2 -3
@@ -79,7 +79,7 @@ describe('RasterTileSource', () => {
79
79
 
80
80
  source.on('data', (e) => {
81
81
  if (e.sourceDataType === 'metadata') {
82
- expect(source.tileBounds.bounds).toEqual({_sw:{lng: -47, lat: -7}, _ne:{lng: -45, lat: 90}});
82
+ expect(source.tileBounds.bounds).toEqual({_sw: {lng: -47, lat: -7}, _ne: {lng: -45, lat: 90}});
83
83
  done();
84
84
  }
85
85
  });
@@ -485,7 +485,7 @@ describe('SourceCache / Source lifecycle', () => {
485
485
  transform.resize(511, 511);
486
486
  transform.zoom = 0;
487
487
 
488
- const expected = [ new OverscaledTileID(0, 0, 0, 0, 0).key, new OverscaledTileID(0, 0, 0, 0, 0).key ];
488
+ const expected = [new OverscaledTileID(0, 0, 0, 0, 0).key, new OverscaledTileID(0, 0, 0, 0, 0).key];
489
489
  expect.assertions(expected.length);
490
490
 
491
491
  const sourceCache = createSourceCache({
@@ -1054,9 +1054,9 @@ describe('SourceCache#_updateRetainedTiles', () => {
1054
1054
 
1055
1055
  expect(retained).toEqual({
1056
1056
  // parent of ideal tile 0/0/0
1057
- '000' : new OverscaledTileID(0, 0, 0, 0, 0),
1057
+ '000': new OverscaledTileID(0, 0, 0, 0, 0),
1058
1058
  // ideal tile id 1/0/1
1059
- '211' : new OverscaledTileID(1, 0, 1, 0, 1)
1059
+ '211': new OverscaledTileID(1, 0, 1, 0, 1)
1060
1060
  });
1061
1061
 
1062
1062
  addTileSpy.mockClear();
@@ -1069,7 +1069,7 @@ describe('SourceCache#_updateRetainedTiles', () => {
1069
1069
  expect(getTileSpy).not.toHaveBeenCalled();
1070
1070
  expect(retainedLoaded).toEqual({
1071
1071
  // only ideal tile retained
1072
- '211' : new OverscaledTileID(1, 0, 1, 0, 1)
1072
+ '211': new OverscaledTileID(1, 0, 1, 0, 1)
1073
1073
  });
1074
1074
  });
1075
1075
 
@@ -1119,9 +1119,9 @@ describe('SourceCache#_updateRetainedTiles', () => {
1119
1119
  expect(retained).toEqual({
1120
1120
  // parent of ideal tile (0, 0, 0) (only partially covered by loaded child
1121
1121
  // tiles, so we still need to load the parent)
1122
- '000' : new OverscaledTileID(0, 0, 0, 0, 0),
1122
+ '000': new OverscaledTileID(0, 0, 0, 0, 0),
1123
1123
  // ideal tile id (1, 0, 0)
1124
- '011' : new OverscaledTileID(1, 0, 1, 0, 0),
1124
+ '011': new OverscaledTileID(1, 0, 1, 0, 0),
1125
1125
  // loaded child tile (2, 0, 0)
1126
1126
  '022': new OverscaledTileID(2, 0, 2, 0, 0)
1127
1127
  });
@@ -1134,9 +1134,9 @@ describe('SourceCache#_updateRetainedTiles', () => {
1134
1134
  expect(retained).toEqual({
1135
1135
  // parent of ideal tile (0, 0, 0) (only partially covered by loaded child
1136
1136
  // tiles, so we still need to load the parent)
1137
- '000' : new OverscaledTileID(0, 0, 0, 0, 0),
1137
+ '000': new OverscaledTileID(0, 0, 0, 0, 0),
1138
1138
  // ideal tile id (1, 0, 0)
1139
- '011' : new OverscaledTileID(1, 0, 1, 0, 0)
1139
+ '011': new OverscaledTileID(1, 0, 1, 0, 0)
1140
1140
  });
1141
1141
 
1142
1142
  });
@@ -1163,7 +1163,7 @@ describe('SourceCache#_updateRetainedTiles', () => {
1163
1163
 
1164
1164
  expect(retained).toEqual({
1165
1165
  // ideal tile id (2, 0, 0)
1166
- '022' : new OverscaledTileID(2, 0, 2, 0, 0)
1166
+ '022': new OverscaledTileID(2, 0, 2, 0, 0)
1167
1167
  });
1168
1168
 
1169
1169
  });
@@ -1191,7 +1191,7 @@ describe('SourceCache#_updateRetainedTiles', () => {
1191
1191
 
1192
1192
  expect(retained).toEqual({
1193
1193
  // ideal tile id (2, 0, 0)
1194
- '022' : new OverscaledTileID(2, 0, 2, 0, 0)
1194
+ '022': new OverscaledTileID(2, 0, 2, 0, 0)
1195
1195
  });
1196
1196
 
1197
1197
  });
@@ -1352,7 +1352,7 @@ describe('SourceCache#tilesIn', () => {
1352
1352
  expect(tiles[0].tile.tileID.key).toBe('011');
1353
1353
  expect(tiles[0].tile.tileSize).toBe(512);
1354
1354
  expect(tiles[0].scale).toBe(1);
1355
- expect(round(tiles[0].queryGeometry)).toEqual([{x: 4096, y: 4050}, {x:12288, y: 8146}]);
1355
+ expect(round(tiles[0].queryGeometry)).toEqual([{x: 4096, y: 4050}, {x: 12288, y: 8146}]);
1356
1356
 
1357
1357
  expect(tiles[1].tile.tileID.key).toBe('111');
1358
1358
  expect(tiles[1].tile.tileSize).toBe(512);
@@ -1404,7 +1404,7 @@ describe('SourceCache#tilesIn', () => {
1404
1404
  expect(tiles[0].tile.tileID.key).toBe('012');
1405
1405
  expect(tiles[0].tile.tileSize).toBe(1024);
1406
1406
  expect(tiles[0].scale).toBe(1);
1407
- expect(round(tiles[0].queryGeometry)).toEqual([{x: 4096, y: 4050}, {x:12288, y: 8146}]);
1407
+ expect(round(tiles[0].queryGeometry)).toEqual([{x: 4096, y: 4050}, {x: 12288, y: 8146}]);
1408
1408
 
1409
1409
  expect(tiles[1].tile.tileID.key).toBe('112');
1410
1410
  expect(tiles[1].tile.tileSize).toBe(1024);
@@ -492,7 +492,7 @@ class SourceCache extends Evented {
492
492
  * are inside the viewport.
493
493
  * @private
494
494
  */
495
- update(transform: Transform, terrain: Terrain) {
495
+ update(transform: Transform, terrain?: Terrain) {
496
496
  this.transform = transform;
497
497
  this.terrain = terrain;
498
498
  if (!this._sourceLoaded || this._paused) { return; }
@@ -133,11 +133,11 @@ export default class TerrainSourceCache extends Evented {
133
133
  }
134
134
 
135
135
  /**
136
- * searches for the corresponding current renderable terrain-tiles
136
+ * Searches for the corresponding current renderable terrain-tiles
137
137
  * @param {OverscaledTileID} tileID - the tile to look for
138
- * @returns {[_:string]: Tile} - the tiles that were found
138
+ * @returns {Record<string, OverscaledTileID>} - the tiles that were found
139
139
  */
140
- getTerrainCoords(tileID: OverscaledTileID): {[_: string]: OverscaledTileID} {
140
+ getTerrainCoords(tileID: OverscaledTileID): Record<string, OverscaledTileID> {
141
141
  const coords = {};
142
142
  for (const key of this._renderableTilesKeys) {
143
143
  const _tileID = this._tiles[key].tileID;
@@ -253,7 +253,7 @@ describe('VectorTileSource', () => {
253
253
 
254
254
  source.on('data', (e) => {
255
255
  if (e.sourceDataType === 'metadata') {
256
- expect(source.tileBounds.bounds).toEqual({_sw:{lng: -47, lat: -7}, _ne:{lng: -45, lat: 90}});
256
+ expect(source.tileBounds.bounds).toEqual({_sw: {lng: -47, lat: -7}, _ne: {lng: -45, lat: 90}});
257
257
  done();
258
258
  }
259
259
  });
@@ -236,7 +236,7 @@ describe('vector tile worker source', () => {
236
236
 
237
237
  const source = new VectorTileWorkerSource(actor, layerIndex, [], loadVectorData);
238
238
 
239
- window.performance.getEntriesByName = jest.fn().mockReturnValue([ exampleResourceTiming ]);
239
+ window.performance.getEntriesByName = jest.fn().mockReturnValue([exampleResourceTiming]);
240
240
 
241
241
  source.loadTile({
242
242
  source: 'source',
@@ -19,7 +19,7 @@ describe('VideoSource', () => {
19
19
  // Attribution File:Volcano Lava Sample.webm: U.S. Geological Survey (USGS), Public domain, via Wikimedia Commons
20
20
  const source = createSource({
21
21
  type: 'video',
22
- urls : [ 'cropped.mp4', 'https://upload.wikimedia.org/wikipedia/commons/2/22/Volcano_Lava_Sample.webm' ],
22
+ urls: ['cropped.mp4', 'https://upload.wikimedia.org/wikipedia/commons/2/22/Volcano_Lava_Sample.webm'],
23
23
  coordinates: [
24
24
  [-76.54, 39.18],
25
25
  [-76.52, 39.18],
@@ -50,7 +50,7 @@ describe('VideoSource', () => {
50
50
  const source = createSource({
51
51
  type: 'video',
52
52
  video: el,
53
- urls : [ 'cropped.mp4', 'https://upload.wikimedia.org/wikipedia/commons/2/22/Volcano_Lava_Sample.webm' ],
53
+ urls: ['cropped.mp4', 'https://upload.wikimedia.org/wikipedia/commons/2/22/Volcano_Lava_Sample.webm'],
54
54
  coordinates: [
55
55
  [-76.54, 39.18],
56
56
  [-76.52, 39.18],
@@ -7,6 +7,7 @@ import GeoJSONWorkerSource from './geojson_worker_source';
7
7
  import assert from 'assert';
8
8
  import {plugin as globalRTLTextPlugin} from './rtl_text_plugin';
9
9
  import {enforceCacheSizeLimit} from '../util/tile_request_cache';
10
+ import {isWorker} from '../util/util';
10
11
 
11
12
  import type {
12
13
  WorkerSource,
@@ -267,9 +268,6 @@ export default class Worker {
267
268
  }
268
269
  }
269
270
 
270
- /* global self, WorkerGlobalScope */
271
- if (typeof WorkerGlobalScope !== 'undefined' &&
272
- typeof self !== 'undefined' &&
273
- self instanceof WorkerGlobalScope) {
271
+ if (isWorker()) {
274
272
  (self as any).worker = new Worker(self as any);
275
273
  }
@@ -77,7 +77,7 @@ describe('Light#setLight', () => {
77
77
  const light = new Light({});
78
78
 
79
79
  const lightSpy = jest.spyOn(light, '_validate');
80
- light.setLight({color: [999]}, {validate: false});
80
+ light.setLight({color: [999]} as any, {validate: false});
81
81
  light.updateTransitions({transition: false} as any as TransitionParameters);
82
82
  light.recalculate({zoom: 16, zoomHistory: {}, now: 10} as EvaluationParameters);
83
83
 
@@ -883,7 +883,7 @@ describe('Style#addLayer', () => {
883
883
  'type': 'geojson',
884
884
  'data': {
885
885
  'type': 'Point',
886
- 'coordinates': [ 0, 0]
886
+ 'coordinates': [0, 0]
887
887
  }
888
888
  };
889
889
  const layer = {id: 'inline-source-layer', type: 'circle', source} as any as LayerSpecification;
@@ -1901,7 +1901,7 @@ describe('Style#queryRenderedFeatures', () => {
1901
1901
  errors++;
1902
1902
  }
1903
1903
  });
1904
- style.queryRenderedFeatures([{x: 0, y: 0}], {layers:'string'}, transform);
1904
+ style.queryRenderedFeatures([{x: 0, y: 0}], {layers: 'string'}, transform);
1905
1905
  expect(errors).toBe(1);
1906
1906
  });
1907
1907
 
@@ -1939,7 +1939,7 @@ describe('Style#queryRenderedFeatures', () => {
1939
1939
  jest.spyOn(style, 'fire').mockImplementation((event) => {
1940
1940
  if (event['error'] && event['error'].message.includes('does not exist in the map\'s style and cannot be queried for features.')) errors++;
1941
1941
  });
1942
- const results = style.queryRenderedFeatures([{x: 0, y: 0}], {layers:['merp']}, transform);
1942
+ const results = style.queryRenderedFeatures([{x: 0, y: 0}], {layers: ['merp']}, transform);
1943
1943
  expect(errors).toBe(1);
1944
1944
  expect(results).toHaveLength(0);
1945
1945
  });
@@ -441,7 +441,7 @@ class Style extends Evented {
441
441
  for (const sourceId in sourcesUsedBefore) {
442
442
  const sourceCache = this.sourceCaches[sourceId];
443
443
  if (sourcesUsedBefore[sourceId] !== sourceCache.used) {
444
- sourceCache.fire(new Event('data', {sourceDataType: 'visibility', dataType:'source', sourceId}));
444
+ sourceCache.fire(new Event('data', {sourceDataType: 'visibility', dataType: 'source', sourceId}));
445
445
  }
446
446
  }
447
447
 
@@ -663,7 +663,7 @@ class Style extends Evented {
663
663
  const sourceCache = this.sourceCaches[id];
664
664
  delete this.sourceCaches[id];
665
665
  delete this._updatedSources[id];
666
- sourceCache.fire(new Event('data', {sourceDataType: 'metadata', dataType:'source', sourceId: id}));
666
+ sourceCache.fire(new Event('data', {sourceDataType: 'metadata', dataType: 'source', sourceId: id}));
667
667
  sourceCache.setEventedParent(null);
668
668
  sourceCache.onRemove(this.map);
669
669
  this._changed = true;
@@ -15,6 +15,7 @@ import {
15
15
  } from '../properties';
16
16
 
17
17
  import type Color from '../../style-spec/util/color';
18
+ import type Padding from '../../style-spec/util/padding';
18
19
 
19
20
  import type Formatted from '../../style-spec/expression/types/formatted';
20
21
 
@@ -15,6 +15,7 @@ import {
15
15
  } from '../properties';
16
16
 
17
17
  import type Color from '../../style-spec/util/color';
18
+ import type Padding from '../../style-spec/util/padding';
18
19
 
19
20
  import type Formatted from '../../style-spec/expression/types/formatted';
20
21
 
@@ -15,6 +15,7 @@ import {
15
15
  } from '../properties';
16
16
 
17
17
  import type Color from '../../style-spec/util/color';
18
+ import type Padding from '../../style-spec/util/padding';
18
19
 
19
20
  import type Formatted from '../../style-spec/expression/types/formatted';
20
21
 
@@ -15,6 +15,7 @@ import {
15
15
  } from '../properties';
16
16
 
17
17
  import type Color from '../../style-spec/util/color';
18
+ import type Padding from '../../style-spec/util/padding';
18
19
 
19
20
  import type Formatted from '../../style-spec/expression/types/formatted';
20
21
 
@@ -15,6 +15,7 @@ import {
15
15
  } from '../properties';
16
16
 
17
17
  import type Color from '../../style-spec/util/color';
18
+ import type Padding from '../../style-spec/util/padding';
18
19
 
19
20
  import type Formatted from '../../style-spec/expression/types/formatted';
20
21
 
@@ -15,6 +15,7 @@ import {
15
15
  } from '../properties';
16
16
 
17
17
  import type Color from '../../style-spec/util/color';
18
+ import type Padding from '../../style-spec/util/padding';
18
19
 
19
20
  import type Formatted from '../../style-spec/expression/types/formatted';
20
21
 
@@ -15,6 +15,7 @@ import {
15
15
  } from '../properties';
16
16
 
17
17
  import type Color from '../../style-spec/util/color';
18
+ import type Padding from '../../style-spec/util/padding';
18
19
 
19
20
  import type Formatted from '../../style-spec/expression/types/formatted';
20
21
 
@@ -15,6 +15,7 @@ import {
15
15
  } from '../properties';
16
16
 
17
17
  import type Color from '../../style-spec/util/color';
18
+ import type Padding from '../../style-spec/util/padding';
18
19
 
19
20
  import type Formatted from '../../style-spec/expression/types/formatted';
20
21
 
@@ -1,7 +1,7 @@
1
1
  import StyleLayer from '../style_layer';
2
2
 
3
3
  import assert from 'assert';
4
- import SymbolBucket from '../../data/bucket/symbol_bucket';
4
+ import SymbolBucket, {SymbolFeature} from '../../data/bucket/symbol_bucket';
5
5
  import resolveTokens from '../../util/resolve_tokens';
6
6
  import properties, {SymbolLayoutPropsPossiblyEvaluated, SymbolPaintPropsPossiblyEvaluated} from './symbol_style_layer_properties.g';
7
7
 
@@ -204,4 +204,19 @@ export function getOverlapMode(layout: PossiblyEvaluated<SymbolLayoutProps, Symb
204
204
  return result;
205
205
  }
206
206
 
207
+ export type SymbolPadding = [number, number, number, number];
208
+
209
+ export function getIconPadding(layout: PossiblyEvaluated<SymbolLayoutProps, SymbolLayoutPropsPossiblyEvaluated>, feature: SymbolFeature, canonical: CanonicalTileID, pixelRatio = 1): SymbolPadding {
210
+ // Support text-padding in addition to icon-padding? Unclear how to apply asymmetric text-padding to the radius for collision circles.
211
+ const result = layout.get('icon-padding').evaluate(feature, {}, canonical);
212
+ const values = result && result.values;
213
+
214
+ return [
215
+ values[0] * pixelRatio,
216
+ values[1] * pixelRatio,
217
+ values[2] * pixelRatio,
218
+ values[3] * pixelRatio,
219
+ ];
220
+ }
221
+
207
222
  export default SymbolStyleLayer;
@@ -15,6 +15,7 @@ import {
15
15
  } from '../properties';
16
16
 
17
17
  import type Color from '../../style-spec/util/color';
18
+ import type Padding from '../../style-spec/util/padding';
18
19
 
19
20
  import type Formatted from '../../style-spec/expression/types/formatted';
20
21
 
@@ -41,7 +42,7 @@ export type SymbolLayoutProps = {
41
42
  "icon-text-fit-padding": DataConstantProperty<[number, number, number, number]>,
42
43
  "icon-image": DataDrivenProperty<ResolvedImage>,
43
44
  "icon-rotate": DataDrivenProperty<number>,
44
- "icon-padding": DataConstantProperty<number>,
45
+ "icon-padding": DataDrivenProperty<Padding>,
45
46
  "icon-keep-upright": DataConstantProperty<boolean>,
46
47
  "icon-offset": DataDrivenProperty<[number, number]>,
47
48
  "icon-anchor": DataDrivenProperty<"center" | "left" | "right" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right">,
@@ -87,7 +88,7 @@ export type SymbolLayoutPropsPossiblyEvaluated = {
87
88
  "icon-text-fit-padding": [number, number, number, number],
88
89
  "icon-image": PossiblyEvaluatedPropertyValue<ResolvedImage>,
89
90
  "icon-rotate": PossiblyEvaluatedPropertyValue<number>,
90
- "icon-padding": number,
91
+ "icon-padding": PossiblyEvaluatedPropertyValue<Padding>,
91
92
  "icon-keep-upright": boolean,
92
93
  "icon-offset": PossiblyEvaluatedPropertyValue<[number, number]>,
93
94
  "icon-anchor": PossiblyEvaluatedPropertyValue<"center" | "left" | "right" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right">,
@@ -133,7 +134,7 @@ const layout: Properties<SymbolLayoutProps> = new Properties({
133
134
  "icon-text-fit-padding": new DataConstantProperty(styleSpec["layout_symbol"]["icon-text-fit-padding"] as any as StylePropertySpecification),
134
135
  "icon-image": new DataDrivenProperty(styleSpec["layout_symbol"]["icon-image"] as any as StylePropertySpecification),
135
136
  "icon-rotate": new DataDrivenProperty(styleSpec["layout_symbol"]["icon-rotate"] as any as StylePropertySpecification),
136
- "icon-padding": new DataConstantProperty(styleSpec["layout_symbol"]["icon-padding"] as any as StylePropertySpecification),
137
+ "icon-padding": new DataDrivenProperty(styleSpec["layout_symbol"]["icon-padding"] as any as StylePropertySpecification),
137
138
  "icon-keep-upright": new DataConstantProperty(styleSpec["layout_symbol"]["icon-keep-upright"] as any as StylePropertySpecification),
138
139
  "icon-offset": new DataDrivenProperty(styleSpec["layout_symbol"]["icon-offset"] as any as StylePropertySpecification),
139
140
  "icon-anchor": new DataDrivenProperty(styleSpec["layout_symbol"]["icon-anchor"] as any as StylePropertySpecification),
@@ -1,3 +1,8 @@
1
+ ## 16.1.0
2
+
3
+ ### ✨ Features and improvements
4
+ * Update `icon-padding` symbol layout property to support asymmetric padding [#1289](https://github.com/maplibre/maplibre-gl-js/pull/1289)
5
+
1
6
  ## 16.0.0
2
7
 
3
8
  ### Breaking changes
@@ -1,3 +1,5 @@
1
+ // @ts-nocheck
2
+
1
3
  import composite from './composite';
2
4
 
3
5
  describe('composite', () => {
@@ -88,7 +88,7 @@ test('diff', () => {
88
88
  }, {
89
89
  layers: [{id: 'a', filter: ['==', 'foo', 'baz']}]
90
90
  })).toEqual([
91
- {command: 'setFilter', args: ['a', [ '==', 'foo', 'baz' ] ]}
91
+ {command: 'setFilter', args: ['a', ['==', 'foo', 'baz']]}
92
92
  ]);
93
93
 
94
94
  expect(diffStyles({
@@ -329,9 +329,9 @@ test('diff', () => {
329
329
  ]);
330
330
 
331
331
  expect(diffStyles({
332
- layers: [ {id: 'a', source: 'source-one'} ]
332
+ layers: [{id: 'a', source: 'source-one'}]
333
333
  }, {
334
- layers: [ {id: 'a', source: 'source-two'} ]
334
+ layers: [{id: 'a', source: 'source-two'}]
335
335
  })).toEqual([
336
336
  {command: 'removeLayer', args: ['a']},
337
337
  {command: 'addLayer', args: [{id: 'a', source: 'source-two'}, undefined]}
@@ -1,6 +1,7 @@
1
1
  import latest from './reference/latest';
2
+ import {StyleSpecification} from './types.g';
2
3
 
3
- export default function emptyStyle() {
4
+ export default function emptyStyle(): StyleSpecification {
4
5
  const style = {};
5
6
 
6
7
  const version = latest['$version'];
@@ -25,5 +26,5 @@ export default function emptyStyle() {
25
26
  }
26
27
  }
27
28
 
28
- return style;
29
+ return style as StyleSpecification;
29
30
  }
@@ -1,7 +1,7 @@
1
1
  import assert from 'assert';
2
2
 
3
3
  import {BooleanType, ColorType, NumberType, StringType, ValueType} from '../types';
4
- import {Color, toString as valueToString, validateRGBA} from '../values';
4
+ import {Color, Padding, toString as valueToString, validateRGBA} from '../values';
5
5
  import RuntimeError from '../runtime_error';
6
6
  import Formatted from '../types/formatted';
7
7
  import ResolvedImage from '../types/resolved_image';
@@ -81,7 +81,18 @@ class Coercion implements Expression {
81
81
  }
82
82
  }
83
83
  }
84
- throw new RuntimeError(error || `Could not parse color from value '${typeof input === 'string' ? input : String(JSON.stringify(input))}'`);
84
+ throw new RuntimeError(error || `Could not parse color from value '${typeof input === 'string' ? input : JSON.stringify(input)}'`);
85
+ } else if (this.type.kind === 'padding') {
86
+ let input;
87
+ for (const arg of this.args) {
88
+ input = arg.evaluate(ctx);
89
+
90
+ const pad = Padding.parse(input);
91
+ if (pad) {
92
+ return pad;
93
+ }
94
+ }
95
+ throw new RuntimeError(`Could not parse padding from value '${typeof input === 'string' ? input : JSON.stringify(input)}'`);
85
96
  } else if (this.type.kind === 'number') {
86
97
  let value = null;
87
98
  for (const arg of this.args) {
@@ -135,6 +135,7 @@ class Interpolate implements Expression {
135
135
 
136
136
  if (outputType.kind !== 'number' &&
137
137
  outputType.kind !== 'color' &&
138
+ outputType.kind !== 'padding' &&
138
139
  !(
139
140
  outputType.kind === 'array' &&
140
141
  outputType.itemType.kind === 'number' &&
@@ -40,7 +40,7 @@ describe('createPropertyExpression', () => {
40
40
 
41
41
  describe('evaluate expression', () => {
42
42
  test('warns and falls back to default for invalid enum values', () => {
43
- const {value} = createPropertyExpression([ 'get', 'x' ], {
43
+ const {value} = createPropertyExpression(['get', 'x'], {
44
44
  type: 'enum',
45
45
  values: {a: {}, b: {}, c: {}},
46
46
  default: 'a',
@@ -2,6 +2,9 @@ import type {Type} from './types';
2
2
  import type ParsingContext from './parsing_context';
3
3
  import type EvaluationContext from './evaluation_context';
4
4
 
5
+ /**
6
+ * Expression
7
+ */
5
8
  export interface Expression {
6
9
  readonly type: Type;
7
10
  evaluate(ctx: EvaluationContext): any;
@@ -379,8 +379,10 @@ export function normalizePropertyExpression<T>(
379
379
 
380
380
  } else {
381
381
  let constant: any = value;
382
- if (typeof value === 'string' && specification.type === 'color') {
382
+ if (specification.type === 'color' && typeof value === 'string') {
383
383
  constant = Color.parse(value);
384
+ } else if (specification.type === 'padding' && (typeof value === 'number' || Array.isArray(value))) {
385
+ constant = Padding.parse(value as (number | number[]));
384
386
  }
385
387
  return {
386
388
  kind: 'constant',
@@ -430,7 +432,8 @@ function findZoomCurve(expression: Expression): Step | Interpolate | ParsingErro
430
432
  return result;
431
433
  }
432
434
 
433
- import {ColorType, StringType, NumberType, BooleanType, ValueType, FormattedType, ResolvedImageType, array} from './types';
435
+ import {ColorType, StringType, NumberType, BooleanType, ValueType, FormattedType, PaddingType, ResolvedImageType, array} from './types';
436
+ import Padding from '../util/padding';
434
437
 
435
438
  function getExpectedType(spec: StylePropertySpecification): Type {
436
439
  const types = {
@@ -440,6 +443,7 @@ function getExpectedType(spec: StylePropertySpecification): Type {
440
443
  enum: StringType,
441
444
  boolean: BooleanType,
442
445
  formatted: FormattedType,
446
+ padding: PaddingType,
443
447
  resolvedImage: ResolvedImageType
444
448
  };
445
449
 
@@ -458,6 +462,8 @@ function getDefaultValue(spec: StylePropertySpecification): Value {
458
462
  return new Color(0, 0, 0, 0);
459
463
  } else if (spec.type === 'color') {
460
464
  return Color.parse(spec.default) || null;
465
+ } else if (spec.type === 'padding') {
466
+ return Padding.parse(spec.default) || null;
461
467
  } else if (spec.default === undefined) {
462
468
  return null;
463
469
  } else {
@@ -120,6 +120,8 @@ class ParsingContext {
120
120
  parsed = annotate(parsed, expected, options.typeAnnotation || 'assert');
121
121
  } else if ((expected.kind === 'color' || expected.kind === 'formatted' || expected.kind === 'resolvedImage') && (actual.kind === 'value' || actual.kind === 'string')) {
122
122
  parsed = annotate(parsed, expected, options.typeAnnotation || 'coerce');
123
+ } else if (expected.kind === 'padding' && (actual.kind === 'value' || actual.kind === 'number' || actual.kind === 'array')) {
124
+ parsed = annotate(parsed, expected, options.typeAnnotation || 'coerce');
123
125
  } else if (this.checkSubtype(expected, actual)) {
124
126
  return null;
125
127
  }
@@ -28,6 +28,9 @@ export type CollatorTypeT = {
28
28
  export type FormattedTypeT = {
29
29
  kind: 'formatted';
30
30
  };
31
+ export type PaddingTypeT = {
32
+ kind: 'padding';
33
+ };
31
34
  export type ResolvedImageTypeT = {
32
35
  kind: 'resolvedImage';
33
36
  };
@@ -35,7 +38,7 @@ export type ResolvedImageTypeT = {
35
38
  export type EvaluationKind = 'constant' | 'source' | 'camera' | 'composite';
36
39
 
37
40
  export type Type = NullTypeT | NumberTypeT | StringTypeT | BooleanTypeT | ColorTypeT | ObjectTypeT | ValueTypeT | // eslint-disable-line no-use-before-define
38
- ArrayType | ErrorTypeT | CollatorTypeT | FormattedTypeT | ResolvedImageTypeT;
41
+ ArrayType | ErrorTypeT | CollatorTypeT | FormattedTypeT | PaddingTypeT | ResolvedImageTypeT;
39
42
 
40
43
  export type ArrayType = {
41
44
  kind: 'array';
@@ -55,6 +58,7 @@ export const ValueType = {kind: 'value'} as ValueTypeT;
55
58
  export const ErrorType = {kind: 'error'} as ErrorTypeT;
56
59
  export const CollatorType = {kind: 'collator'} as CollatorTypeT;
57
60
  export const FormattedType = {kind: 'formatted'} as FormattedTypeT;
61
+ export const PaddingType = {kind: 'padding'} as PaddingTypeT;
58
62
  export const ResolvedImageType = {kind: 'resolvedImage'} as ResolvedImageTypeT;
59
63
 
60
64
  export function array(itemType: Type, N?: number | null): ArrayType {
@@ -85,6 +89,7 @@ const valueMemberTypes = [
85
89
  FormattedType,
86
90
  ObjectType,
87
91
  array(ValueType),
92
+ PaddingType,
88
93
  ResolvedImageType
89
94
  ];
90
95
 
@@ -3,8 +3,9 @@ import assert from 'assert';
3
3
  import Color from '../util/color';
4
4
  import Collator from './types/collator';
5
5
  import Formatted from './types/formatted';
6
+ import Padding from '../util/padding';
6
7
  import ResolvedImage from './types/resolved_image';
7
- import {NullType, NumberType, StringType, BooleanType, ColorType, ObjectType, ValueType, CollatorType, FormattedType, ResolvedImageType, array} from './types';
8
+ import {NullType, NumberType, StringType, BooleanType, ColorType, ObjectType, ValueType, CollatorType, FormattedType, ResolvedImageType, array, PaddingType} from './types';
8
9
 
9
10
  import type {Type} from './types';
10
11
 
@@ -27,7 +28,7 @@ export function validateRGBA(r: unknown, g: unknown, b: unknown, a?: unknown): s
27
28
  return null;
28
29
  }
29
30
 
30
- export type Value = null | string | boolean | number | Color | Collator | Formatted | ResolvedImage | ReadonlyArray<Value> | {
31
+ export type Value = null | string | boolean | number | Color | Collator | Formatted | Padding | ResolvedImage | ReadonlyArray<Value> | {
31
32
  readonly [x: string]: Value;
32
33
  };
33
34
 
@@ -46,6 +47,8 @@ export function isValue(mixed: unknown): boolean {
46
47
  return true;
47
48
  } else if (mixed instanceof Formatted) {
48
49
  return true;
50
+ } else if (mixed instanceof Padding) {
51
+ return true;
49
52
  } else if (mixed instanceof ResolvedImage) {
50
53
  return true;
51
54
  } else if (Array.isArray(mixed)) {
@@ -82,6 +85,8 @@ export function typeOf(value: Value): Type {
82
85
  return CollatorType;
83
86
  } else if (value instanceof Formatted) {
84
87
  return FormattedType;
88
+ } else if (value instanceof Padding) {
89
+ return PaddingType;
85
90
  } else if (value instanceof ResolvedImage) {
86
91
  return ResolvedImageType;
87
92
  } else if (Array.isArray(value)) {
@@ -113,11 +118,11 @@ export function toString(value: Value) {
113
118
  return '';
114
119
  } else if (type === 'string' || type === 'number' || type === 'boolean') {
115
120
  return String(value);
116
- } else if (value instanceof Color || value instanceof Formatted || value instanceof ResolvedImage) {
121
+ } else if (value instanceof Color || value instanceof Formatted || value instanceof Padding || value instanceof ResolvedImage) {
117
122
  return value.toString();
118
123
  } else {
119
124
  return JSON.stringify(value);
120
125
  }
121
126
  }
122
127
 
123
- export {Color, Collator};
128
+ export {Color, Collator, Padding};