@mapwhit/tilerenderer 0.47.1 → 0.48.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.
- package/build/min/package.json +1 -1
- package/package.json +1 -2
- package/src/data/array_types.js +1 -1
- package/src/data/bucket/circle_bucket.js +1 -1
- package/src/data/bucket/fill_bucket.js +1 -1
- package/src/data/bucket/fill_extrusion_bucket.js +1 -1
- package/src/data/bucket/heatmap_bucket.js +1 -1
- package/src/data/bucket/line_bucket.js +1 -1
- package/src/data/bucket/symbol_bucket.js +26 -12
- package/src/data/dem_data.js +1 -1
- package/src/data/feature_index.js +43 -82
- package/src/data/program_configuration.js +19 -11
- package/src/data/segment.js +2 -2
- package/src/geo/transform.js +4 -2
- package/src/gl/color_mode.js +6 -6
- package/src/index.js +3 -1
- package/src/render/glyph_atlas.js +1 -1
- package/src/render/glyph_manager.js +43 -48
- package/src/render/image_atlas.js +1 -1
- package/src/render/image_manager.js +9 -37
- package/src/source/geojson_source.js +49 -93
- package/src/source/geojson_worker_source.js +33 -134
- package/src/source/image_source.js +9 -14
- package/src/source/load_tilejson.js +27 -34
- package/src/source/raster_dem_tile_source.js +27 -40
- package/src/source/raster_tile_source.js +53 -62
- package/src/source/rtl_text_plugin.js +3 -1
- package/src/source/source_cache.js +23 -21
- package/src/source/source_state.js +17 -26
- package/src/source/tile.js +6 -5
- package/src/source/tile_id.js +1 -1
- package/src/source/vector_tile_source.js +56 -73
- package/src/source/vector_tile_worker_source.js +20 -85
- package/src/source/worker.js +37 -103
- package/src/source/worker_tile.js +39 -84
- package/src/style/load_sprite.js +14 -17
- package/src/style/properties.js +1 -1
- package/src/style/style.js +22 -37
- package/src/style/style_layer/symbol_style_layer_properties.js +1 -1
- package/src/style/style_layer_index.js +17 -23
- package/src/style-spec/expression/compound_expression.js +30 -16
- package/src/style-spec/expression/definitions/coercion.js +13 -0
- package/src/style-spec/expression/definitions/comparison.js +193 -0
- package/src/style-spec/expression/definitions/formatted.js +123 -0
- package/src/style-spec/expression/definitions/index.js +10 -60
- package/src/style-spec/expression/definitions/interpolate.js +17 -7
- package/src/style-spec/expression/definitions/literal.js +5 -0
- package/src/style-spec/expression/parsing_context.js +4 -0
- package/src/style-spec/expression/types.js +12 -1
- package/src/style-spec/feature_filter/index.js +1 -1
- package/src/style-spec/reference/v8.json +120 -49
- package/src/symbol/anchor.js +1 -1
- package/src/symbol/collision_index.js +23 -16
- package/src/symbol/get_anchors.js +11 -22
- package/src/symbol/grid_index.js +176 -182
- package/src/symbol/mergelines.js +51 -48
- package/src/symbol/opacity_state.js +1 -1
- package/src/symbol/placement.js +8 -2
- package/src/symbol/quads.js +7 -6
- package/src/symbol/shaping.js +185 -40
- package/src/symbol/symbol_layout.js +9 -6
- package/src/symbol/transform_text.js +12 -1
- package/src/ui/camera.js +82 -85
- package/src/ui/map.js +13 -57
- package/src/util/actor.js +46 -42
- package/src/util/browser.js +6 -0
- package/src/util/dictionary_coder.js +13 -21
- package/src/util/dispatcher.js +14 -17
- package/src/util/image.js +1 -1
- package/src/util/loader/image.js +11 -11
- package/src/util/polyfill.js +16 -0
- package/src/util/task_queue.js +39 -43
- package/src/util/transfer_registry.js +167 -0
- package/src/util/web_worker_transfer.js +5 -190
- package/src/source/raster_dem_tile_worker_source.js +0 -26
- package/src/style-spec/expression/definitions/equals.js +0 -93
|
@@ -22,10 +22,9 @@ const padding = 1;
|
|
|
22
22
|
to refactor this.
|
|
23
23
|
*/
|
|
24
24
|
class ImageManager {
|
|
25
|
+
#loadedState = Promise.withResolvers();
|
|
25
26
|
constructor() {
|
|
26
27
|
this.images = {};
|
|
27
|
-
this.loaded = false;
|
|
28
|
-
this.requestors = [];
|
|
29
28
|
|
|
30
29
|
this.shelfPack = new ShelfPack(64, 64, { autoResize: true });
|
|
31
30
|
this.patterns = {};
|
|
@@ -34,22 +33,15 @@ class ImageManager {
|
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
isLoaded() {
|
|
37
|
-
return this.loaded;
|
|
36
|
+
return !!this.#loadedState.loaded;
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
setLoaded(
|
|
41
|
-
if (this.loaded
|
|
39
|
+
setLoaded() {
|
|
40
|
+
if (this.#loadedState.loaded) {
|
|
42
41
|
return;
|
|
43
42
|
}
|
|
44
|
-
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
if (loaded) {
|
|
48
|
-
for (const { ids, callback } of this.requestors) {
|
|
49
|
-
this._notify(ids, callback);
|
|
50
|
-
}
|
|
51
|
-
this.requestors = [];
|
|
52
|
-
}
|
|
43
|
+
this.#loadedState.loaded = true;
|
|
44
|
+
this.#loadedState.resolve();
|
|
53
45
|
}
|
|
54
46
|
|
|
55
47
|
getImage(id) {
|
|
@@ -76,29 +68,10 @@ class ImageManager {
|
|
|
76
68
|
return Object.keys(this.images);
|
|
77
69
|
}
|
|
78
70
|
|
|
79
|
-
getImages(ids
|
|
80
|
-
|
|
81
|
-
// (i.e. if they've been addeded via runtime styling), then notify the requestor immediately.
|
|
82
|
-
// Otherwise, delay notification until the sprite is loaded. At that point, if any of the
|
|
83
|
-
// dependencies are still unavailable, we'll just assume they are permanently missing.
|
|
84
|
-
let hasAllDependencies = true;
|
|
85
|
-
if (!this.isLoaded()) {
|
|
86
|
-
for (const id of ids) {
|
|
87
|
-
if (!this.images[id]) {
|
|
88
|
-
hasAllDependencies = false;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (this.isLoaded() || hasAllDependencies) {
|
|
93
|
-
this._notify(ids, callback);
|
|
94
|
-
} else {
|
|
95
|
-
this.requestors.push({ ids, callback });
|
|
96
|
-
}
|
|
97
|
-
}
|
|
71
|
+
async getImages(ids) {
|
|
72
|
+
await this.#loadedState.promise;
|
|
98
73
|
|
|
99
|
-
_notify(ids, callback) {
|
|
100
74
|
const response = {};
|
|
101
|
-
|
|
102
75
|
for (const id of ids) {
|
|
103
76
|
const image = this.images[id];
|
|
104
77
|
if (image) {
|
|
@@ -110,8 +83,7 @@ class ImageManager {
|
|
|
110
83
|
};
|
|
111
84
|
}
|
|
112
85
|
}
|
|
113
|
-
|
|
114
|
-
callback(null, response);
|
|
86
|
+
return response;
|
|
115
87
|
}
|
|
116
88
|
|
|
117
89
|
// Pattern stuff
|
|
@@ -49,9 +49,10 @@ const browser = require('../util/browser');
|
|
|
49
49
|
* @see [Create a heatmap from points](https://www.mapbox.com/mapbox-gl-js/example/heatmap/)
|
|
50
50
|
*/
|
|
51
51
|
class GeoJSONSource extends Evented {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
#pendingDataEvents = new Set();
|
|
53
|
+
#newData = false;
|
|
54
|
+
#updateInProgress = false;
|
|
55
|
+
|
|
55
56
|
constructor(id, options, dispatcher, eventedParent) {
|
|
56
57
|
super();
|
|
57
58
|
|
|
@@ -109,19 +110,7 @@ class GeoJSONSource extends Evented {
|
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
load() {
|
|
112
|
-
this
|
|
113
|
-
this._updateWorkerData(err => {
|
|
114
|
-
if (err) {
|
|
115
|
-
this.fire(new ErrorEvent(err));
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const data = { dataType: 'source', sourceDataType: 'metadata' };
|
|
120
|
-
|
|
121
|
-
// although GeoJSON sources contain no metadata, we fire this event to let the SourceCache
|
|
122
|
-
// know its ok to start requesting tiles.
|
|
123
|
-
this.fire(new Event('data', data));
|
|
124
|
-
});
|
|
113
|
+
this.#updateData('metadata');
|
|
125
114
|
}
|
|
126
115
|
|
|
127
116
|
onAdd(map) {
|
|
@@ -137,73 +126,55 @@ class GeoJSONSource extends Evented {
|
|
|
137
126
|
*/
|
|
138
127
|
setData(data) {
|
|
139
128
|
this._data = data;
|
|
140
|
-
this
|
|
141
|
-
this._updateWorkerData(err => {
|
|
142
|
-
if (err) {
|
|
143
|
-
return this.fire(new ErrorEvent(err));
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const data = { dataType: 'source', sourceDataType: 'content' };
|
|
147
|
-
this.fire(new Event('data', data));
|
|
148
|
-
});
|
|
149
|
-
|
|
129
|
+
this.#updateData();
|
|
150
130
|
return this;
|
|
151
131
|
}
|
|
152
132
|
|
|
133
|
+
async #updateData(sourceDataType = 'content') {
|
|
134
|
+
this.#newData = true;
|
|
135
|
+
this.#pendingDataEvents.add(sourceDataType);
|
|
136
|
+
if (this.#updateInProgress) {
|
|
137
|
+
// will handle this update when the current one is done
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
this.#updateInProgress = true;
|
|
142
|
+
this.fire(new Event('dataloading', { dataType: 'source' }));
|
|
143
|
+
while (this.#newData) {
|
|
144
|
+
this.#newData = false;
|
|
145
|
+
await this._updateWorkerData(this._data);
|
|
146
|
+
}
|
|
147
|
+
this.#pendingDataEvents.forEach(sourceDataType =>
|
|
148
|
+
this.fire(new Event('data', { dataType: 'source', sourceDataType }))
|
|
149
|
+
);
|
|
150
|
+
this.#pendingDataEvents.clear();
|
|
151
|
+
} catch (err) {
|
|
152
|
+
this.fire(new ErrorEvent(err));
|
|
153
|
+
} finally {
|
|
154
|
+
this.#updateInProgress = false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
153
158
|
/*
|
|
154
159
|
* Responsible for invoking WorkerSource's geojson.loadData target, which
|
|
155
160
|
* handles loading the geojson data and preparing to serve it up as tiles,
|
|
156
161
|
* using geojson-vt or supercluster as appropriate.
|
|
157
162
|
*/
|
|
158
|
-
_updateWorkerData(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return data();
|
|
163
|
-
}
|
|
164
|
-
return data;
|
|
163
|
+
async _updateWorkerData(data) {
|
|
164
|
+
const json = typeof data === 'function' ? await data().catch(() => {}) : data;
|
|
165
|
+
if (!json) {
|
|
166
|
+
throw new Error('no GeoJSON data');
|
|
165
167
|
}
|
|
168
|
+
const options = { ...this.workerOptions, data: JSON.stringify(json) };
|
|
169
|
+
this.workerID ??= this.dispatcher.nextWorkerId();
|
|
166
170
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (!json) {
|
|
172
|
-
return callback(new Error('no GeoJSON data'));
|
|
173
|
-
}
|
|
174
|
-
const options = Object.assign({}, this.workerOptions);
|
|
175
|
-
options.data = JSON.stringify(json);
|
|
176
|
-
// target {this.type}.loadData rather than literally geojson.loadData,
|
|
177
|
-
// so that other geojson-like source types can easily reuse this
|
|
178
|
-
// implementation
|
|
179
|
-
this.workerID = this.dispatcher.send(
|
|
180
|
-
`${this.type}.loadData`,
|
|
181
|
-
options,
|
|
182
|
-
(err, result) => {
|
|
183
|
-
if (this._removed || result?.abandoned) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
this._loaded = true;
|
|
188
|
-
|
|
189
|
-
if (result?.resourceTiming?.[this.id]) this._resourceTiming = result.resourceTiming[this.id].slice(0);
|
|
190
|
-
// Any `loadData` calls that piled up while we were processing
|
|
191
|
-
// this one will get coalesced into a single call when this
|
|
192
|
-
// 'coalesce' message is processed.
|
|
193
|
-
// We would self-send from the worker if we had access to its
|
|
194
|
-
// message queue. Waiting instead for the 'coalesce' to round-trip
|
|
195
|
-
// through the foreground just means we're throttling the worker
|
|
196
|
-
// to run at a little less than full-throttle.
|
|
197
|
-
this.dispatcher.send(`${this.type}.coalesce`, { source: options.source }, null, this.workerID);
|
|
198
|
-
callback(err);
|
|
199
|
-
},
|
|
200
|
-
this.workerID
|
|
201
|
-
);
|
|
202
|
-
});
|
|
171
|
+
// target {this.type}.loadData rather than literally geojson.loadData,
|
|
172
|
+
// so that other geojson-like source types can easily reuse this
|
|
173
|
+
// implementation
|
|
174
|
+
await this.dispatcher.send(`${this.type}.loadData`, options, this.workerID);
|
|
203
175
|
}
|
|
204
176
|
|
|
205
|
-
loadTile(tile
|
|
206
|
-
const message = tile.workerID === undefined ? 'loadTile' : 'reloadTile';
|
|
177
|
+
async loadTile(tile) {
|
|
207
178
|
const params = {
|
|
208
179
|
type: this.type,
|
|
209
180
|
uid: tile.uid,
|
|
@@ -216,26 +187,12 @@ class GeoJSONSource extends Evented {
|
|
|
216
187
|
showCollisionBoxes: this.map.showCollisionBoxes
|
|
217
188
|
};
|
|
218
189
|
|
|
219
|
-
tile.workerID
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (tile.aborted) {
|
|
226
|
-
return callback(null);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (err) {
|
|
230
|
-
return callback(err);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
tile.loadVectorData(data, this.map.painter, message === 'reloadTile');
|
|
234
|
-
|
|
235
|
-
return callback(null);
|
|
236
|
-
},
|
|
237
|
-
this.workerID
|
|
238
|
-
);
|
|
190
|
+
const justReloaded = tile.workerID != null;
|
|
191
|
+
tile.workerID ??= this.dispatcher.nextWorkerId(this.workerID);
|
|
192
|
+
const data = await this.dispatcher.send('loadTile', params, tile.workerID).finally(() => tile.unloadVectorData());
|
|
193
|
+
if (!tile.aborted) {
|
|
194
|
+
tile.loadVectorData(data, this.map.painter, justReloaded);
|
|
195
|
+
}
|
|
239
196
|
}
|
|
240
197
|
|
|
241
198
|
abortTile(tile) {
|
|
@@ -244,12 +201,11 @@ class GeoJSONSource extends Evented {
|
|
|
244
201
|
|
|
245
202
|
unloadTile(tile) {
|
|
246
203
|
tile.unloadVectorData();
|
|
247
|
-
this.dispatcher.send('removeTile', { uid: tile.uid, type: this.type, source: this.id }, null, tile.workerID);
|
|
248
204
|
}
|
|
249
205
|
|
|
250
206
|
onRemove() {
|
|
251
207
|
this._removed = true;
|
|
252
|
-
this.dispatcher.send('removeSource', { type: this.type, source: this.id },
|
|
208
|
+
return this.dispatcher.send('removeSource', { type: this.type, source: this.id }, this.workerID);
|
|
253
209
|
}
|
|
254
210
|
|
|
255
211
|
serialize() {
|
|
@@ -3,19 +3,25 @@ const GeoJSONWrapper = require('./geojson_wrapper');
|
|
|
3
3
|
const vtpbf = require('@mapwhit/vt-pbf');
|
|
4
4
|
const supercluster = require('supercluster');
|
|
5
5
|
const geojsonvt = require('geojson-vt');
|
|
6
|
-
const assert = require('assert');
|
|
7
6
|
const VectorTileWorkerSource = require('./vector_tile_worker_source');
|
|
8
7
|
|
|
9
|
-
function loadGeoJSONTile(params
|
|
10
|
-
const canonical = params.tileID.canonical;
|
|
11
|
-
|
|
8
|
+
function loadGeoJSONTile(params) {
|
|
12
9
|
if (!this._geoJSONIndex) {
|
|
13
|
-
|
|
10
|
+
if (!this._createGeoJSONIndex) {
|
|
11
|
+
return; // we couldn't load the file
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
this._geoJSONIndex = this._createGeoJSONIndex();
|
|
16
|
+
} finally {
|
|
17
|
+
this._createGeoJSONIndex = null;
|
|
18
|
+
}
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
const
|
|
21
|
+
const { z, x, y } = params.tileID.canonical;
|
|
22
|
+
const geoJSONTile = this._geoJSONIndex.getTile(z, x, y);
|
|
17
23
|
if (!geoJSONTile) {
|
|
18
|
-
return
|
|
24
|
+
return; // nothing in the given tile
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
const geojsonWrapper = new GeoJSONWrapper(geoJSONTile.features);
|
|
@@ -29,14 +35,12 @@ function loadGeoJSONTile(params, callback) {
|
|
|
29
35
|
pbf = new Uint8Array(pbf);
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
return {
|
|
33
39
|
vectorTile: geojsonWrapper,
|
|
34
40
|
rawData: pbf.buffer
|
|
35
|
-
}
|
|
41
|
+
};
|
|
36
42
|
}
|
|
37
43
|
|
|
38
|
-
// 'loadData' received while coalescing, trigger one more 'loadData' on receiving 'coalesced'
|
|
39
|
-
|
|
40
44
|
/**
|
|
41
45
|
* The {@link WorkerSource} implementation that supports {@link GeoJSONSource}.
|
|
42
46
|
* This class is designed to be easily reused to support custom source types
|
|
@@ -45,7 +49,6 @@ function loadGeoJSONTile(params, callback) {
|
|
|
45
49
|
* `new GeoJSONWorkerSource(actor, layerIndex, customLoadGeoJSONFunction)`.
|
|
46
50
|
* For a full example, see [mapbox-gl-topojson](https://github.com/developmentseed/mapbox-gl-topojson).
|
|
47
51
|
*
|
|
48
|
-
* @private
|
|
49
52
|
*/
|
|
50
53
|
class GeoJSONWorkerSource extends VectorTileWorkerSource {
|
|
51
54
|
/**
|
|
@@ -69,141 +72,37 @@ class GeoJSONWorkerSource extends VectorTileWorkerSource {
|
|
|
69
72
|
* expecting `callback(error, data)` to be called with either an error or a
|
|
70
73
|
* parsed GeoJSON object.
|
|
71
74
|
*
|
|
72
|
-
* When `loadData` requests come in faster than they can be processed,
|
|
73
|
-
* they are coalesced into a single request using the latest data.
|
|
74
|
-
* See {@link GeoJSONWorkerSource#coalesce}
|
|
75
|
-
*
|
|
76
75
|
* @param params
|
|
77
76
|
* @param callback
|
|
78
77
|
*/
|
|
79
|
-
loadData(params
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
this._loadData();
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Internal implementation: called directly by `loadData`
|
|
97
|
-
* or by `coalesce` using stored parameters.
|
|
98
|
-
*/
|
|
99
|
-
_loadData() {
|
|
100
|
-
if (!this._pendingCallback || !this._pendingLoadDataParams) {
|
|
101
|
-
assert(false);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const callback = this._pendingCallback;
|
|
105
|
-
const params = this._pendingLoadDataParams;
|
|
106
|
-
delete this._pendingCallback;
|
|
107
|
-
delete this._pendingLoadDataParams;
|
|
108
|
-
this.loadGeoJSON(params, (err, data) => {
|
|
109
|
-
if (err || !data) {
|
|
110
|
-
return callback(err);
|
|
111
|
-
}
|
|
112
|
-
if (typeof data !== 'object') {
|
|
113
|
-
return callback(new Error('Input data is not a valid GeoJSON object.'));
|
|
114
|
-
}
|
|
115
|
-
rewind(data, true);
|
|
116
|
-
|
|
117
|
-
try {
|
|
118
|
-
this._geoJSONIndex = params.cluster
|
|
119
|
-
? supercluster(params.superclusterOptions).load(data.features)
|
|
120
|
-
: geojsonvt(data, params.geojsonVtOptions);
|
|
121
|
-
} catch (err) {
|
|
122
|
-
return callback(err);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
this.loaded = {};
|
|
126
|
-
|
|
127
|
-
const result = {};
|
|
128
|
-
callback(null, result);
|
|
129
|
-
});
|
|
78
|
+
loadData(params) {
|
|
79
|
+
const data = this.loadGeoJSON(params);
|
|
80
|
+
this._geoJSONIndex = null;
|
|
81
|
+
this._createGeoJSONIndex = params.cluster
|
|
82
|
+
? () => {
|
|
83
|
+
rewind(data, true);
|
|
84
|
+
return supercluster(params.superclusterOptions).load(data.features);
|
|
85
|
+
}
|
|
86
|
+
: () => {
|
|
87
|
+
rewind(data, true);
|
|
88
|
+
return geojsonvt(data, params.geojsonVtOptions);
|
|
89
|
+
};
|
|
130
90
|
}
|
|
131
91
|
|
|
132
92
|
/**
|
|
133
|
-
*
|
|
134
|
-
* `loadData` messages into a single call to _loadData
|
|
135
|
-
* that will happen once we've finished processing the
|
|
136
|
-
* first message. {@link GeoJSONSource#_updateWorkerData}
|
|
137
|
-
* is responsible for sending us the `coalesce` message
|
|
138
|
-
* at the time it receives a response from `loadData`
|
|
139
|
-
*
|
|
140
|
-
* State: Idle
|
|
141
|
-
* ↑ |
|
|
142
|
-
* 'coalesce' 'loadData'
|
|
143
|
-
* | (triggers load)
|
|
144
|
-
* | ↓
|
|
145
|
-
* State: Coalescing
|
|
146
|
-
* ↑ |
|
|
147
|
-
* (triggers load) |
|
|
148
|
-
* 'coalesce' 'loadData'
|
|
149
|
-
* | ↓
|
|
150
|
-
* State: NeedsLoadData
|
|
151
|
-
*/
|
|
152
|
-
coalesce() {
|
|
153
|
-
if (this._state === 'Coalescing') {
|
|
154
|
-
this._state = 'Idle';
|
|
155
|
-
} else if (this._state === 'NeedsLoadData') {
|
|
156
|
-
this._state = 'Coalescing';
|
|
157
|
-
this._loadData();
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Implements {@link WorkerSource#reloadTile}.
|
|
163
|
-
*
|
|
164
|
-
* If the tile is loaded, uses the implementation in VectorTileWorkerSource.
|
|
165
|
-
* Otherwise, such as after a setData() call, we load the tile fresh.
|
|
166
|
-
*
|
|
167
|
-
* @param params
|
|
168
|
-
* @param params.uid The UID for this tile.
|
|
169
|
-
*/
|
|
170
|
-
reloadTile(params, callback) {
|
|
171
|
-
const loaded = this.loaded;
|
|
172
|
-
const uid = params.uid;
|
|
173
|
-
|
|
174
|
-
if (loaded?.[uid]) {
|
|
175
|
-
return super.reloadTile(params, callback);
|
|
176
|
-
}
|
|
177
|
-
return this.loadTile(params, callback);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Fetch and parse GeoJSON according to the given params. Calls `callback`
|
|
182
|
-
* with `(err, data)`, where `data` is a parsed GeoJSON object.
|
|
93
|
+
* Fetch and parse GeoJSON according to the given params.
|
|
183
94
|
*
|
|
184
95
|
* GeoJSON is expected as a literal (string or object) `params.data`.
|
|
185
96
|
*
|
|
186
97
|
* @param params
|
|
187
98
|
* @param [params.data] Literal GeoJSON data. Must be provided.
|
|
188
99
|
*/
|
|
189
|
-
loadGeoJSON(params
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return callback(new Error('Input data is not a valid GeoJSON object.'));
|
|
195
|
-
}
|
|
196
|
-
} else {
|
|
197
|
-
return callback(new Error('Input data is not a valid GeoJSON object.'));
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
removeSource(params, callback) {
|
|
202
|
-
if (this._pendingCallback) {
|
|
203
|
-
// Don't leak callbacks
|
|
204
|
-
this._pendingCallback(null, { abandoned: true });
|
|
100
|
+
loadGeoJSON(params) {
|
|
101
|
+
try {
|
|
102
|
+
return JSON.parse(params.data);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
throw new Error('Input data is not a valid GeoJSON object.');
|
|
205
105
|
}
|
|
206
|
-
callback();
|
|
207
106
|
}
|
|
208
107
|
}
|
|
209
108
|
|
|
@@ -61,19 +61,15 @@ class ImageSource extends Evented {
|
|
|
61
61
|
this.options = options;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
load() {
|
|
64
|
+
async load() {
|
|
65
65
|
this.fire(new Event('dataloading', { dataType: 'source' }));
|
|
66
|
-
|
|
67
66
|
this.url = this.options.url;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this._finishLoading();
|
|
75
|
-
}
|
|
76
|
-
});
|
|
67
|
+
try {
|
|
68
|
+
this.image = await loadImage(this.url);
|
|
69
|
+
this._finishLoading();
|
|
70
|
+
} catch (err) {
|
|
71
|
+
this.fire(new ErrorEvent(err));
|
|
72
|
+
}
|
|
77
73
|
}
|
|
78
74
|
|
|
79
75
|
_finishLoading() {
|
|
@@ -180,7 +176,7 @@ class ImageSource extends Evented {
|
|
|
180
176
|
}
|
|
181
177
|
}
|
|
182
178
|
|
|
183
|
-
loadTile(tile
|
|
179
|
+
loadTile(tile) {
|
|
184
180
|
// We have a single tile -- whoose coordinates are this.tileID -- that
|
|
185
181
|
// covers the image we want to render. If that's the one being
|
|
186
182
|
// requested, set it up with the image; otherwise, mark the tile as
|
|
@@ -190,11 +186,10 @@ class ImageSource extends Evented {
|
|
|
190
186
|
if (this.tileID?.equals(tile.tileID.canonical)) {
|
|
191
187
|
this.tiles[String(tile.tileID.wrap)] = tile;
|
|
192
188
|
tile.buckets = {};
|
|
193
|
-
callback(null);
|
|
194
189
|
} else {
|
|
195
190
|
tile.state = 'errored';
|
|
196
|
-
callback(null);
|
|
197
191
|
}
|
|
192
|
+
return Promise.resolve();
|
|
198
193
|
}
|
|
199
194
|
|
|
200
195
|
serialize() {
|
|
@@ -1,40 +1,33 @@
|
|
|
1
1
|
const { pick } = require('../util/object');
|
|
2
|
-
const browser = require('../util/browser');
|
|
3
2
|
|
|
4
|
-
module.exports = function (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if (tileJSON) {
|
|
8
|
-
const { resourceSets } = tileJSON;
|
|
9
|
-
if (resourceSets) {
|
|
10
|
-
if (!resourceSets.length) {
|
|
11
|
-
return callback('expected resources');
|
|
12
|
-
}
|
|
13
|
-
const { resources } = resourceSets[0];
|
|
14
|
-
if (!resources?.length) {
|
|
15
|
-
return callback('expected resources');
|
|
16
|
-
}
|
|
17
|
-
const { imageUrl, imageUrlSubdomains } = resources[0];
|
|
18
|
-
const result = Object.assign(
|
|
19
|
-
{
|
|
20
|
-
tiles: imageUrlSubdomains.map(sub => imageUrl.replace('{subdomain}', sub).replace('http:', 'https:'))
|
|
21
|
-
},
|
|
22
|
-
options
|
|
23
|
-
);
|
|
24
|
-
delete result.url;
|
|
25
|
-
return callback(null, result);
|
|
26
|
-
}
|
|
27
|
-
const result = pick(tileJSON, ['tiles', 'minzoom', 'maxzoom', 'attribution', 'mapbox_logo', 'bounds']);
|
|
28
|
-
|
|
29
|
-
if (tileJSON.vector_layers) {
|
|
30
|
-
result.vectorLayers = tileJSON.vector_layers;
|
|
31
|
-
result.vectorLayerIds = result.vectorLayers.map(layer => layer.id);
|
|
32
|
-
}
|
|
3
|
+
module.exports = function (tileJSON) {
|
|
4
|
+
return tileJSON.resourceSets ? fromResourseSets(tileJSON) : fromTileJSON(tileJSON);
|
|
5
|
+
};
|
|
33
6
|
|
|
34
|
-
|
|
35
|
-
|
|
7
|
+
function fromTileJSON(tileJSON) {
|
|
8
|
+
const result = pick(tileJSON, ['tiles', 'minzoom', 'maxzoom', 'attribution', 'bounds']);
|
|
9
|
+
if (tileJSON.vector_layers) {
|
|
10
|
+
result.vectorLayers = tileJSON.vector_layers;
|
|
11
|
+
result.vectorLayerIds = result.vectorLayers.map(layer => layer.id);
|
|
36
12
|
}
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
37
15
|
|
|
16
|
+
function fromResourseSets(tileJSON) {
|
|
17
|
+
const { resourceSets } = tileJSON;
|
|
18
|
+
if (!resourceSets.length) {
|
|
19
|
+
throw new Error('expected resources');
|
|
20
|
+
}
|
|
21
|
+
const { resources } = resourceSets[0];
|
|
22
|
+
if (!resources?.length) {
|
|
23
|
+
throw new Error('expected resources');
|
|
24
|
+
}
|
|
25
|
+
const { imageUrl, imageUrlSubdomains } = resources[0];
|
|
26
|
+
const result = {
|
|
27
|
+
tiles: imageUrlSubdomains.map(sub => imageUrl.replace('{subdomain}', sub).replace('http:', 'https:')),
|
|
28
|
+
...tileJSON
|
|
29
|
+
};
|
|
38
30
|
// expects already loaded object, `url` property is ignored
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
delete result.url;
|
|
32
|
+
return result;
|
|
33
|
+
}
|