maplibre-gl 2.0.2 → 2.1.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.
Files changed (132) hide show
  1. package/build/generate-struct-arrays.ts +1 -1
  2. package/build/post-ts-build.js +0 -9
  3. package/build/release-notes.js +7 -32
  4. package/dist/maplibre-gl.css +1 -1
  5. package/dist/maplibre-gl.d.ts +57 -219
  6. package/dist/maplibre-gl.js +4 -4
  7. package/dist/maplibre-gl.js.map +1 -1
  8. package/package.json +37 -53
  9. package/src/css/maplibre-gl.css +21 -21
  10. package/src/data/array_types.ts +1 -1
  11. package/src/data/bucket/circle_bucket.ts +1 -1
  12. package/src/data/bucket/fill_bucket.test.ts +1 -1
  13. package/src/data/bucket/fill_bucket.ts +1 -1
  14. package/src/data/bucket/fill_extrusion_bucket.ts +1 -1
  15. package/src/data/bucket/line_bucket.test.ts +1 -1
  16. package/src/data/bucket/line_bucket.ts +1 -1
  17. package/src/data/bucket/symbol_bucket.test.ts +1 -1
  18. package/src/data/bucket/symbol_bucket.ts +4 -4
  19. package/src/data/bucket.ts +1 -1
  20. package/src/data/evaluation_feature.ts +1 -1
  21. package/src/data/feature_index.ts +1 -1
  22. package/src/data/load_geometry.ts +1 -1
  23. package/src/data/program_configuration.ts +1 -1
  24. package/src/geo/edge_insets.ts +1 -1
  25. package/src/geo/transform.test.ts +1 -1
  26. package/src/geo/transform.ts +1 -1
  27. package/src/index.ts +1 -1
  28. package/src/render/draw_debug.ts +1 -1
  29. package/src/render/draw_symbol.ts +1 -1
  30. package/src/render/glyph_manager.ts +1 -1
  31. package/src/render/painter.ts +5 -3
  32. package/src/render/program/circle_program.ts +1 -1
  33. package/src/render/program/line_program.ts +3 -3
  34. package/src/render/program/symbol_program.ts +1 -1
  35. package/src/source/geojson_source.test.ts +29 -1
  36. package/src/source/geojson_source.ts +2 -4
  37. package/src/source/geojson_wrapper.ts +1 -1
  38. package/src/source/image_source.test.ts +153 -0
  39. package/src/source/query_features.test.ts +1 -1
  40. package/src/source/query_features.ts +1 -1
  41. package/src/source/raster_dem_tile_source.test.ts +2 -1
  42. package/src/source/raster_dem_tile_source.ts +1 -1
  43. package/src/source/raster_tile_source.test.ts +2 -1
  44. package/src/source/raster_tile_source.ts +1 -1
  45. package/src/source/source_cache.test.ts +2 -2
  46. package/src/source/source_cache.ts +1 -1
  47. package/src/source/tile.test.ts +1 -1
  48. package/src/source/tile.ts +1 -1
  49. package/src/source/tile_id.test.ts +10 -12
  50. package/src/source/tile_id.ts +3 -3
  51. package/src/source/vector_tile_source.test.ts +2 -1
  52. package/src/source/vector_tile_source.ts +2 -2
  53. package/src/source/vector_tile_worker_source.test.ts +306 -0
  54. package/src/style/load_sprite.ts +2 -1
  55. package/src/style/properties.ts +1 -1
  56. package/src/style/query_utils.ts +1 -1
  57. package/src/style/style.test.ts +4 -0
  58. package/src/style/style.ts +1 -1
  59. package/src/style/style_layer/circle_style_layer.ts +1 -1
  60. package/src/style/style_layer/custom_style_layer.ts +2 -2
  61. package/src/style/style_layer/fill_extrusion_style_layer.ts +2 -2
  62. package/src/style/style_layer/fill_style_layer.ts +1 -1
  63. package/src/style/style_layer/line_style_layer.ts +1 -1
  64. package/src/style/style_layer/symbol_style_layer.ts +19 -0
  65. package/src/style/style_layer/symbol_style_layer_properties.ts +6 -0
  66. package/src/style/style_layer.ts +1 -1
  67. package/src/style-spec/CHANGELOG.md +6 -0
  68. package/src/style-spec/expression/index.ts +1 -1
  69. package/src/style-spec/feature_filter/feature_filter.test.ts +1 -1
  70. package/src/style-spec/migrate.test.ts +112 -0
  71. package/src/style-spec/package.json +1 -1
  72. package/src/style-spec/reference/v8.json +68 -2
  73. package/src/style-spec/style-spec.ts +0 -3
  74. package/src/style-spec/types.ts +2 -0
  75. package/src/style-spec/validate_spec.test.ts +29 -0
  76. package/src/symbol/anchor.ts +1 -1
  77. package/src/symbol/check_max_angle.test.ts +1 -1
  78. package/src/symbol/check_max_angle.ts +1 -1
  79. package/src/symbol/clip_line.test.ts +1 -1
  80. package/src/symbol/clip_line.ts +1 -1
  81. package/src/symbol/collision_feature.test.ts +1 -1
  82. package/src/symbol/collision_feature.ts +1 -1
  83. package/src/symbol/collision_index.ts +20 -20
  84. package/src/symbol/get_anchors.test.ts +1 -1
  85. package/src/symbol/get_anchors.ts +1 -1
  86. package/src/symbol/grid_index.test.ts +42 -19
  87. package/src/symbol/grid_index.ts +62 -33
  88. package/src/symbol/mergelines.test.ts +1 -1
  89. package/src/symbol/path_interpolator.test.ts +1 -1
  90. package/src/symbol/path_interpolator.ts +1 -1
  91. package/src/symbol/placement.ts +83 -54
  92. package/src/symbol/projection.ts +1 -1
  93. package/src/symbol/quads.ts +1 -1
  94. package/src/symbol/symbol_layout.ts +1 -1
  95. package/src/symbol/symbol_style_layer.test.ts +48 -1
  96. package/src/ui/camera.test.ts +0 -8
  97. package/src/ui/camera.ts +13 -3
  98. package/src/ui/control/navigation_control.ts +1 -1
  99. package/src/ui/events.ts +1 -1
  100. package/src/ui/handler/box_zoom.ts +1 -1
  101. package/src/ui/handler/click_zoom.ts +1 -1
  102. package/src/ui/handler/handler_util.ts +1 -1
  103. package/src/ui/handler/map_event.ts +1 -1
  104. package/src/ui/handler/mouse.ts +1 -1
  105. package/src/ui/handler/scroll_zoom.ts +1 -1
  106. package/src/ui/handler/tap_drag_zoom.ts +1 -1
  107. package/src/ui/handler/tap_recognizer.ts +1 -1
  108. package/src/ui/handler/tap_zoom.ts +1 -1
  109. package/src/ui/handler/touch_pan.ts +1 -1
  110. package/src/ui/handler/touch_zoom_rotate.ts +1 -1
  111. package/src/ui/handler_inertia.ts +1 -1
  112. package/src/ui/handler_manager.ts +1 -1
  113. package/src/ui/map.test.ts +61 -0
  114. package/src/ui/map.ts +35 -10
  115. package/src/ui/marker.test.ts +1 -1
  116. package/src/ui/marker.ts +2 -1
  117. package/src/ui/popup.test.ts +1 -1
  118. package/src/ui/popup.ts +2 -2
  119. package/src/util/ajax.test.ts +206 -0
  120. package/src/util/classify_rings.test.ts +1 -1
  121. package/src/util/classify_rings.ts +1 -1
  122. package/src/util/dom.ts +1 -1
  123. package/src/util/find_pole_of_inaccessibility.test.ts +1 -1
  124. package/src/util/find_pole_of_inaccessibility.ts +1 -1
  125. package/src/util/intersection_tests.ts +1 -1
  126. package/src/util/smart_wrap.ts +1 -1
  127. package/src/util/test/util.ts +14 -0
  128. package/src/util/util.test.ts +1 -1
  129. package/src/util/util.ts +1 -1
  130. package/CHANGELOG.md +0 -2585
  131. package/src/types/packages-types/vector-tile/index.d.ts +0 -27
  132. package/src/util/point.ts +0 -349
@@ -0,0 +1,306 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import vt from '@mapbox/vector-tile';
4
+ import Protobuf from 'pbf';
5
+ import VectorTileWorkerSource from '../source/vector_tile_worker_source';
6
+ import StyleLayerIndex from '../style/style_layer_index';
7
+ import {fakeServer, SinonFakeServer} from 'sinon';
8
+ import Actor from '../util/actor';
9
+ import {TileParameters, WorkerTileParameters} from './worker_source';
10
+ import WorkerTile from './worker_tile';
11
+ import {setPerformance} from '../util/test/util';
12
+
13
+ describe('vector tile worker source', () => {
14
+ const actor = {send: () => {}} as any as Actor;
15
+ let server: SinonFakeServer;
16
+ let originalGetEntriesByName;
17
+ let originalMeasure;
18
+ let originalMark;
19
+
20
+ beforeEach(() => {
21
+ global.fetch = null;
22
+ server = fakeServer.create();
23
+ setPerformance();
24
+ originalGetEntriesByName = window.performance.getEntriesByName;
25
+ originalMeasure = window.performance.measure;
26
+ originalMark = window.performance.mark;
27
+
28
+ });
29
+
30
+ afterEach(() => {
31
+ server.restore();
32
+ jest.clearAllMocks();
33
+ window.performance.getEntriesByName = originalGetEntriesByName;
34
+ window.performance.measure = originalMeasure;
35
+ window.performance.mark = originalMark;
36
+ });
37
+ test('VectorTileWorkerSource#abortTile aborts pending request', () => {
38
+ const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
39
+
40
+ source.loadTile({
41
+ source: 'source',
42
+ uid: 0,
43
+ tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}},
44
+ request: {url: 'http://localhost:2900/abort'}
45
+ } as any as WorkerTileParameters, (err, res) => {
46
+ expect(err).toBeFalsy();
47
+ expect(res).toBeFalsy();
48
+ });
49
+
50
+ source.abortTile({
51
+ source: 'source',
52
+ uid: 0
53
+ } as any as TileParameters, (err, res) => {
54
+ expect(err).toBeFalsy();
55
+ expect(res).toBeFalsy();
56
+ });
57
+
58
+ expect(source.loading).toEqual({});
59
+ });
60
+
61
+ test('VectorTileWorkerSource#removeTile removes loaded tile', () => {
62
+ const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
63
+
64
+ source.loaded = {
65
+ '0': {} as WorkerTile
66
+ };
67
+
68
+ source.removeTile({
69
+ source: 'source',
70
+ uid: 0
71
+ } as any as TileParameters, (err, res) => {
72
+ expect(err).toBeFalsy();
73
+ expect(res).toBeFalsy();
74
+ });
75
+
76
+ expect(source.loaded).toEqual({});
77
+ });
78
+
79
+ test('VectorTileWorkerSource#reloadTile reloads a previously-loaded tile', () => {
80
+ const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
81
+ const parse = jest.fn();
82
+
83
+ source.loaded = {
84
+ '0': {
85
+ status: 'done',
86
+ vectorTile: {},
87
+ parse
88
+ } as any as WorkerTile
89
+ };
90
+
91
+ const callback = jest.fn();
92
+ source.reloadTile({uid: 0} as any as WorkerTileParameters, callback);
93
+ expect(parse).toHaveBeenCalledTimes(1);
94
+
95
+ parse.mock.calls[0][4]();
96
+ expect(callback).toHaveBeenCalledTimes(1);
97
+ });
98
+
99
+ test('VectorTileWorkerSource#reloadTile queues a reload when parsing is in progress', () => {
100
+ const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
101
+ const parse = jest.fn();
102
+
103
+ source.loaded = {
104
+ '0': {
105
+ status: 'done',
106
+ vectorTile: {},
107
+ parse
108
+ } as any as WorkerTile
109
+ };
110
+
111
+ const callback1 = jest.fn();
112
+ const callback2 = jest.fn();
113
+ source.reloadTile({uid: 0} as any as WorkerTileParameters, callback1);
114
+ expect(parse).toHaveBeenCalledTimes(1);
115
+
116
+ source.loaded[0].status = 'parsing';
117
+ source.reloadTile({uid: 0} as any as WorkerTileParameters, callback2);
118
+ expect(parse).toHaveBeenCalledTimes(1);
119
+
120
+ parse.mock.calls[0][4]();
121
+ expect(parse).toHaveBeenCalledTimes(2);
122
+ expect(callback1).toHaveBeenCalledTimes(1);
123
+ expect(callback2).toHaveBeenCalledTimes(0);
124
+
125
+ parse.mock.calls[1][4]();
126
+ expect(callback1).toHaveBeenCalledTimes(1);
127
+ expect(callback2).toHaveBeenCalledTimes(1);
128
+ });
129
+
130
+ test('VectorTileWorkerSource#reloadTile handles multiple pending reloads', () => {
131
+ // https://github.com/mapbox/mapbox-gl-js/issues/6308
132
+ const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
133
+ const parse = jest.fn();
134
+
135
+ source.loaded = {
136
+ '0': {
137
+ status: 'done',
138
+ vectorTile: {},
139
+ parse
140
+ } as any as WorkerTile
141
+ };
142
+
143
+ const callback1 = jest.fn();
144
+ const callback2 = jest.fn();
145
+ const callback3 = jest.fn();
146
+ source.reloadTile({uid: 0} as any as WorkerTileParameters, callback1);
147
+ expect(parse).toHaveBeenCalledTimes(1);
148
+
149
+ source.loaded[0].status = 'parsing';
150
+ source.reloadTile({uid: 0} as any as WorkerTileParameters, callback2);
151
+ expect(parse).toHaveBeenCalledTimes(1);
152
+
153
+ parse.mock.calls[0][4]();
154
+ expect(parse).toHaveBeenCalledTimes(2);
155
+ expect(callback1).toHaveBeenCalledTimes(1);
156
+ expect(callback2).toHaveBeenCalledTimes(0);
157
+ expect(callback3).toHaveBeenCalledTimes(0);
158
+
159
+ source.reloadTile({uid: 0} as any as WorkerTileParameters, callback3);
160
+ expect(parse).toHaveBeenCalledTimes(2);
161
+ expect(callback1).toHaveBeenCalledTimes(1);
162
+ expect(callback2).toHaveBeenCalledTimes(0);
163
+ expect(callback3).toHaveBeenCalledTimes(0);
164
+
165
+ parse.mock.calls[1][4]();
166
+ expect(parse).toHaveBeenCalledTimes(3);
167
+ expect(callback1).toHaveBeenCalledTimes(1);
168
+ expect(callback2).toHaveBeenCalledTimes(1);
169
+ expect(callback3).toHaveBeenCalledTimes(0);
170
+
171
+ parse.mock.calls[2][4]();
172
+ expect(callback1).toHaveBeenCalledTimes(1);
173
+ expect(callback2).toHaveBeenCalledTimes(1);
174
+ expect(callback3).toHaveBeenCalledTimes(1);
175
+
176
+ });
177
+
178
+ test('VectorTileWorkerSource#reloadTile does not reparse tiles with no vectorTile data but does call callback', () => {
179
+ const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
180
+ const parse = jest.fn();
181
+
182
+ source.loaded = {
183
+ '0': {
184
+ status: 'done',
185
+ parse
186
+ } as any as WorkerTile
187
+ };
188
+
189
+ const callback = jest.fn();
190
+
191
+ source.reloadTile({uid: 0} as any as WorkerTileParameters, callback);
192
+ expect(parse).not.toHaveBeenCalled();
193
+ expect(callback).toHaveBeenCalledTimes(1);
194
+
195
+ });
196
+
197
+ test('VectorTileWorkerSource provides resource timing information', done => {
198
+ const rawTileData = fs.readFileSync(path.join(__dirname, '/../../test/fixtures/mbsv5-6-18-23.vector.pbf'));
199
+
200
+ function loadVectorData(params, callback) {
201
+ return callback(null, {
202
+ vectorTile: new vt.VectorTile(new Protobuf(rawTileData)),
203
+ rawData: rawTileData,
204
+ cacheControl: null,
205
+ expires: null
206
+ });
207
+ }
208
+
209
+ const exampleResourceTiming = {
210
+ connectEnd: 473,
211
+ connectStart: 473,
212
+ decodedBodySize: 86494,
213
+ domainLookupEnd: 473,
214
+ domainLookupStart: 473,
215
+ duration: 341,
216
+ encodedBodySize: 52528,
217
+ entryType: 'resource',
218
+ fetchStart: 473.5,
219
+ initiatorType: 'xmlhttprequest',
220
+ name: 'http://localhost:2900/faketile.pbf',
221
+ nextHopProtocol: 'http/1.1',
222
+ redirectEnd: 0,
223
+ redirectStart: 0,
224
+ requestStart: 477,
225
+ responseEnd: 815,
226
+ responseStart: 672,
227
+ secureConnectionStart: 0
228
+ };
229
+
230
+ const layerIndex = new StyleLayerIndex([{
231
+ id: 'test',
232
+ source: 'source',
233
+ 'source-layer': 'test',
234
+ type: 'fill'
235
+ }]);
236
+
237
+ const source = new VectorTileWorkerSource(actor, layerIndex, [], loadVectorData);
238
+
239
+ window.performance.getEntriesByName = jest.fn().mockReturnValue([ exampleResourceTiming ]);
240
+
241
+ source.loadTile({
242
+ source: 'source',
243
+ uid: 0,
244
+ tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}},
245
+ request: {url: 'http://localhost:2900/faketile.pbf', collectResourceTiming: true}
246
+ } as any as WorkerTileParameters, (err, res) => {
247
+ expect(err).toBeFalsy();
248
+ expect(res.resourceTiming[0]).toEqual(exampleResourceTiming);
249
+ done();
250
+ });
251
+ });
252
+
253
+ test('VectorTileWorkerSource provides resource timing information (fallback method)', done => {
254
+ const rawTileData = fs.readFileSync(path.join(__dirname, '/../../test/fixtures/mbsv5-6-18-23.vector.pbf'));
255
+
256
+ function loadVectorData(params, callback) {
257
+ return callback(null, {
258
+ vectorTile: new vt.VectorTile(new Protobuf(rawTileData)),
259
+ rawData: rawTileData,
260
+ cacheControl: null,
261
+ expires: null
262
+ });
263
+ }
264
+
265
+ const layerIndex = new StyleLayerIndex([{
266
+ id: 'test',
267
+ source: 'source',
268
+ 'source-layer': 'test',
269
+ type: 'fill'
270
+ }]);
271
+
272
+ const source = new VectorTileWorkerSource(actor, layerIndex, [], loadVectorData);
273
+
274
+ const sampleMarks = [100, 350];
275
+ const marks = {};
276
+ const measures = {};
277
+ window.performance.getEntriesByName = jest.fn().mockImplementation(name => (measures[name] || []));
278
+ window.performance.mark = jest.fn().mockImplementation(name => {
279
+ marks[name] = sampleMarks.shift();
280
+ return null;
281
+ });
282
+ window.performance.measure = jest.fn().mockImplementation((name, start, end) => {
283
+ measures[name] = measures[name] || [];
284
+ measures[name].push({
285
+ duration: marks[end] - marks[start],
286
+ entryType: 'measure',
287
+ name,
288
+ startTime: marks[start]
289
+ });
290
+ return null;
291
+ });
292
+
293
+ source.loadTile({
294
+ source: 'source',
295
+ uid: 0,
296
+ tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}},
297
+ request: {url: 'http://localhost:2900/faketile.pbf', collectResourceTiming: true}
298
+ } as any as WorkerTileParameters, (err, res) => {
299
+ expect(err).toBeFalsy();
300
+ expect(res.resourceTiming[0]).toEqual(
301
+ {'duration': 250, 'entryType': 'measure', 'name': 'http://localhost:2900/faketile.pbf', 'startTime': 100}
302
+ );
303
+ done();
304
+ });
305
+ });
306
+ });
@@ -11,10 +11,11 @@ import type {Cancelable} from '../types/cancelable';
11
11
  export default function(
12
12
  baseURL: string,
13
13
  requestManager: RequestManager,
14
+ pixelRatio: number,
14
15
  callback: Callback<{[_: string]: StyleImage}>
15
16
  ): Cancelable {
16
17
  let json: any, image, error;
17
- const format = devicePixelRatio > 1 ? '@2x' : '';
18
+ const format = pixelRatio > 1 ? '@2x' : '';
18
19
 
19
20
  let jsonRequest = getJSON(requestManager.transformRequest(requestManager.normalizeSpriteURL(baseURL, format, '.json'), ResourceType.SpriteJSON), (err?: Error | null, data?: any | null) => {
20
21
  jsonRequest = null;
@@ -730,7 +730,7 @@ export class Properties<Props> {
730
730
  defaultPropertyValues: {[K in keyof Props]: PropertyValue<unknown, any>};
731
731
  defaultTransitionablePropertyValues: {[K in keyof Props]: TransitionablePropertyValue<unknown, unknown>};
732
732
  defaultTransitioningPropertyValues: {[K in keyof Props]: TransitioningPropertyValue<unknown, unknown>};
733
- defaultPossiblyEvaluatedValues: {[K in keyof Props]: PossiblyEvaluatedPropertyValue<unknown>};;
733
+ defaultPossiblyEvaluatedValues: {[K in keyof Props]: PossiblyEvaluatedPropertyValue<unknown>};
734
734
  overridableProperties: Array<string>;
735
735
 
736
736
  constructor(properties: Props) {
@@ -1,4 +1,4 @@
1
- import Point from '../util/point';
1
+ import Point from '@mapbox/point-geometry';
2
2
 
3
3
  import type {PossiblyEvaluatedPropertyValue} from './properties';
4
4
  import type StyleLayer from '../style/style_layer';
@@ -60,6 +60,10 @@ class StubMap extends Evented {
60
60
  _getMapId() {
61
61
  return 1;
62
62
  }
63
+
64
+ getPixelRatio() {
65
+ return 1;
66
+ }
63
67
  }
64
68
 
65
69
  const getStubMap = () => new StubMap() as any;
@@ -276,7 +276,7 @@ class Style extends Evented {
276
276
  }
277
277
 
278
278
  _loadSprite(url: string) {
279
- this._spriteRequest = loadSprite(url, this.map._requestManager, (err, images) => {
279
+ this._spriteRequest = loadSprite(url, this.map._requestManager, this.map.getPixelRatio(), (err, images) => {
280
280
  this._spriteRequest = null;
281
281
  if (err) {
282
282
  this.fire(new ErrorEvent(err));
@@ -6,7 +6,7 @@ import {getMaximumPaintValue, translateDistance, translate} from '../query_utils
6
6
  import properties, {CircleLayoutPropsPossiblyEvaluated, CirclePaintPropsPossiblyEvaluated} from './circle_style_layer_properties';
7
7
  import {Transitionable, Transitioning, Layout, PossiblyEvaluated} from '../properties';
8
8
  import {mat4, vec4} from 'gl-matrix';
9
- import Point from '../../util/point';
9
+ import Point from '@mapbox/point-geometry';
10
10
  import type {FeatureState} from '../../style-spec/expression';
11
11
  import type Transform from '../../geo/transform';
12
12
  import type {Bucket, BucketParameters} from '../../data/bucket';
@@ -213,13 +213,13 @@ class CustomStyleLayer extends StyleLayer {
213
213
  if (this.implementation.onAdd) {
214
214
  this.implementation.onAdd(map, map.painter.context.gl);
215
215
  }
216
- }
216
+ };
217
217
 
218
218
  onRemove = (map: Map) => {
219
219
  if (this.implementation.onRemove) {
220
220
  this.implementation.onRemove(map, map.painter.context.gl);
221
221
  }
222
- }
222
+ };
223
223
  }
224
224
 
225
225
  export default CustomStyleLayer;
@@ -6,7 +6,7 @@ import {translateDistance, translate} from '../query_utils';
6
6
  import properties, {FillExtrusionPaintPropsPossiblyEvaluated} from './fill_extrusion_style_layer_properties';
7
7
  import {Transitionable, Transitioning, PossiblyEvaluated} from '../properties';
8
8
  import {mat4, vec4} from 'gl-matrix';
9
- import Point from '../../util/point';
9
+ import Point from '@mapbox/point-geometry';
10
10
  import type {FeatureState} from '../../style-spec/expression';
11
11
  import type {BucketParameters} from '../../data/bucket';
12
12
  import type {FillExtrusionPaintProps} from './fill_extrusion_style_layer_properties';
@@ -15,7 +15,7 @@ import type {LayerSpecification} from '../../style-spec/types';
15
15
  import type {VectorTileFeature} from '@mapbox/vector-tile';
16
16
 
17
17
  export class Point3D extends Point {
18
- z: number
18
+ z: number;
19
19
  }
20
20
 
21
21
  class FillExtrusionStyleLayer extends StyleLayer {
@@ -8,7 +8,7 @@ import {Transitionable, Transitioning, Layout, PossiblyEvaluated} from '../prope
8
8
 
9
9
  import type {FeatureState} from '../../style-spec/expression';
10
10
  import type {BucketParameters} from '../../data/bucket';
11
- import type Point from '../../util/point';
11
+ import type Point from '@mapbox/point-geometry';
12
12
  import type {FillLayoutProps, FillPaintProps} from './fill_style_layer_properties';
13
13
  import type EvaluationParameters from '../evaluation_parameters';
14
14
  import type Transform from '../../geo/transform';
@@ -1,4 +1,4 @@
1
- import Point from '../../util/point';
1
+ import Point from '@mapbox/point-geometry';
2
2
 
3
3
  import StyleLayer from '../style_layer';
4
4
  import LineBucket from '../../data/bucket/line_bucket';
@@ -185,4 +185,23 @@ class SymbolStyleLayer extends StyleLayer {
185
185
  }
186
186
  }
187
187
 
188
+ export type OverlapMode = 'never' | 'always' | 'cooperative';
189
+
190
+ export function getOverlapMode(layout: PossiblyEvaluated<SymbolLayoutProps, SymbolLayoutPropsPossiblyEvaluated>, overlapProp: 'icon-overlap', allowOverlapProp: 'icon-allow-overlap'): OverlapMode;
191
+ export function getOverlapMode(layout: PossiblyEvaluated<SymbolLayoutProps, SymbolLayoutPropsPossiblyEvaluated>, overlapProp: 'text-overlap', allowOverlapProp: 'text-allow-overlap'): OverlapMode;
192
+ export function getOverlapMode(layout: PossiblyEvaluated<SymbolLayoutProps, SymbolLayoutPropsPossiblyEvaluated>, overlapProp: 'icon-overlap' | 'text-overlap', allowOverlapProp: 'icon-allow-overlap' | 'text-allow-overlap'): OverlapMode {
193
+ let result: OverlapMode = 'never';
194
+ const overlap = layout.get(overlapProp);
195
+
196
+ if (overlap) {
197
+ // if -overlap is set, use it
198
+ result = overlap;
199
+ } else if (layout.get(allowOverlapProp)) {
200
+ // fall back to -allow-overlap, with false='never', true='always'
201
+ result = 'always';
202
+ }
203
+
204
+ return result;
205
+ }
206
+
188
207
  export default SymbolStyleLayer;
@@ -32,6 +32,7 @@ export type SymbolLayoutProps = {
32
32
  "symbol-sort-key": DataDrivenProperty<number>,
33
33
  "symbol-z-order": DataConstantProperty<"auto" | "viewport-y" | "source">,
34
34
  "icon-allow-overlap": DataConstantProperty<boolean>,
35
+ "icon-overlap": DataConstantProperty<"never" | "always" | "cooperative">,
35
36
  "icon-ignore-placement": DataConstantProperty<boolean>,
36
37
  "icon-optional": DataConstantProperty<boolean>,
37
38
  "icon-rotation-alignment": DataConstantProperty<"map" | "viewport" | "auto">,
@@ -65,6 +66,7 @@ export type SymbolLayoutProps = {
65
66
  "text-transform": DataDrivenProperty<"none" | "uppercase" | "lowercase">,
66
67
  "text-offset": DataDrivenProperty<[number, number]>,
67
68
  "text-allow-overlap": DataConstantProperty<boolean>,
69
+ "text-overlap": DataConstantProperty<"never" | "always" | "cooperative">,
68
70
  "text-ignore-placement": DataConstantProperty<boolean>,
69
71
  "text-optional": DataConstantProperty<boolean>,
70
72
  };
@@ -76,6 +78,7 @@ export type SymbolLayoutPropsPossiblyEvaluated = {
76
78
  "symbol-sort-key": PossiblyEvaluatedPropertyValue<number>,
77
79
  "symbol-z-order": "auto" | "viewport-y" | "source",
78
80
  "icon-allow-overlap": boolean,
81
+ "icon-overlap": "never" | "always" | "cooperative",
79
82
  "icon-ignore-placement": boolean,
80
83
  "icon-optional": boolean,
81
84
  "icon-rotation-alignment": "map" | "viewport" | "auto",
@@ -109,6 +112,7 @@ export type SymbolLayoutPropsPossiblyEvaluated = {
109
112
  "text-transform": PossiblyEvaluatedPropertyValue<"none" | "uppercase" | "lowercase">,
110
113
  "text-offset": PossiblyEvaluatedPropertyValue<[number, number]>,
111
114
  "text-allow-overlap": boolean,
115
+ "text-overlap": "never" | "always" | "cooperative",
112
116
  "text-ignore-placement": boolean,
113
117
  "text-optional": boolean,
114
118
  };
@@ -120,6 +124,7 @@ const layout: Properties<SymbolLayoutProps> = new Properties({
120
124
  "symbol-sort-key": new DataDrivenProperty(styleSpec["layout_symbol"]["symbol-sort-key"] as any as StylePropertySpecification),
121
125
  "symbol-z-order": new DataConstantProperty(styleSpec["layout_symbol"]["symbol-z-order"] as any as StylePropertySpecification),
122
126
  "icon-allow-overlap": new DataConstantProperty(styleSpec["layout_symbol"]["icon-allow-overlap"] as any as StylePropertySpecification),
127
+ "icon-overlap": new DataConstantProperty(styleSpec["layout_symbol"]["icon-overlap"] as any as StylePropertySpecification),
123
128
  "icon-ignore-placement": new DataConstantProperty(styleSpec["layout_symbol"]["icon-ignore-placement"] as any as StylePropertySpecification),
124
129
  "icon-optional": new DataConstantProperty(styleSpec["layout_symbol"]["icon-optional"] as any as StylePropertySpecification),
125
130
  "icon-rotation-alignment": new DataConstantProperty(styleSpec["layout_symbol"]["icon-rotation-alignment"] as any as StylePropertySpecification),
@@ -153,6 +158,7 @@ const layout: Properties<SymbolLayoutProps> = new Properties({
153
158
  "text-transform": new DataDrivenProperty(styleSpec["layout_symbol"]["text-transform"] as any as StylePropertySpecification),
154
159
  "text-offset": new DataDrivenProperty(styleSpec["layout_symbol"]["text-offset"] as any as StylePropertySpecification),
155
160
  "text-allow-overlap": new DataConstantProperty(styleSpec["layout_symbol"]["text-allow-overlap"] as any as StylePropertySpecification),
161
+ "text-overlap": new DataConstantProperty(styleSpec["layout_symbol"]["text-overlap"] as any as StylePropertySpecification),
156
162
  "text-ignore-placement": new DataConstantProperty(styleSpec["layout_symbol"]["text-ignore-placement"] as any as StylePropertySpecification),
157
163
  "text-optional": new DataConstantProperty(styleSpec["layout_symbol"]["text-optional"] as any as StylePropertySpecification),
158
164
  });
@@ -13,7 +13,7 @@ import {supportsPropertyExpression} from '../style-spec/util/properties';
13
13
 
14
14
  import type {FeatureState} from '../style-spec/expression';
15
15
  import type {Bucket} from '../data/bucket';
16
- import type Point from '../util/point';
16
+ import type Point from '@mapbox/point-geometry';
17
17
  import type {FeatureFilter} from '../style-spec/feature_filter';
18
18
  import type {TransitionParameters, PropertyValue} from './properties';
19
19
  import EvaluationParameters from './evaluation_parameters';
@@ -1,3 +1,9 @@
1
+ ## 15.1.0
2
+
3
+ ### ✨ Features and improvements
4
+ * Add `icon-overlap` and `text-overlap` symbol layout properties [#347](https://github.com/maplibre/maplibre-gl-js/pull/347)
5
+ * Deprecate `icon-allow-overlap` and `text-allow-overlap` symbol layout properties. `icon-overlap` and `text-overlap` are their replacements.
6
+
1
7
  ## 15.0.0
2
8
 
3
9
  ### Breaking changes
@@ -23,7 +23,7 @@ import type {Result} from '../util/result';
23
23
  import type {InterpolationType} from './definitions/interpolate';
24
24
  import type {PropertyValueSpecification} from '../types';
25
25
  import type {FormattedSection} from './types/formatted';
26
- import type Point from '../../util/point';
26
+ import type Point from '@mapbox/point-geometry';
27
27
  import type {CanonicalTileID} from '../../source/tile_id';
28
28
 
29
29
  export type Feature = {
@@ -1,7 +1,7 @@
1
1
  import {default as createFilter, isExpressionFilter} from '.';
2
2
 
3
3
  import convertFilter from './convert';
4
- import Point from '../../util/point';
4
+ import Point from '@mapbox/point-geometry';
5
5
  import MercatorCoordinate from '../../geo/mercator_coordinate';
6
6
  import EXTENT from '../../data/extent';
7
7
  import {CanonicalTileID} from '../../source/tile_id';
@@ -0,0 +1,112 @@
1
+ import migrate from './migrate';
2
+ import * as spec from './style-spec';
3
+ import v8 from './reference/v8.json';
4
+ import validate from './validate_style';
5
+
6
+ describe('migrate', () => {
7
+ test('does not migrate from version 5', () => {
8
+ expect(() => {
9
+ migrate({version: 5, layers: []});
10
+ }).toThrow(new Error('Cannot migrate from 5'));
11
+ });
12
+
13
+ test('does not migrate from version 6', () => {
14
+ expect(() => {
15
+ migrate({version: 6, layers: []});
16
+ }).toThrow(new Error('Cannot migrate from 6'));
17
+ });
18
+
19
+ test('migrates to latest version from version 7', () => {
20
+ expect(migrate({version: 7, layers: []}).version).toEqual(spec.latest.$version);
21
+ });
22
+
23
+ test('converts token strings to expressions', () => {
24
+ const migrated = migrate({
25
+ version: 8,
26
+ layers: [{
27
+ id: '1',
28
+ type: 'symbol',
29
+ layout: {'text-field': 'a{x}', 'icon-image': '{y}'}
30
+ }]
31
+ });
32
+ expect(migrated.layers[0].layout['text-field']).toEqual(['concat', 'a', ['get', 'x']]);
33
+ expect(migrated.layers[0].layout['icon-image']).toEqual(['to-string', ['get', 'y']]);
34
+ });
35
+
36
+ test('converts stop functions to expressions', () => {
37
+ const migrated = migrate({
38
+ version: 8,
39
+ layers: [{
40
+ id: '1',
41
+ type: 'background',
42
+ paint: {
43
+ 'background-opacity': {
44
+ base: 1.0,
45
+ stops: [[0, 1], [10, 0.72]]
46
+ }
47
+ }
48
+ }, {
49
+ id: '2',
50
+ type: 'background',
51
+ paint: {
52
+ 'background-opacity': {
53
+ base: 1.0,
54
+ stops: [[0, [1, 2]], [10, [0.72, 0.98]]]
55
+ }
56
+ }
57
+ }]
58
+ });
59
+ expect(migrated.layers[0].paint['background-opacity']).toEqual([
60
+ 'interpolate',
61
+ ['linear'],
62
+ ['zoom'],
63
+ 0,
64
+ 1,
65
+ 10,
66
+ 0.72
67
+ ]);
68
+ expect(migrated.layers[1].paint['background-opacity']).toEqual([
69
+ 'interpolate',
70
+ ['linear'],
71
+ ['zoom'],
72
+ 0,
73
+ ['literal', [1, 2]],
74
+ 10,
75
+ ['literal', [0.72, 0.98]]
76
+ ]);
77
+ });
78
+
79
+ test('converts categorical function on resolvedImage type to valid expression', () => {
80
+ const migrated = migrate({
81
+ version: 8,
82
+ sources: {
83
+ streets: {
84
+ url: 'mapbox://mapbox.streets',
85
+ type: 'vector'
86
+ }
87
+ },
88
+ layers: [{
89
+ id: '1',
90
+ source: 'streets',
91
+ 'source-layer': 'labels',
92
+ type: 'symbol',
93
+ layout: {
94
+ 'icon-image': {
95
+ base: 1,
96
+ type: 'categorical',
97
+ property: 'type',
98
+ stops: [['park', 'some-icon']]
99
+ }
100
+ }
101
+ }]
102
+ });
103
+ expect(migrated.layers[0].layout['icon-image']).toEqual([
104
+ 'match',
105
+ ['get', 'type' ],
106
+ 'park',
107
+ 'some-icon',
108
+ ''
109
+ ]);
110
+ expect(validate(migrated, v8)).toEqual([]);
111
+ });
112
+ });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@maplibre/maplibre-gl-style-spec",
3
3
  "description": "a specification for maplibre gl styles",
4
- "version": "15.0.0",
4
+ "version": "15.1.0",
5
5
  "author": "MapLibre",
6
6
  "keywords": [
7
7
  "mapbox",