@mapwhit/tilerenderer 0.52.0 → 1.0.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/README.md +7 -0
- package/build/min/package.json +1 -1
- package/build/min/src/shaders/_prelude.fragment.glsl.js +2 -2
- package/build/min/src/shaders/_prelude.vertex.glsl.js +2 -2
- package/build/min/src/shaders/background.fragment.glsl.js +2 -2
- package/build/min/src/shaders/background.vertex.glsl.js +1 -1
- package/build/min/src/shaders/background_pattern.fragment.glsl.js +2 -2
- package/build/min/src/shaders/background_pattern.vertex.glsl.js +1 -1
- package/build/min/src/shaders/circle.fragment.glsl.js +2 -2
- package/build/min/src/shaders/circle.vertex.glsl.js +2 -2
- package/build/min/src/shaders/clipping_mask.fragment.glsl.js +1 -1
- package/build/min/src/shaders/clipping_mask.vertex.glsl.js +1 -1
- package/build/min/src/shaders/collision_box.fragment.glsl.js +1 -1
- package/build/min/src/shaders/collision_box.vertex.glsl.js +1 -1
- package/build/min/src/shaders/collision_circle.fragment.glsl.js +1 -1
- package/build/min/src/shaders/collision_circle.vertex.glsl.js +1 -1
- package/build/min/src/shaders/debug.fragment.glsl.js +1 -1
- package/build/min/src/shaders/debug.vertex.glsl.js +1 -1
- package/build/min/src/shaders/fill.fragment.glsl.js +2 -2
- package/build/min/src/shaders/fill.vertex.glsl.js +2 -2
- package/build/min/src/shaders/fill_extrusion.fragment.glsl.js +2 -2
- package/build/min/src/shaders/fill_extrusion.vertex.glsl.js +2 -2
- package/build/min/src/shaders/fill_extrusion_pattern.fragment.glsl.js +2 -2
- package/build/min/src/shaders/fill_extrusion_pattern.vertex.glsl.js +2 -2
- package/build/min/src/shaders/fill_outline.fragment.glsl.js +2 -2
- package/build/min/src/shaders/fill_outline.vertex.glsl.js +2 -2
- package/build/min/src/shaders/fill_outline_pattern.fragment.glsl.js +2 -2
- package/build/min/src/shaders/fill_outline_pattern.vertex.glsl.js +2 -2
- package/build/min/src/shaders/fill_pattern.fragment.glsl.js +2 -2
- package/build/min/src/shaders/fill_pattern.vertex.glsl.js +2 -2
- package/build/min/src/shaders/heatmap.fragment.glsl.js +2 -2
- package/build/min/src/shaders/heatmap.vertex.glsl.js +2 -2
- package/build/min/src/shaders/heatmap_texture.fragment.glsl.js +2 -2
- package/build/min/src/shaders/heatmap_texture.vertex.glsl.js +1 -1
- package/build/min/src/shaders/hillshade.fragment.glsl.js +2 -2
- package/build/min/src/shaders/hillshade.vertex.glsl.js +1 -1
- package/build/min/src/shaders/hillshade_prepare.fragment.glsl.js +2 -2
- package/build/min/src/shaders/hillshade_prepare.vertex.glsl.js +1 -1
- package/build/min/src/shaders/line.fragment.glsl.js +2 -2
- package/build/min/src/shaders/line.vertex.glsl.js +2 -2
- package/build/min/src/shaders/line_gradient.fragment.glsl.js +2 -2
- package/build/min/src/shaders/line_gradient.vertex.glsl.js +2 -2
- package/build/min/src/shaders/line_pattern.fragment.glsl.js +2 -2
- package/build/min/src/shaders/line_pattern.vertex.glsl.js +2 -2
- package/build/min/src/shaders/line_sdf.fragment.glsl.js +2 -2
- package/build/min/src/shaders/line_sdf.vertex.glsl.js +2 -2
- package/build/min/src/shaders/raster.fragment.glsl.js +2 -2
- package/build/min/src/shaders/raster.vertex.glsl.js +1 -1
- package/build/min/src/shaders/symbol_icon.fragment.glsl.js +2 -2
- package/build/min/src/shaders/symbol_icon.vertex.glsl.js +2 -2
- package/build/min/src/shaders/symbol_sdf.fragment.glsl.js +2 -2
- package/build/min/src/shaders/symbol_sdf.vertex.glsl.js +2 -2
- package/package.json +3 -3
- package/src/data/array_types.js +1 -36
- package/src/data/bucket/circle_bucket.js +8 -5
- package/src/data/bucket/fill_bucket.js +8 -5
- package/src/data/bucket/fill_extrusion_bucket.js +8 -5
- package/src/data/bucket/heatmap_bucket.js +0 -4
- package/src/data/bucket/line_bucket.js +9 -6
- package/src/data/bucket/pattern_bucket_features.js +2 -2
- package/src/data/bucket/symbol_bucket.js +99 -129
- package/src/data/bucket.js +26 -21
- package/src/data/dem_data.js +0 -3
- package/src/data/feature_index.js +3 -8
- package/src/data/program_configuration.js +24 -33
- package/src/data/segment.js +0 -4
- package/src/render/draw_background.js +3 -3
- package/src/render/draw_circle.js +4 -4
- package/src/render/draw_fill.js +8 -8
- package/src/render/draw_fill_extrusion.js +8 -8
- package/src/render/draw_heatmap.js +4 -4
- package/src/render/draw_line.js +6 -6
- package/src/render/draw_raster.js +6 -6
- package/src/render/draw_symbol.js +16 -16
- package/src/render/glyph_atlas.js +0 -3
- package/src/render/glyph_manager.js +1 -2
- package/src/render/image_atlas.js +0 -4
- package/src/render/image_manager.js +33 -19
- package/src/render/painter.js +13 -14
- package/src/render/program/circle_program.js +4 -4
- package/src/render/program/fill_extrusion_program.js +1 -1
- package/src/render/program/heatmap_program.js +1 -1
- package/src/render/program/hillshade_program.js +6 -6
- package/src/render/program/line_program.js +3 -3
- package/src/render/program/raster_program.js +6 -6
- package/src/source/geojson_source.js +15 -24
- package/src/source/geojson_worker_source.js +40 -68
- package/src/source/geojson_wrapper.js +9 -1
- package/src/source/image_source.js +6 -16
- package/src/source/query_features.js +4 -5
- package/src/source/raster_dem_tile_source.js +45 -64
- package/src/source/raster_tile_source.js +1 -6
- package/src/source/resources/glyphs.js +2 -2
- package/src/source/resources/index.js +3 -9
- package/src/source/rtl_text_plugin.js +58 -31
- package/src/source/source.js +11 -13
- package/src/source/source_cache.js +135 -151
- package/src/source/source_state.js +101 -12
- package/src/source/tile.js +32 -46
- package/src/source/tile_bounds.js +26 -26
- package/src/source/tile_id.js +2 -5
- package/src/source/vector_tile_source.js +14 -14
- package/src/source/vector_tile_worker_source.js +19 -23
- package/src/source/worker_tile.js +122 -119
- package/src/style/create_style_layer.js +1 -1
- package/src/style/pauseable_placement.js +4 -5
- package/src/style/properties.js +1 -8
- package/src/style/query_utils.js +3 -3
- package/src/style/style.js +286 -216
- package/src/style/style_layer/circle_style_layer.js +13 -11
- package/src/style/style_layer/fill_extrusion_style_layer.js +42 -27
- package/src/style/style_layer/fill_style_layer.js +5 -5
- package/src/style/style_layer/heatmap_style_layer.js +1 -1
- package/src/style/style_layer/hillshade_style_layer.js +1 -1
- package/src/style/style_layer/line_style_layer.js +23 -19
- package/src/style/style_layer/symbol_style_layer.js +13 -13
- package/src/style/style_layer.js +71 -30
- package/src/style/style_layer_index.js +16 -41
- package/src/symbol/anchor.js +0 -4
- package/src/symbol/cross_tile_symbol_index.js +2 -5
- package/src/symbol/opacity_state.js +0 -4
- package/src/symbol/placement.js +3 -3
- package/src/symbol/quads.js +4 -4
- package/src/symbol/symbol_layout.js +7 -7
- package/src/symbol/transform_text.js +1 -1
- package/src/ui/map.js +52 -15
- package/src/util/group_layers.js +41 -0
- package/src/util/image.js +0 -5
- package/src/util/key.js +21 -0
- package/src/util/object.js +8 -53
- package/src/worker.js +1 -4
- package/src/source/resources/images.js +0 -68
- package/src/source/worker.js +0 -110
- package/src/source/worker_source.js +0 -14
- package/src/style-spec/deref.js +0 -51
- package/src/style-spec/group_by_layout.js +0 -46
- package/src/util/actor.js +0 -108
- package/src/util/dispatcher.js +0 -65
- package/src/util/global_worker_pool.js +0 -15
- package/src/util/transfer_registry.js +0 -168
- package/src/util/web_worker_transfer.js +0 -43
- package/src/util/worker_pool.js +0 -41
package/src/source/source.js
CHANGED
|
@@ -10,7 +10,6 @@ const { bindAll } = require('../util/object');
|
|
|
10
10
|
* @param {Object} options Source options, specific to the source type (except for `options.type`, which is always
|
|
11
11
|
* required).
|
|
12
12
|
* @param {string} options.type The source type, matching the value of `name` used in {@link Style#addSourceType}.
|
|
13
|
-
* @param {Dispatcher} dispatcher A {@link Dispatcher} instance, which can be used to send messages to the workers.
|
|
14
13
|
*
|
|
15
14
|
* @fires data with `{dataType: 'source', sourceDataType: 'metadata'}` to indicate that any necessary metadata
|
|
16
15
|
* has been loaded so that it's okay to call `loadTile`; and with `{dataType: 'source', sourceDataType: 'content'}`
|
|
@@ -25,11 +24,11 @@ const { bindAll } = require('../util/object');
|
|
|
25
24
|
* if they are floor-ed to the nearest integer.
|
|
26
25
|
*/
|
|
27
26
|
|
|
28
|
-
const vector = require('
|
|
29
|
-
const raster = require('
|
|
30
|
-
const rasterDem = require('
|
|
31
|
-
const geojson = require('
|
|
32
|
-
const image = require('
|
|
27
|
+
const vector = require('./vector_tile_source');
|
|
28
|
+
const raster = require('./raster_tile_source');
|
|
29
|
+
const rasterDem = require('./raster_dem_tile_source');
|
|
30
|
+
const geojson = require('./geojson_source');
|
|
31
|
+
const image = require('./image_source');
|
|
33
32
|
|
|
34
33
|
const sourceTypes = {
|
|
35
34
|
vector,
|
|
@@ -46,15 +45,14 @@ const sourceTypes = {
|
|
|
46
45
|
* @param {Object} source A source definition object compliant with
|
|
47
46
|
* [`mapbox-gl-style-spec`](https://www.mapbox.com/mapbox-gl-style-spec/#sources) or, for a third-party source type,
|
|
48
47
|
* with that type's requirements.
|
|
49
|
-
* @param {Dispatcher} dispatcher
|
|
50
48
|
* @returns {Source}
|
|
51
49
|
*/
|
|
52
|
-
function create(id, specification,
|
|
53
|
-
const source = new sourceTypes[specification.type](id, specification,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
50
|
+
function create(id, specification, eventedParent, { resources, layerIndex, showTileBoundaries }) {
|
|
51
|
+
const source = new sourceTypes[specification.type](id, specification, eventedParent, {
|
|
52
|
+
resources,
|
|
53
|
+
layerIndex,
|
|
54
|
+
showTileBoundaries
|
|
55
|
+
});
|
|
58
56
|
|
|
59
57
|
bindAll(['load', 'abort', 'unload', 'serialize', 'prepare'], source);
|
|
60
58
|
return source;
|
|
@@ -3,12 +3,10 @@ const Tile = require('./tile');
|
|
|
3
3
|
const { Event, ErrorEvent, Evented } = require('@mapwhit/events');
|
|
4
4
|
const TileCache = require('./tile_cache');
|
|
5
5
|
const Coordinate = require('../geo/coordinate');
|
|
6
|
-
const { keysDifference } = require('../util/object');
|
|
7
6
|
const EXTENT = require('../data/extent');
|
|
8
7
|
const { default: Point } = require('@mapbox/point-geometry');
|
|
9
8
|
const browser = require('../util/browser');
|
|
10
9
|
const { OverscaledTileID } = require('./tile_id');
|
|
11
|
-
const assert = require('assert');
|
|
12
10
|
const SourceFeatureState = require('./source_state');
|
|
13
11
|
|
|
14
12
|
/**
|
|
@@ -23,47 +21,42 @@ const SourceFeatureState = require('./source_state');
|
|
|
23
21
|
* @private
|
|
24
22
|
*/
|
|
25
23
|
class SourceCache extends Evented {
|
|
26
|
-
|
|
24
|
+
// this.#sourceLoaded signifies that the TileJSON is loaded if applicable.
|
|
25
|
+
// if the source type does not come with a TileJSON, the flag signifies the
|
|
26
|
+
// source data has loaded (i.e geojson has been tiled on the worker and is ready)
|
|
27
|
+
#sourceLoaded = false;
|
|
28
|
+
#sourceErrored = false;
|
|
29
|
+
#paused = false;
|
|
30
|
+
#shouldReloadOnResume = false;
|
|
31
|
+
|
|
32
|
+
constructor(id, options, workerOpts) {
|
|
27
33
|
super();
|
|
28
34
|
this.id = id;
|
|
29
|
-
this.dispatcher = dispatcher;
|
|
30
35
|
|
|
31
36
|
this.on('data', e => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// source data has loaded (i.e geojson has been tiled on the worker and is ready)
|
|
35
|
-
if (e.dataType === 'source' && e.sourceDataType === 'metadata') this._sourceLoaded = true;
|
|
37
|
+
if (e.dataType !== 'source') return;
|
|
38
|
+
if (e.sourceDataType === 'metadata') this.#sourceLoaded = true;
|
|
36
39
|
|
|
37
40
|
// for sources with mutable data, this event fires when the underlying data
|
|
38
41
|
// to a source is changed. (i.e. GeoJSONSource#setData and ImageSource#serCoordinates)
|
|
39
|
-
if (this
|
|
42
|
+
if (this.#sourceLoaded && !this.#paused && e.sourceDataType === 'content') {
|
|
40
43
|
this.reload();
|
|
41
|
-
if (this.transform)
|
|
42
|
-
this.update(this.transform);
|
|
43
|
-
}
|
|
44
|
+
if (this.transform) this.update(this.transform);
|
|
44
45
|
}
|
|
45
46
|
});
|
|
46
47
|
|
|
47
|
-
this.on('error', () =>
|
|
48
|
-
this._sourceErrored = true;
|
|
49
|
-
});
|
|
48
|
+
this.on('error', () => (this.#sourceErrored = true));
|
|
50
49
|
|
|
51
|
-
this._source = createSource(id, options,
|
|
50
|
+
this._source = createSource(id, options, this, workerOpts);
|
|
52
51
|
|
|
53
|
-
this._tiles =
|
|
52
|
+
this._tiles = new Map();
|
|
54
53
|
this._cache = new TileCache(0, this._unloadTile.bind(this));
|
|
55
|
-
this.
|
|
56
|
-
|
|
57
|
-
this._isIdRenderable = this._isIdRenderable.bind(this);
|
|
58
|
-
this._isIdRenderableForSymbols = this._isIdRenderableForSymbols.bind(this);
|
|
59
|
-
|
|
60
|
-
this._coveredTiles = {};
|
|
54
|
+
this._coveredTiles = new Set();
|
|
61
55
|
this._state = new SourceFeatureState();
|
|
62
56
|
}
|
|
63
57
|
|
|
64
58
|
onAdd(map) {
|
|
65
59
|
this.map = map;
|
|
66
|
-
this._maxTileCacheSize = map ? map._maxTileCacheSize : null;
|
|
67
60
|
if (this._source?.onAdd) {
|
|
68
61
|
this._source.onAdd(map);
|
|
69
62
|
}
|
|
@@ -80,14 +73,11 @@ class SourceCache extends Evented {
|
|
|
80
73
|
* an additional API call is received.
|
|
81
74
|
*/
|
|
82
75
|
loaded() {
|
|
83
|
-
if (this
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
for (const t in this._tiles) {
|
|
90
|
-
const tile = this._tiles[t];
|
|
76
|
+
if (this.#sourceErrored) return true;
|
|
77
|
+
|
|
78
|
+
if (!this.#sourceLoaded) return false;
|
|
79
|
+
|
|
80
|
+
for (const tile of this._tiles.values()) {
|
|
91
81
|
if (tile.state !== 'loaded' && tile.state !== 'errored') return false;
|
|
92
82
|
}
|
|
93
83
|
return true;
|
|
@@ -98,14 +88,14 @@ class SourceCache extends Evented {
|
|
|
98
88
|
}
|
|
99
89
|
|
|
100
90
|
pause() {
|
|
101
|
-
this
|
|
91
|
+
this.#paused = true;
|
|
102
92
|
}
|
|
103
93
|
|
|
104
94
|
resume() {
|
|
105
|
-
if (!this
|
|
106
|
-
const shouldReload = this
|
|
107
|
-
this
|
|
108
|
-
this
|
|
95
|
+
if (!this.#paused) return;
|
|
96
|
+
const shouldReload = this.#shouldReloadOnResume;
|
|
97
|
+
this.#paused = false;
|
|
98
|
+
this.#shouldReloadOnResume = false;
|
|
109
99
|
if (shouldReload) this.reload();
|
|
110
100
|
if (this.transform) this.update(this.transform);
|
|
111
101
|
}
|
|
@@ -122,77 +112,69 @@ class SourceCache extends Evented {
|
|
|
122
112
|
return this._source.abortTile?.(tile);
|
|
123
113
|
}
|
|
124
114
|
|
|
125
|
-
serialize() {
|
|
126
|
-
return this._source.serialize();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
115
|
prepare(context) {
|
|
130
116
|
this._source.prepare?.();
|
|
131
117
|
|
|
132
|
-
this._state.coalesceChanges(this._tiles, this.map
|
|
133
|
-
|
|
134
|
-
this._tiles[i].upload(context);
|
|
135
|
-
}
|
|
118
|
+
this._state.coalesceChanges(this._tiles.values(), this.map?.painter);
|
|
119
|
+
this._tiles.forEach(tile => tile.upload(context));
|
|
136
120
|
}
|
|
137
121
|
|
|
138
122
|
/**
|
|
139
|
-
* Return all tile ids ordered with z-order
|
|
123
|
+
* Return all tile ids ordered with z-order
|
|
140
124
|
*/
|
|
141
|
-
getIds() {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
125
|
+
getIds(filter = () => true) {
|
|
126
|
+
const angle = this.transform?.angle ?? 0;
|
|
127
|
+
|
|
128
|
+
return Array.from(this._tiles)
|
|
129
|
+
.filter(it => filter.call(this, it[1]))
|
|
130
|
+
.sort(compareKeyZoom)
|
|
131
|
+
.map(it => it[0]);
|
|
132
|
+
|
|
133
|
+
function compareKeyZoom([, a_], [, b_]) {
|
|
134
|
+
const a = a_.tileID;
|
|
135
|
+
const b = b_.tileID;
|
|
136
|
+
const zDiff = a.overscaledZ - b.overscaledZ;
|
|
137
|
+
if (zDiff !== 0) {
|
|
138
|
+
return zDiff;
|
|
139
|
+
}
|
|
140
|
+
const rotatedA = new Point(a.canonical.x, a.canonical.y).rotate(angle);
|
|
141
|
+
const rotatedB = new Point(b.canonical.x, b.canonical.y).rotate(angle);
|
|
142
|
+
return rotatedB.y - rotatedA.y || rotatedB.x - rotatedA.x;
|
|
143
|
+
}
|
|
151
144
|
}
|
|
152
145
|
|
|
153
146
|
getRenderableIds(symbolLayer) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
: this.getIds().filter(this._isIdRenderable);
|
|
147
|
+
const filter = symbolLayer ? this.#isTileRenderableForSymbols : this.#isTileRenderable;
|
|
148
|
+
return this.getIds(filter);
|
|
157
149
|
}
|
|
158
150
|
|
|
159
151
|
hasRenderableParent(tileID) {
|
|
160
152
|
const parentTile = this.findLoadedParent(tileID, 0);
|
|
161
|
-
|
|
162
|
-
return this._isIdRenderable(parentTile.tileID.key);
|
|
163
|
-
}
|
|
164
|
-
return false;
|
|
153
|
+
return this.#isTileRenderable(parentTile);
|
|
165
154
|
}
|
|
166
155
|
|
|
167
|
-
|
|
168
|
-
return
|
|
156
|
+
#isTileRenderable(tile) {
|
|
157
|
+
return tile?.hasData() && !this._coveredTiles.has(tile.tileID.key) && !tile.holdingForFade();
|
|
169
158
|
}
|
|
170
159
|
|
|
171
|
-
|
|
172
|
-
return
|
|
160
|
+
#isTileRenderableForSymbols(tile) {
|
|
161
|
+
return tile?.hasData() && !this._coveredTiles.has(tile.tileID.key);
|
|
173
162
|
}
|
|
174
163
|
|
|
175
164
|
reload() {
|
|
176
|
-
if (this
|
|
177
|
-
this
|
|
165
|
+
if (this.#paused) {
|
|
166
|
+
this.#shouldReloadOnResume = true;
|
|
178
167
|
return;
|
|
179
168
|
}
|
|
180
169
|
|
|
181
170
|
this._cache.reset();
|
|
182
171
|
|
|
183
|
-
|
|
184
|
-
if (
|
|
185
|
-
}
|
|
172
|
+
this._tiles.forEach(tile => {
|
|
173
|
+
if (tile.state !== 'errored') this._reloadTile(tile, 'reloading');
|
|
174
|
+
});
|
|
186
175
|
}
|
|
187
176
|
|
|
188
|
-
_reloadTile(
|
|
189
|
-
const tile = this._tiles[id];
|
|
190
|
-
|
|
191
|
-
// this potentially does not address all underlying
|
|
192
|
-
// issues https://github.com/mapbox/mapbox-gl-js/issues/4252
|
|
193
|
-
// - hard to tell without repro steps
|
|
194
|
-
if (!tile) return;
|
|
195
|
-
|
|
177
|
+
_reloadTile(tile, state) {
|
|
196
178
|
// The difference between "loading" tiles and "reloading" or "expired"
|
|
197
179
|
// tiles is that "reloading"/"expired" tiles are "renderable".
|
|
198
180
|
// Therefore, a "loading" tile cannot become a "reloading" tile without
|
|
@@ -273,7 +255,7 @@ class SourceCache extends Evented {
|
|
|
273
255
|
* Get a specific tile by id
|
|
274
256
|
*/
|
|
275
257
|
getTileByID(id) {
|
|
276
|
-
return this._tiles
|
|
258
|
+
return this._tiles.get(+id);
|
|
277
259
|
}
|
|
278
260
|
|
|
279
261
|
/**
|
|
@@ -288,11 +270,14 @@ class SourceCache extends Evented {
|
|
|
288
270
|
* between `zoom` (exclusive) and `maxCoveringZoom` (inclusive)
|
|
289
271
|
*/
|
|
290
272
|
_retainLoadedChildren(idealTiles, zoom, maxCoveringZoom, retain) {
|
|
291
|
-
for (
|
|
292
|
-
let tile = this._tiles[id];
|
|
293
|
-
|
|
273
|
+
for (let [id, tile] of this._tiles) {
|
|
294
274
|
// only consider renderable tiles up to maxCoveringZoom
|
|
295
|
-
if (
|
|
275
|
+
if (
|
|
276
|
+
retain.has(id) ||
|
|
277
|
+
!tile.hasData() ||
|
|
278
|
+
tile.tileID.overscaledZ <= zoom ||
|
|
279
|
+
tile.tileID.overscaledZ > maxCoveringZoom
|
|
280
|
+
)
|
|
296
281
|
continue;
|
|
297
282
|
|
|
298
283
|
// loop through parents and retain the topmost loaded one if found
|
|
@@ -300,7 +285,7 @@ class SourceCache extends Evented {
|
|
|
300
285
|
while (tile && tile.tileID.overscaledZ > zoom + 1) {
|
|
301
286
|
const parentID = tile.tileID.scaledTo(tile.tileID.overscaledZ - 1);
|
|
302
287
|
|
|
303
|
-
tile = this._tiles
|
|
288
|
+
tile = this._tiles.get(parentID.key);
|
|
304
289
|
|
|
305
290
|
if (tile?.hasData()) {
|
|
306
291
|
topmostLoadedID = parentID;
|
|
@@ -311,10 +296,9 @@ class SourceCache extends Evented {
|
|
|
311
296
|
let tileID = topmostLoadedID;
|
|
312
297
|
while (tileID.overscaledZ > zoom) {
|
|
313
298
|
tileID = tileID.scaledTo(tileID.overscaledZ - 1);
|
|
314
|
-
|
|
315
|
-
if (idealTiles[tileID.key]) {
|
|
299
|
+
if (idealTiles.has(tileID.key)) {
|
|
316
300
|
// found a parent that needed a loaded child; retain that child
|
|
317
|
-
retain
|
|
301
|
+
retain.set(topmostLoadedID.key, topmostLoadedID);
|
|
318
302
|
break;
|
|
319
303
|
}
|
|
320
304
|
}
|
|
@@ -328,8 +312,7 @@ class SourceCache extends Evented {
|
|
|
328
312
|
for (let z = tileID.overscaledZ - 1; z >= minCoveringZoom; z--) {
|
|
329
313
|
const parent = tileID.scaledTo(z);
|
|
330
314
|
if (!parent) return;
|
|
331
|
-
const
|
|
332
|
-
const tile = this._tiles[id];
|
|
315
|
+
const tile = this._tiles.get(parent.key);
|
|
333
316
|
if (tile?.hasData()) {
|
|
334
317
|
return tile;
|
|
335
318
|
}
|
|
@@ -341,8 +324,7 @@ class SourceCache extends Evented {
|
|
|
341
324
|
}
|
|
342
325
|
|
|
343
326
|
/**
|
|
344
|
-
* Resizes the tile cache based on the current viewport's size
|
|
345
|
-
* or the maxTileCacheSize option passed during map creation
|
|
327
|
+
* Resizes the tile cache based on the current viewport's size.
|
|
346
328
|
*
|
|
347
329
|
* Larger viewports use more tiles and need larger caches. Larger viewports
|
|
348
330
|
* are more likely to be found on devices with more memory and on pages where
|
|
@@ -355,12 +337,7 @@ class SourceCache extends Evented {
|
|
|
355
337
|
const commonZoomRange = 5;
|
|
356
338
|
|
|
357
339
|
const viewDependentMaxSize = Math.floor(approxTilesInView * commonZoomRange);
|
|
358
|
-
|
|
359
|
-
typeof this._maxTileCacheSize === 'number'
|
|
360
|
-
? Math.min(this._maxTileCacheSize, viewDependentMaxSize)
|
|
361
|
-
: viewDependentMaxSize;
|
|
362
|
-
|
|
363
|
-
this._cache.setMaxSize(maxSize);
|
|
340
|
+
this._cache.setMaxSize(viewDependentMaxSize);
|
|
364
341
|
}
|
|
365
342
|
|
|
366
343
|
handleWrapJump(lng) {
|
|
@@ -386,11 +363,10 @@ class SourceCache extends Evented {
|
|
|
386
363
|
this._prevLng = lng;
|
|
387
364
|
|
|
388
365
|
if (wrapDelta) {
|
|
389
|
-
const tiles =
|
|
390
|
-
for (const
|
|
391
|
-
const tile = this._tiles[key];
|
|
366
|
+
const tiles = new Map();
|
|
367
|
+
for (const tile of this._tiles.values()) {
|
|
392
368
|
tile.tileID = tile.tileID.unwrapTo(tile.tileID.wrap + wrapDelta);
|
|
393
|
-
tiles
|
|
369
|
+
tiles.set(tile.tileID.key, tile);
|
|
394
370
|
}
|
|
395
371
|
this._tiles = tiles;
|
|
396
372
|
}
|
|
@@ -402,7 +378,7 @@ class SourceCache extends Evented {
|
|
|
402
378
|
*/
|
|
403
379
|
update(transform) {
|
|
404
380
|
this.transform = transform;
|
|
405
|
-
if (!this
|
|
381
|
+
if (!this.#sourceLoaded || this.#paused) {
|
|
406
382
|
return;
|
|
407
383
|
}
|
|
408
384
|
|
|
@@ -411,7 +387,7 @@ class SourceCache extends Evented {
|
|
|
411
387
|
|
|
412
388
|
// Covered is a list of retained tiles who's areas are fully covered by other,
|
|
413
389
|
// better, retained tiles. They are not drawn separately.
|
|
414
|
-
this._coveredTiles
|
|
390
|
+
this._coveredTiles.clear();
|
|
415
391
|
|
|
416
392
|
let idealTileIDs;
|
|
417
393
|
if (!this.used) {
|
|
@@ -454,82 +430,77 @@ class SourceCache extends Evented {
|
|
|
454
430
|
const retain = this._updateRetainedTiles(idealTileIDs, zoom);
|
|
455
431
|
|
|
456
432
|
if (isRasterType(this._source.type)) {
|
|
457
|
-
const parentsForFading =
|
|
458
|
-
const fadingTiles =
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
const tileID = retain[id];
|
|
462
|
-
assert(tileID.key === +id);
|
|
463
|
-
|
|
464
|
-
const tile = this._tiles[id];
|
|
433
|
+
const parentsForFading = new Map();
|
|
434
|
+
const fadingTiles = new Set();
|
|
435
|
+
for (const [id, tileID] of retain) {
|
|
436
|
+
const tile = this._tiles.get(id);
|
|
465
437
|
if (!tile || (tile.fadeEndTime && tile.fadeEndTime <= browser.now())) continue;
|
|
466
438
|
|
|
467
439
|
// if the tile is loaded but still fading in, find parents to cross-fade with it
|
|
468
440
|
const parentTile = this.findLoadedParent(tileID, minCoveringZoom);
|
|
469
441
|
if (parentTile) {
|
|
470
442
|
this._addTile(parentTile.tileID);
|
|
471
|
-
parentsForFading
|
|
443
|
+
parentsForFading.set(parentTile.tileID.key, parentTile.tileID);
|
|
472
444
|
}
|
|
473
445
|
|
|
474
|
-
fadingTiles
|
|
446
|
+
fadingTiles.add(id);
|
|
475
447
|
}
|
|
476
448
|
|
|
477
449
|
// for tiles that are still fading in, also find children to cross-fade with
|
|
478
450
|
this._retainLoadedChildren(fadingTiles, zoom, maxCoveringZoom, retain);
|
|
479
451
|
|
|
480
|
-
for (const id
|
|
481
|
-
if (!retain
|
|
452
|
+
for (const [id, tileID] of parentsForFading) {
|
|
453
|
+
if (!retain.has(id)) {
|
|
482
454
|
// If a tile is only needed for fading, mark it as covered so that it isn't rendered on it's own.
|
|
483
|
-
this._coveredTiles
|
|
484
|
-
retain
|
|
455
|
+
this._coveredTiles.add(id);
|
|
456
|
+
retain.set(id, tileID);
|
|
485
457
|
}
|
|
486
458
|
}
|
|
487
459
|
}
|
|
488
460
|
|
|
489
|
-
for (const retainedId
|
|
461
|
+
for (const [retainedId] of retain) {
|
|
490
462
|
// Make sure retained tiles always clear any existing fade holds
|
|
491
463
|
// so that if they're removed again their fade timer starts fresh.
|
|
492
|
-
this._tiles
|
|
464
|
+
this._tiles.get(retainedId).clearFadeHold();
|
|
493
465
|
}
|
|
494
466
|
|
|
495
467
|
// Remove the tiles we don't need anymore.
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
const tile = this._tiles[tileID];
|
|
468
|
+
for (const [id, tile] of this._tiles) {
|
|
469
|
+
if (retain.has(id)) continue;
|
|
499
470
|
if (tile.hasSymbolBuckets && !tile.holdingForFade()) {
|
|
500
471
|
tile.setHoldDuration(this.map._fadeDuration);
|
|
501
472
|
} else if (!tile.hasSymbolBuckets || tile.symbolFadeFinished()) {
|
|
502
|
-
this._removeTile(
|
|
473
|
+
this._removeTile(id);
|
|
503
474
|
}
|
|
504
475
|
}
|
|
505
476
|
}
|
|
506
477
|
|
|
507
478
|
releaseSymbolFadeTiles() {
|
|
508
|
-
for (const id
|
|
509
|
-
if (
|
|
479
|
+
for (const [id, tile] of this._tiles) {
|
|
480
|
+
if (tile.holdingForFade()) {
|
|
510
481
|
this._removeTile(id);
|
|
511
482
|
}
|
|
512
483
|
}
|
|
513
484
|
}
|
|
514
485
|
|
|
515
486
|
_updateRetainedTiles(idealTileIDs, zoom) {
|
|
516
|
-
const retain =
|
|
517
|
-
const checked =
|
|
487
|
+
const retain = new Map();
|
|
488
|
+
const checked = new Set();
|
|
518
489
|
const minCoveringZoom = Math.max(zoom - SourceCache.maxOverzooming, this._source.minzoom);
|
|
519
490
|
const maxCoveringZoom = Math.max(zoom + SourceCache.maxUnderzooming, this._source.minzoom);
|
|
520
491
|
|
|
521
|
-
const missingTiles =
|
|
492
|
+
const missingTiles = new Set();
|
|
522
493
|
for (const tileID of idealTileIDs) {
|
|
523
494
|
const tile = this._addTile(tileID);
|
|
524
495
|
|
|
525
496
|
// retain the tile even if it's not loaded because it's an ideal tile.
|
|
526
|
-
retain
|
|
497
|
+
retain.set(tileID.key, tileID);
|
|
527
498
|
|
|
528
499
|
if (tile.hasData()) continue;
|
|
529
500
|
|
|
530
501
|
if (zoom < this._source.maxzoom) {
|
|
531
502
|
// save missing tiles that potentially have loaded children
|
|
532
|
-
missingTiles
|
|
503
|
+
missingTiles.add(tileID.key);
|
|
533
504
|
}
|
|
534
505
|
}
|
|
535
506
|
|
|
@@ -537,7 +508,7 @@ class SourceCache extends Evented {
|
|
|
537
508
|
this._retainLoadedChildren(missingTiles, zoom, maxCoveringZoom, retain);
|
|
538
509
|
|
|
539
510
|
for (const tileID of idealTileIDs) {
|
|
540
|
-
let tile = this._tiles
|
|
511
|
+
let tile = this._tiles.get(tileID.key);
|
|
541
512
|
|
|
542
513
|
if (tile.hasData()) continue;
|
|
543
514
|
|
|
@@ -549,14 +520,19 @@ class SourceCache extends Evented {
|
|
|
549
520
|
const childCoord = tileID.children(this._source.maxzoom)[0];
|
|
550
521
|
const childTile = this.getTile(childCoord);
|
|
551
522
|
if (!!childTile && childTile.hasData()) {
|
|
552
|
-
retain
|
|
523
|
+
retain.set(childCoord.key, childCoord);
|
|
553
524
|
continue; // tile is covered by overzoomed child
|
|
554
525
|
}
|
|
555
526
|
} else {
|
|
556
527
|
// check if all 4 immediate children are loaded (i.e. the missing ideal tile is covered)
|
|
557
528
|
const children = tileID.children(this._source.maxzoom);
|
|
558
529
|
|
|
559
|
-
if (
|
|
530
|
+
if (
|
|
531
|
+
retain.has(children[0].key) &&
|
|
532
|
+
retain.has(children[1].key) &&
|
|
533
|
+
retain.has(children[2].key) &&
|
|
534
|
+
retain.has(children[3].key)
|
|
535
|
+
)
|
|
560
536
|
continue; // tile is covered by children
|
|
561
537
|
}
|
|
562
538
|
|
|
@@ -571,15 +547,15 @@ class SourceCache extends Evented {
|
|
|
571
547
|
const parentId = tileID.scaledTo(overscaledZ);
|
|
572
548
|
|
|
573
549
|
// Break parent tile ascent if this route has been previously checked by another child.
|
|
574
|
-
if (checked
|
|
575
|
-
checked
|
|
550
|
+
if (checked.has(parentId.key)) break;
|
|
551
|
+
checked.add(parentId.key);
|
|
576
552
|
|
|
577
553
|
tile = this.getTile(parentId);
|
|
578
554
|
if (!tile && parentWasRequested) {
|
|
579
555
|
tile = this._addTile(parentId);
|
|
580
556
|
}
|
|
581
557
|
if (tile) {
|
|
582
|
-
retain
|
|
558
|
+
retain.set(parentId.key, parentId);
|
|
583
559
|
// Save the current values, since they're the parent of the next iteration
|
|
584
560
|
// of the parent tile ascent loop.
|
|
585
561
|
parentWasRequested = tile.wasRequested();
|
|
@@ -596,14 +572,14 @@ class SourceCache extends Evented {
|
|
|
596
572
|
* @private
|
|
597
573
|
*/
|
|
598
574
|
_addTile(tileID) {
|
|
599
|
-
let tile = this._tiles
|
|
575
|
+
let tile = this._tiles.get(tileID.key);
|
|
600
576
|
if (tile) return tile;
|
|
601
577
|
|
|
602
578
|
tile = this._cache.getAndRemove(tileID);
|
|
603
579
|
if (tile) {
|
|
604
580
|
// set the tileID because the cached tile could have had a different wrap value
|
|
605
581
|
tile.tileID = tileID;
|
|
606
|
-
this._state.initializeTileState(tile, this.map
|
|
582
|
+
this._state.initializeTileState(tile, this.map?.painter);
|
|
607
583
|
}
|
|
608
584
|
|
|
609
585
|
const cached = Boolean(tile);
|
|
@@ -619,7 +595,7 @@ class SourceCache extends Evented {
|
|
|
619
595
|
if (!tile) return null;
|
|
620
596
|
|
|
621
597
|
tile.uses++;
|
|
622
|
-
this._tiles
|
|
598
|
+
this._tiles.set(tileID.key, tile);
|
|
623
599
|
if (!cached) this._source.fire(new Event('dataloading', { tile: tile, coord: tile.tileID, dataType: 'source' }));
|
|
624
600
|
|
|
625
601
|
return tile;
|
|
@@ -630,11 +606,11 @@ class SourceCache extends Evented {
|
|
|
630
606
|
* @private
|
|
631
607
|
*/
|
|
632
608
|
_removeTile(id) {
|
|
633
|
-
const tile = this._tiles
|
|
609
|
+
const tile = this._tiles.get(id);
|
|
634
610
|
if (!tile) return;
|
|
635
611
|
|
|
636
612
|
tile.uses--;
|
|
637
|
-
|
|
613
|
+
this._tiles.delete(id);
|
|
638
614
|
|
|
639
615
|
if (tile.uses > 0) return;
|
|
640
616
|
|
|
@@ -651,10 +627,10 @@ class SourceCache extends Evented {
|
|
|
651
627
|
* Remove all tiles from this pyramid
|
|
652
628
|
*/
|
|
653
629
|
clearTiles() {
|
|
654
|
-
this
|
|
655
|
-
this
|
|
630
|
+
this.#shouldReloadOnResume = false;
|
|
631
|
+
this.#paused = false;
|
|
656
632
|
|
|
657
|
-
for (const id
|
|
633
|
+
for (const id of this._tiles.keys()) this._removeTile(id);
|
|
658
634
|
|
|
659
635
|
this._cache.reset();
|
|
660
636
|
}
|
|
@@ -693,8 +669,8 @@ class SourceCache extends Evented {
|
|
|
693
669
|
maxY = Math.max(maxY, p.row);
|
|
694
670
|
}
|
|
695
671
|
|
|
696
|
-
for (
|
|
697
|
-
const tile = this._tiles
|
|
672
|
+
for (const id of ids) {
|
|
673
|
+
const tile = this._tiles.get(id);
|
|
698
674
|
if (tile.holdingForFade()) {
|
|
699
675
|
// Tiles held for fading are covered by tiles that are closer to ideal
|
|
700
676
|
continue;
|
|
@@ -731,7 +707,7 @@ class SourceCache extends Evented {
|
|
|
731
707
|
}
|
|
732
708
|
|
|
733
709
|
getVisibleCoordinates(symbolLayer) {
|
|
734
|
-
const coords = this.getRenderableIds(symbolLayer).map(id => this._tiles
|
|
710
|
+
const coords = this.getRenderableIds(symbolLayer).map(id => this._tiles.get(id).tileID);
|
|
735
711
|
for (const coord of coords) {
|
|
736
712
|
coord.posMatrix = this.transform.calculatePosMatrix(coord.toUnwrapped());
|
|
737
713
|
}
|
|
@@ -744,8 +720,7 @@ class SourceCache extends Evented {
|
|
|
744
720
|
}
|
|
745
721
|
|
|
746
722
|
if (isRasterType(this._source.type)) {
|
|
747
|
-
for (const
|
|
748
|
-
const tile = this._tiles[id];
|
|
723
|
+
for (const tile of this._tiles.values()) {
|
|
749
724
|
if (tile.fadeEndTime !== undefined && tile.fadeEndTime >= browser.now()) {
|
|
750
725
|
return true;
|
|
751
726
|
}
|
|
@@ -764,6 +739,15 @@ class SourceCache extends Evented {
|
|
|
764
739
|
this._state.updateState(sourceLayer, feature, state);
|
|
765
740
|
}
|
|
766
741
|
|
|
742
|
+
/**
|
|
743
|
+
* Resets the value of a particular state key for a feature
|
|
744
|
+
* @private
|
|
745
|
+
*/
|
|
746
|
+
removeFeatureState(sourceLayer, feature, key) {
|
|
747
|
+
sourceLayer = sourceLayer || '_geojsonTileLayer';
|
|
748
|
+
this._state.removeFeatureState(sourceLayer, feature, key);
|
|
749
|
+
}
|
|
750
|
+
|
|
767
751
|
/**
|
|
768
752
|
* Get the entire state object for a feature
|
|
769
753
|
* @private
|