@mapwhit/tilerenderer 0.47.1 → 0.47.2

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 (56) hide show
  1. package/build/min/package.json +1 -1
  2. package/package.json +1 -2
  3. package/src/data/array_types.js +1 -1
  4. package/src/data/bucket/circle_bucket.js +1 -1
  5. package/src/data/bucket/fill_bucket.js +1 -1
  6. package/src/data/bucket/fill_extrusion_bucket.js +1 -1
  7. package/src/data/bucket/heatmap_bucket.js +1 -1
  8. package/src/data/bucket/line_bucket.js +1 -1
  9. package/src/data/bucket/symbol_bucket.js +1 -1
  10. package/src/data/dem_data.js +1 -1
  11. package/src/data/feature_index.js +43 -82
  12. package/src/data/program_configuration.js +1 -1
  13. package/src/data/segment.js +2 -2
  14. package/src/gl/color_mode.js +6 -6
  15. package/src/index.js +2 -0
  16. package/src/render/glyph_atlas.js +1 -1
  17. package/src/render/glyph_manager.js +43 -48
  18. package/src/render/image_atlas.js +1 -1
  19. package/src/render/image_manager.js +9 -37
  20. package/src/source/geojson_source.js +49 -93
  21. package/src/source/geojson_worker_source.js +33 -134
  22. package/src/source/image_source.js +9 -14
  23. package/src/source/load_tilejson.js +27 -34
  24. package/src/source/raster_dem_tile_source.js +27 -40
  25. package/src/source/raster_tile_source.js +53 -62
  26. package/src/source/rtl_text_plugin.js +2 -1
  27. package/src/source/source_cache.js +22 -20
  28. package/src/source/source_state.js +17 -26
  29. package/src/source/tile_id.js +1 -1
  30. package/src/source/vector_tile_source.js +56 -73
  31. package/src/source/vector_tile_worker_source.js +20 -85
  32. package/src/source/worker.js +38 -95
  33. package/src/source/worker_tile.js +39 -84
  34. package/src/style/load_sprite.js +14 -17
  35. package/src/style/properties.js +1 -1
  36. package/src/style/style.js +22 -22
  37. package/src/style/style_layer_index.js +17 -23
  38. package/src/style-spec/reference/v8.json +2 -2
  39. package/src/symbol/anchor.js +1 -1
  40. package/src/symbol/collision_index.js +23 -16
  41. package/src/symbol/grid_index.js +176 -182
  42. package/src/symbol/mergelines.js +48 -48
  43. package/src/symbol/opacity_state.js +1 -1
  44. package/src/ui/camera.js +82 -85
  45. package/src/ui/map.js +5 -32
  46. package/src/util/actor.js +46 -42
  47. package/src/util/browser.js +6 -0
  48. package/src/util/dictionary_coder.js +13 -21
  49. package/src/util/dispatcher.js +14 -17
  50. package/src/util/image.js +1 -1
  51. package/src/util/loader/image.js +11 -11
  52. package/src/util/polyfill.js +16 -0
  53. package/src/util/task_queue.js +39 -43
  54. package/src/util/transfer_registry.js +167 -0
  55. package/src/util/web_worker_transfer.js +5 -190
  56. package/src/source/raster_dem_tile_worker_source.js +0 -26
@@ -1,20 +1,20 @@
1
+ require('../util/polyfill');
2
+
1
3
  const Actor = require('../util/actor');
2
4
 
3
5
  const StyleLayerIndex = require('../style/style_layer_index');
4
6
  const VectorTileWorkerSource = require('./vector_tile_worker_source');
5
- const RasterDEMTileWorkerSource = require('./raster_dem_tile_worker_source');
6
7
  const GeoJSONWorkerSource = require('./geojson_worker_source');
7
8
  const assert = require('assert');
8
9
  const { plugin: globalRTLTextPlugin } = require('./rtl_text_plugin');
10
+ const DEMData = require('../data/dem_data');
9
11
 
10
- /**
11
- * @private
12
- */
13
12
  class Worker {
14
13
  constructor(self) {
15
14
  this.self = self;
16
15
  this.actor = new Actor(self, this);
17
16
 
17
+ this.actors = {};
18
18
  this.layerIndexes = {};
19
19
 
20
20
  this.workerSourceTypes = {
@@ -24,7 +24,6 @@ class Worker {
24
24
 
25
25
  // [mapId][sourceType][sourceName] => worker source instance
26
26
  this.workerSources = {};
27
- this.demWorkerSources = {};
28
27
 
29
28
  this.self.registerWorkerSource = (name, WorkerSource) => {
30
29
  if (this.workerSourceTypes[name]) {
@@ -42,63 +41,33 @@ class Worker {
42
41
  };
43
42
  }
44
43
 
45
- setLayers(mapId, layers, callback) {
44
+ setLayers(mapId, layers) {
46
45
  this.getLayerIndex(mapId).replace(layers);
47
- callback();
48
46
  }
49
47
 
50
- updateLayers(mapId, params, callback) {
48
+ updateLayers(mapId, params) {
51
49
  this.getLayerIndex(mapId).update(params.layers, params.removedIds);
52
- callback();
53
- }
54
-
55
- loadTile(mapId, params, callback) {
56
- assert(params.type);
57
- this.getWorkerSource(mapId, params.type, params.source).loadTile(params, callback);
58
- }
59
-
60
- loadDEMTile(mapId, params, callback) {
61
- this.getDEMWorkerSource(mapId, params.source).loadTile(params, callback);
62
50
  }
63
51
 
64
- reloadTile(mapId, params, callback) {
52
+ loadTile(mapId, params) {
65
53
  assert(params.type);
66
- this.getWorkerSource(mapId, params.type, params.source).reloadTile(params, callback);
54
+ return this.getWorkerSource(mapId, params.type, params.source).loadTile(params);
67
55
  }
68
56
 
69
- abortTile(mapId, params, callback) {
70
- assert(params.type);
71
- this.getWorkerSource(mapId, params.type, params.source).abortTile(params, callback);
72
- }
73
-
74
- removeTile(mapId, params, callback) {
75
- assert(params.type);
76
- this.getWorkerSource(mapId, params.type, params.source).removeTile(params, callback);
57
+ loadDEMTile(mapId, params) {
58
+ const { uid, rawImageData, encoding } = params;
59
+ return new DEMData(uid, rawImageData, encoding);
77
60
  }
78
61
 
79
- removeDEMTile(mapId, params) {
80
- this.getDEMWorkerSource(mapId, params.source).removeTile(params);
81
- }
62
+ removeSource(mapId, params) {
63
+ const { type, source } = params;
64
+ assert(type);
65
+ assert(source);
82
66
 
83
- removeSource(mapId, params, callback) {
84
- assert(params.type);
85
- assert(params.source);
86
-
87
- if (
88
- !this.workerSources[mapId] ||
89
- !this.workerSources[mapId][params.type] ||
90
- !this.workerSources[mapId][params.type][params.source]
91
- ) {
92
- return;
93
- }
94
-
95
- const worker = this.workerSources[mapId][params.type][params.source];
96
- delete this.workerSources[mapId][params.type][params.source];
97
-
98
- if (worker.removeSource !== undefined) {
99
- worker.removeSource(params, callback);
100
- } else {
101
- callback();
67
+ const worker = this.workerSources?.[mapId]?.[type]?.[source];
68
+ if (worker) {
69
+ delete this.workerSources[mapId][type][source];
70
+ worker.removeSource?.(params);
102
71
  }
103
72
  }
104
73
 
@@ -108,65 +77,39 @@ class Worker {
108
77
  * function taking `(name, workerSourceObject)`.
109
78
  * @private
110
79
  */
111
- loadWorkerSource(map, params, callback) {
112
- try {
113
- this.self.importScripts(params.url);
114
- callback();
115
- } catch (e) {
116
- callback(e.toString());
117
- }
80
+ loadWorkerSource(map, params) {
81
+ this.self.importScripts(params.url);
118
82
  }
119
83
 
120
- loadRTLTextPlugin(map, pluginURL, callback) {
121
- try {
84
+ loadRTLTextPlugin(map, pluginURL) {
85
+ if (!globalRTLTextPlugin.isLoaded()) {
86
+ this.self.importScripts(pluginURL);
122
87
  if (!globalRTLTextPlugin.isLoaded()) {
123
- this.self.importScripts(pluginURL);
124
- callback(
125
- globalRTLTextPlugin.isLoaded()
126
- ? null
127
- : new Error(`RTL Text Plugin failed to import scripts from ${pluginURL}`)
128
- );
88
+ throw new Error(`RTL Text Plugin failed to import scripts from ${pluginURL}`);
129
89
  }
130
- } catch (e) {
131
- callback(e.toString());
132
90
  }
133
91
  }
134
92
 
135
93
  getLayerIndex(mapId) {
136
- let layerIndexes = this.layerIndexes[mapId];
137
- if (!layerIndexes) {
138
- layerIndexes = this.layerIndexes[mapId] = new StyleLayerIndex();
139
- }
140
- return layerIndexes;
94
+ return (this.layerIndexes[mapId] ??= new StyleLayerIndex());
141
95
  }
142
96
 
143
- getWorkerSource(mapId, type, source) {
144
- if (!this.workerSources[mapId]) this.workerSources[mapId] = {};
145
- if (!this.workerSources[mapId][type]) this.workerSources[mapId][type] = {};
146
-
147
- if (!this.workerSources[mapId][type][source]) {
148
- // use a wrapped actor so that we can attach a target mapId param
149
- // to any messages invoked by the WorkerSource
150
- const actor = {
151
- send: (type, data, callback) => {
152
- this.actor.send(type, data, callback, mapId);
153
- }
154
- };
155
-
156
- this.workerSources[mapId][type][source] = new this.workerSourceTypes[type](actor, this.getLayerIndex(mapId));
157
- }
158
-
159
- return this.workerSources[mapId][type][source];
97
+ getActor(mapId) {
98
+ return (this.actors[mapId] ??= {
99
+ send: (type, data) => this.actor.send(type, data, mapId)
100
+ });
160
101
  }
161
102
 
162
- getDEMWorkerSource(mapId, source) {
163
- if (!this.demWorkerSources[mapId]) this.demWorkerSources[mapId] = {};
103
+ getWorkerSource(mapId, type, source) {
104
+ this.workerSources[mapId] ??= {};
105
+ this.workerSources[mapId][type] ??= {};
164
106
 
165
- if (!this.demWorkerSources[mapId][source]) {
166
- this.demWorkerSources[mapId][source] = new RasterDEMTileWorkerSource();
167
- }
107
+ return (this.workerSources[mapId][type][source] ??= this.createWorkerSource(type, mapId));
108
+ }
168
109
 
169
- return this.demWorkerSources[mapId][source];
110
+ createWorkerSource(type, mapId) {
111
+ const WorkerSource = this.workerSourceTypes[type];
112
+ return new WorkerSource(this.getActor(mapId), this.getLayerIndex(mapId));
170
113
  }
171
114
  }
172
115
 
@@ -2,7 +2,7 @@ const FeatureIndex = require('../data/feature_index');
2
2
 
3
3
  const { performSymbolLayout } = require('../symbol/symbol_layout');
4
4
  const { CollisionBoxArray } = require('../data/array_types');
5
- const DictionaryCoder = require('../util/dictionary_coder');
5
+ const dictionaryCoder = require('../util/dictionary_coder');
6
6
  const SymbolBucket = require('../data/bucket/symbol_bucket');
7
7
  const LineBucket = require('../data/bucket/line_bucket');
8
8
  const FillBucket = require('../data/bucket/fill_bucket');
@@ -33,12 +33,12 @@ class WorkerTile {
33
33
  this.showCollisionBoxes = params.showCollisionBoxes;
34
34
  }
35
35
 
36
- parse(data, layerIndex, actor, callback) {
36
+ async parse(data, layerIndex, actor) {
37
37
  this.status = 'parsing';
38
38
  this.data = data;
39
39
 
40
40
  this.collisionBoxArray = new CollisionBoxArray();
41
- const sourceLayerCoder = new DictionaryCoder(Object.keys(data.layers).sort());
41
+ const sourceLayerCoder = dictionaryCoder(Object.keys(data.layers));
42
42
 
43
43
  const featureIndex = new FeatureIndex(this.tileID);
44
44
  featureIndex.bucketLayerIDs = [];
@@ -99,92 +99,47 @@ class WorkerTile {
99
99
  }
100
100
  }
101
101
 
102
- let error;
103
- let glyphMap;
104
- let iconMap;
105
- let patternMap;
106
-
107
102
  const stacks = mapObject(options.glyphDependencies, glyphs => Object.keys(glyphs).map(Number));
108
- if (Object.keys(stacks).length) {
109
- actor.send('getGlyphs', { uid: this.uid, stacks }, (err, result) => {
110
- if (!error) {
111
- error = err;
112
- glyphMap = result;
113
- maybePrepare.call(this);
114
- }
115
- });
116
- } else {
117
- glyphMap = {};
118
- }
119
-
120
103
  const icons = Object.keys(options.iconDependencies);
121
- if (icons.length) {
122
- actor.send('getImages', { icons }, (err, result) => {
123
- if (!error) {
124
- error = err;
125
- iconMap = result;
126
- maybePrepare.call(this);
127
- }
128
- });
129
- } else {
130
- iconMap = {};
131
- }
132
-
133
104
  const patterns = Object.keys(options.patternDependencies);
134
- if (patterns.length) {
135
- actor.send('getImages', { icons: patterns }, (err, result) => {
136
- if (!error) {
137
- error = err;
138
- patternMap = result;
139
- maybePrepare.call(this);
140
- }
141
- });
142
- } else {
143
- patternMap = {};
144
- }
145
-
146
- maybePrepare.call(this);
147
-
148
- function maybePrepare() {
149
- if (error) {
150
- return callback(error);
151
- }
152
- if (glyphMap && iconMap && patternMap) {
153
- const glyphAtlas = new GlyphAtlas(glyphMap);
154
- const imageAtlas = new ImageAtlas(iconMap, patternMap);
155
-
156
- for (const key in buckets) {
157
- const bucket = buckets[key];
158
- if (bucket instanceof SymbolBucket) {
159
- recalculateLayers(bucket.layers, this.zoom);
160
- performSymbolLayout(
161
- bucket,
162
- glyphMap,
163
- glyphAtlas.positions,
164
- iconMap,
165
- imageAtlas.iconPositions,
166
- this.showCollisionBoxes
167
- );
168
- } else if (
169
- bucket.hasPattern &&
170
- (bucket instanceof LineBucket || bucket instanceof FillBucket || bucket instanceof FillExtrusionBucket)
171
- ) {
172
- recalculateLayers(bucket.layers, this.zoom);
173
- bucket.addFeatures(options, imageAtlas.patternPositions);
174
- }
175
- }
176
-
177
- this.status = 'done';
178
-
179
- callback(null, {
180
- buckets: values(buckets).filter(b => !b.isEmpty()),
181
- featureIndex,
182
- collisionBoxArray: this.collisionBoxArray,
183
- glyphAtlasImage: glyphAtlas.image,
184
- imageAtlas
185
- });
105
+ const tasks = [
106
+ Object.keys(stacks).length ? actor.send('getGlyphs', { uid: this.uid, stacks }) : {},
107
+ icons.length ? actor.send('getImages', { icons }) : {},
108
+ patterns.length ? actor.send('getImages', { icons: patterns }) : {}
109
+ ];
110
+ const [glyphMap, iconMap, patternMap] = await Promise.all(tasks);
111
+ const glyphAtlas = new GlyphAtlas(glyphMap);
112
+ const imageAtlas = new ImageAtlas(iconMap, patternMap);
113
+
114
+ for (const key in buckets) {
115
+ const bucket = buckets[key];
116
+ if (bucket instanceof SymbolBucket) {
117
+ recalculateLayers(bucket.layers, this.zoom);
118
+ performSymbolLayout(
119
+ bucket,
120
+ glyphMap,
121
+ glyphAtlas.positions,
122
+ iconMap,
123
+ imageAtlas.iconPositions,
124
+ this.showCollisionBoxes
125
+ );
126
+ } else if (
127
+ bucket.hasPattern &&
128
+ (bucket instanceof LineBucket || bucket instanceof FillBucket || bucket instanceof FillExtrusionBucket)
129
+ ) {
130
+ recalculateLayers(bucket.layers, this.zoom);
131
+ bucket.addFeatures(options, imageAtlas.patternPositions);
186
132
  }
187
133
  }
134
+
135
+ this.status = 'done';
136
+ return {
137
+ buckets: values(buckets).filter(b => !b.isEmpty()),
138
+ featureIndex,
139
+ collisionBoxArray: this.collisionBoxArray,
140
+ glyphAtlasImage: glyphAtlas.image,
141
+ imageAtlas
142
+ };
188
143
  }
189
144
  }
190
145
 
@@ -4,23 +4,20 @@ const loadImage = require('../util/loader/image');
4
4
 
5
5
  module.exports = loadSprite;
6
6
 
7
- function loadSprite(sprite, callback) {
8
- loadImage(sprite.image, (error, image) => {
9
- const { json } = sprite;
10
- if (error) {
11
- callback(error);
12
- } else if (json && image) {
13
- const imageData = browser.getImageData(image);
14
- const result = {};
7
+ async function loadSprite(sprite) {
8
+ const image = await loadImage(sprite.image);
9
+ const { json } = sprite;
10
+ if (json && image) {
11
+ const imageData = browser.getImageData(image);
12
+ const result = {};
15
13
 
16
- for (const id in json) {
17
- const { width, height, x, y, sdf, pixelRatio } = json[id];
18
- const data = new RGBAImage({ width, height });
19
- RGBAImage.copy(imageData, data, { x, y }, { x: 0, y: 0 }, { width, height });
20
- result[id] = { data, pixelRatio, sdf };
21
- }
22
-
23
- callback(null, result);
14
+ for (const id in json) {
15
+ const { width, height, x, y, sdf, pixelRatio } = json[id];
16
+ const data = new RGBAImage({ width, height });
17
+ RGBAImage.copy(imageData, data, { x, y }, { x: 0, y: 0 }, { width, height });
18
+ result[id] = { data, pixelRatio, sdf };
24
19
  }
25
- });
20
+
21
+ return result;
22
+ }
26
23
  }
@@ -4,7 +4,7 @@ const { clone } = require('../util/object');
4
4
  const { easeCubicInOut } = require('../util/util');
5
5
  const interpolate = require('../style-spec/util/interpolate');
6
6
  const { normalizePropertyExpression } = require('../style-spec/expression');
7
- const { register } = require('../util/web_worker_transfer');
7
+ const { register } = require('../util/transfer_registry');
8
8
  const EvaluationParameters = require('./evaluation_parameters');
9
9
 
10
10
  /**
@@ -46,7 +46,9 @@ class Style extends Evented {
46
46
 
47
47
  const self = this;
48
48
  this._rtlTextPluginCallback = Style.registerForPluginAvailability(args => {
49
- self.dispatcher.broadcast('loadRTLTextPlugin', args.pluginURL, args.completionCallback);
49
+ self.dispatcher
50
+ .broadcast('loadRTLTextPlugin', args.pluginURL)
51
+ .then(_ => args.completionCallback(), args.completionCallback);
50
52
  for (const id in self.sourceCaches) {
51
53
  self.sourceCaches[id].reload(); // Should be a no-op if the plugin loads before any tiles load
52
54
  }
@@ -93,20 +95,20 @@ class Style extends Evented {
93
95
  }
94
96
 
95
97
  if (json.sprite) {
96
- loadSprite(json.sprite, (err, images) => {
97
- if (err) {
98
- this.fire(new ErrorEvent(err));
99
- } else if (images) {
100
- for (const id in images) {
101
- this.imageManager.addImage(id, images[id]);
98
+ loadSprite(json.sprite)
99
+ .then(images => {
100
+ if (images) {
101
+ for (const id in images) {
102
+ this.imageManager.addImage(id, images[id]);
103
+ }
102
104
  }
103
- }
104
105
 
105
- this.imageManager.setLoaded(true);
106
- this.fire(new Event('data', { dataType: 'style' }));
107
- });
106
+ this.imageManager.setLoaded();
107
+ this.fire(new Event('data', { dataType: 'style' }));
108
+ })
109
+ .catch(err => this.fire(new ErrorEvent(err)));
108
110
  } else {
109
- this.imageManager.setLoaded(true);
111
+ this.imageManager.setLoaded();
110
112
  }
111
113
 
112
114
  this.glyphManager.setGlyphsLoader(json.glyphs);
@@ -776,14 +778,12 @@ class Style extends Evented {
776
778
  return callback(null, null);
777
779
  }
778
780
 
779
- this.dispatcher.broadcast(
780
- 'loadWorkerSource',
781
- {
781
+ this.dispatcher
782
+ .broadcast('loadWorkerSource', {
782
783
  name: name,
783
784
  url: SourceType.workerSourceURL
784
- },
785
- callback
786
- );
785
+ })
786
+ .then(data => callback(null, data), callback);
787
787
  }
788
788
 
789
789
  getLight() {
@@ -939,12 +939,12 @@ class Style extends Evented {
939
939
 
940
940
  // Callbacks from web workers
941
941
 
942
- getImages(mapId, params, callback) {
943
- this.imageManager.getImages(params.icons, callback);
942
+ getImages(_mapId, { icons }) {
943
+ return this.imageManager.getImages(icons);
944
944
  }
945
945
 
946
- getGlyphs(mapId, params, callback) {
947
- return this.glyphManager.getGlyphs(params.stacks, callback);
946
+ getGlyphs(_mapId, { stacks }) {
947
+ return this.glyphManager.getGlyphs(stacks);
948
948
  }
949
949
  }
950
950
 
@@ -5,54 +5,48 @@ const featureFilter = require('../style-spec/feature_filter');
5
5
  const groupByLayout = require('../style-spec/group_by_layout');
6
6
 
7
7
  class StyleLayerIndex {
8
+ #layerConfigs = {};
9
+ #layers = {};
10
+
8
11
  constructor(layerConfigs) {
9
12
  if (layerConfigs) {
10
- this.replace(layerConfigs);
13
+ this.update(layerConfigs);
11
14
  }
12
15
  }
13
16
 
14
17
  replace(layerConfigs) {
15
- this._layerConfigs = {};
16
- this._layers = {};
17
- this.update(layerConfigs, []);
18
+ this.#layerConfigs = {};
19
+ this.#layers = {};
20
+ this.update(layerConfigs);
18
21
  }
19
22
 
20
- update(layerConfigs, removedIds) {
23
+ update(layerConfigs, removedIds = []) {
21
24
  for (const layerConfig of layerConfigs) {
22
- this._layerConfigs[layerConfig.id] = layerConfig;
25
+ this.#layerConfigs[layerConfig.id] = layerConfig;
23
26
 
24
- const layer = (this._layers[layerConfig.id] = createStyleLayer(layerConfig));
27
+ const layer = (this.#layers[layerConfig.id] = createStyleLayer(layerConfig));
25
28
  layer._featureFilter = featureFilter(layer.filter);
26
29
  }
27
30
  for (const id of removedIds) {
28
- delete this._layerConfigs[id];
29
- delete this._layers[id];
31
+ delete this.#layerConfigs[id];
32
+ delete this.#layers[id];
30
33
  }
31
34
 
32
35
  this.familiesBySource = {};
33
36
 
34
- const groups = groupByLayout(values(this._layerConfigs));
37
+ const groups = groupByLayout(values(this.#layerConfigs));
35
38
 
36
39
  for (const layerConfigs of groups) {
37
- const layers = layerConfigs.map(layerConfig => this._layers[layerConfig.id]);
40
+ const layers = layerConfigs.map(layerConfig => this.#layers[layerConfig.id]);
38
41
 
39
42
  const layer = layers[0];
40
43
  if (layer.visibility === 'none') {
41
44
  continue;
42
45
  }
43
46
 
44
- const sourceId = layer.source || '';
45
- let sourceGroup = this.familiesBySource[sourceId];
46
- if (!sourceGroup) {
47
- sourceGroup = this.familiesBySource[sourceId] = {};
48
- }
49
-
50
- const sourceLayerId = layer.sourceLayer || '_geojsonTileLayer';
51
- let sourceLayerFamilies = sourceGroup[sourceLayerId];
52
- if (!sourceLayerFamilies) {
53
- sourceLayerFamilies = sourceGroup[sourceLayerId] = [];
54
- }
55
-
47
+ const { source = '', sourceLayer = '_geojsonTileLayer' } = layer;
48
+ const sourceGroup = (this.familiesBySource[source] ??= {});
49
+ const sourceLayerFamilies = (sourceGroup[sourceLayer] ??= []);
56
50
  sourceLayerFamilies.push(layers);
57
51
  }
58
52
  }
@@ -80,7 +80,7 @@
80
80
  },
81
81
  "transition": {
82
82
  "type": "transition",
83
- "doc": "A global transition definition to use as a default across properties.",
83
+ "doc": "A global transition definition to use as a default across properties, to be used for timing transitions between one value and the next when no property-specific transition is set. Collision-based symbol fading is controlled independently of the style's `transition` property.",
84
84
  "example": {
85
85
  "duration": 300,
86
86
  "delay": 0
@@ -2621,7 +2621,7 @@
2621
2621
  }
2622
2622
  },
2623
2623
  "feature-state": {
2624
- "doc": "Retrieves a property value from the current feature's state. Returns null if the requested property is not present on the feature's state object.",
2624
+ "doc": "Retrieves a property value from the current feature's state. Returns null if the requested property is not present on the feature's state. A feature's state is not part of the GeoJSON or vector tile data, and must be set programmatically on each feature. Note that [\"feature-state\"] can only be used with paint properties that support data-driven styling.",
2625
2625
  "group": "Feature data",
2626
2626
  "sdk-support": {
2627
2627
  "basic functionality": {
@@ -1,6 +1,6 @@
1
1
  const Point = require('@mapbox/point-geometry');
2
2
 
3
- const { register } = require('../util/web_worker_transfer');
3
+ const { register } = require('../util/transfer_registry');
4
4
 
5
5
  class Anchor extends Point {
6
6
  constructor(x, y, angle, segment) {
@@ -39,6 +39,8 @@ class CollisionIndex {
39
39
 
40
40
  this.screenRightBoundary = transform.width + viewportPadding;
41
41
  this.screenBottomBoundary = transform.height + viewportPadding;
42
+ this.gridRightBoundary = transform.width + 2 * viewportPadding;
43
+ this.gridBottomBoundary = transform.height + 2 * viewportPadding;
42
44
  }
43
45
 
44
46
  placeCollisionBox(collisionBox, allowOverlap, textPixelRatio, posMatrix, collisionGroupPredicate) {
@@ -53,14 +55,16 @@ class CollisionIndex {
53
55
  const brX = collisionBox.x2 * tileToViewport + projectedPoint.point.x;
54
56
  const brY = collisionBox.y2 * tileToViewport + projectedPoint.point.y;
55
57
 
56
- if (!allowOverlap) {
57
- if (this.grid.hitTest(tlX, tlY, brX, brY, collisionGroupPredicate)) {
58
- return {
59
- box: [],
60
- offscreen: false
61
- };
62
- }
58
+ if (
59
+ !this.isInsideGrid(tlX, tlY, brX, brY) ||
60
+ (!allowOverlap && this.grid.hitTest(tlX, tlY, brX, brY, collisionGroupPredicate))
61
+ ) {
62
+ return {
63
+ box: [],
64
+ offscreen: false
65
+ };
63
66
  }
67
+
64
68
  return {
65
69
  box: [tlX, tlY, brX, brY],
66
70
  offscreen: this.isOffscreen(tlX, tlY, brX, brY)
@@ -135,6 +139,7 @@ class CollisionIndex {
135
139
  );
136
140
 
137
141
  let collisionDetected = false;
142
+ let inGrid = false;
138
143
  let entirelyOffscreen = true;
139
144
 
140
145
  const tileToViewport = projectedAnchor.perspectiveRatio * textPixelRatio;
@@ -211,14 +216,12 @@ class CollisionIndex {
211
216
  placedCollisionCircles.push(projectedPoint.x, projectedPoint.y, radius, collisionBoxArrayIndex);
212
217
  markCollisionCircleUsed(collisionCircles, k, true);
213
218
 
214
- entirelyOffscreen =
215
- entirelyOffscreen &&
216
- this.isOffscreen(
217
- projectedPoint.x - radius,
218
- projectedPoint.y - radius,
219
- projectedPoint.x + radius,
220
- projectedPoint.y + radius
221
- );
219
+ const x1 = projectedPoint.x - radius;
220
+ const y1 = projectedPoint.y - radius;
221
+ const x2 = projectedPoint.x + radius;
222
+ const y2 = projectedPoint.y + radius;
223
+ entirelyOffscreen = entirelyOffscreen && this.isOffscreen(x1, y1, x2, y2);
224
+ inGrid = inGrid || this.isInsideGrid(x1, y1, x2, y2);
222
225
 
223
226
  if (!allowOverlap) {
224
227
  if (this.grid.hitTestCircle(projectedPoint.x, projectedPoint.y, radius, collisionGroupPredicate)) {
@@ -236,7 +239,7 @@ class CollisionIndex {
236
239
  }
237
240
 
238
241
  return {
239
- circles: collisionDetected ? [] : placedCollisionCircles,
242
+ circles: collisionDetected || !inGrid ? [] : placedCollisionCircles,
240
243
  offscreen: entirelyOffscreen
241
244
  };
242
245
  }
@@ -370,6 +373,10 @@ class CollisionIndex {
370
373
  x2 < viewportPadding || x1 >= this.screenRightBoundary || y2 < viewportPadding || y1 > this.screenBottomBoundary
371
374
  );
372
375
  }
376
+
377
+ isInsideGrid(x1, y1, x2, y2) {
378
+ return x2 >= 0 && x1 < this.gridRightBoundary && y2 >= 0 && y1 < this.gridBottomBoundary;
379
+ }
373
380
  }
374
381
 
375
382
  function markCollisionCircleUsed(collisionCircles, index, used) {