ol 9.2.5-dev.1718651852752 → 9.2.5-dev.1718925536936
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/DataTile.d.ts +14 -0
- package/DataTile.d.ts.map +1 -1
- package/DataTile.js +24 -1
- package/Map.d.ts +1 -1
- package/Map.d.ts.map +1 -1
- package/Map.js +9 -10
- package/Tile.d.ts +2 -22
- package/Tile.d.ts.map +1 -1
- package/Tile.js +2 -77
- package/TileQueue.d.ts.map +1 -1
- package/TileQueue.js +6 -4
- package/VectorRenderTile.d.ts +8 -13
- package/VectorRenderTile.d.ts.map +1 -1
- package/VectorRenderTile.js +17 -24
- package/VectorTile.d.ts +5 -5
- package/VectorTile.d.ts.map +1 -1
- package/VectorTile.js +3 -3
- package/dist/ol.d.ts +10 -2
- package/dist/ol.d.ts.map +1 -1
- package/dist/ol.js +2 -2
- package/dist/ol.js.map +1 -1
- package/featureloader.d.ts +4 -4
- package/featureloader.d.ts.map +1 -1
- package/featureloader.js +2 -2
- package/format/EsriJSON.d.ts +1 -1
- package/format/Feature.d.ts +8 -8
- package/format/Feature.d.ts.map +1 -1
- package/format/Feature.js +7 -5
- package/format/GeoJSON.d.ts +9 -9
- package/format/GeoJSON.d.ts.map +1 -1
- package/format/GeoJSON.js +10 -14
- package/format/JSONFeature.d.ts +7 -7
- package/format/JSONFeature.d.ts.map +1 -1
- package/format/JSONFeature.js +9 -11
- package/format/MVT.d.ts +12 -12
- package/format/MVT.d.ts.map +1 -1
- package/format/MVT.js +12 -14
- package/format/TextFeature.d.ts +1 -1
- package/format/TopoJSON.d.ts +1 -1
- package/format/WKB.d.ts +1 -1
- package/format/XMLFeature.d.ts +1 -1
- package/interaction/DragAndDrop.d.ts +1 -1
- package/layer/BaseTile.d.ts +23 -6
- package/layer/BaseTile.d.ts.map +1 -1
- package/layer/BaseTile.js +22 -3
- package/layer/Tile.d.ts +1 -1
- package/layer/Tile.d.ts.map +1 -1
- package/layer/Tile.js +3 -1
- package/layer/VectorTile.d.ts +19 -6
- package/layer/VectorTile.d.ts.map +1 -1
- package/layer/VectorTile.js +20 -8
- package/layer/WebGLTile.d.ts +5 -10
- package/layer/WebGLTile.d.ts.map +1 -1
- package/layer/WebGLTile.js +3 -12
- package/package.json +1 -1
- package/renderer/Layer.d.ts +22 -25
- package/renderer/Layer.d.ts.map +1 -1
- package/renderer/Layer.js +36 -36
- package/renderer/canvas/TileLayer.d.ts +100 -38
- package/renderer/canvas/TileLayer.d.ts.map +1 -1
- package/renderer/canvas/TileLayer.js +542 -329
- package/renderer/canvas/VectorTileLayer.d.ts +11 -11
- package/renderer/canvas/VectorTileLayer.d.ts.map +1 -1
- package/renderer/canvas/VectorTileLayer.js +33 -46
- package/renderer/webgl/TileLayerBase.d.ts +0 -6
- package/renderer/webgl/TileLayerBase.d.ts.map +1 -1
- package/renderer/webgl/TileLayerBase.js +61 -78
- package/reproj/DataTile.d.ts.map +1 -1
- package/reproj/DataTile.js +103 -100
- package/source/BingMaps.d.ts +2 -2
- package/source/BingMaps.d.ts.map +1 -1
- package/source/BingMaps.js +1 -2
- package/source/CartoDB.d.ts +2 -2
- package/source/CartoDB.js +1 -1
- package/source/DataTile.d.ts +49 -20
- package/source/DataTile.d.ts.map +1 -1
- package/source/DataTile.js +56 -9
- package/source/GeoTIFF.d.ts +2 -6
- package/source/GeoTIFF.d.ts.map +1 -1
- package/source/GeoTIFF.js +3 -3
- package/source/Google.d.ts.map +1 -1
- package/source/Google.js +0 -2
- package/source/IIIF.d.ts +1 -1
- package/source/IIIF.js +1 -1
- package/source/ImageTile.d.ts +102 -0
- package/source/ImageTile.d.ts.map +1 -0
- package/source/ImageTile.js +208 -0
- package/source/OGCMapTile.d.ts +2 -2
- package/source/OGCMapTile.js +1 -1
- package/source/OGCVectorTile.d.ts +4 -4
- package/source/OGCVectorTile.js +2 -2
- package/source/OSM.d.ts +2 -7
- package/source/OSM.d.ts.map +1 -1
- package/source/OSM.js +1 -3
- package/source/StadiaMaps.d.ts +2 -2
- package/source/StadiaMaps.d.ts.map +1 -1
- package/source/StadiaMaps.js +2 -18
- package/source/Tile.d.ts +7 -36
- package/source/Tile.d.ts.map +1 -1
- package/source/Tile.js +5 -69
- package/source/TileArcGISRest.d.ts +2 -2
- package/source/TileArcGISRest.js +1 -1
- package/source/TileDebug.d.ts.map +1 -1
- package/source/TileDebug.js +0 -1
- package/source/TileImage.d.ts +7 -11
- package/source/TileImage.d.ts.map +1 -1
- package/source/TileImage.js +11 -43
- package/source/TileJSON.d.ts +2 -2
- package/source/TileJSON.js +1 -1
- package/source/TileWMS.d.ts +2 -2
- package/source/TileWMS.d.ts.map +1 -1
- package/source/TileWMS.js +1 -4
- package/source/UTFGrid.d.ts +1 -1
- package/source/UrlTile.d.ts +14 -12
- package/source/UrlTile.d.ts.map +1 -1
- package/source/UrlTile.js +12 -7
- package/source/Vector.d.ts +5 -5
- package/source/Vector.d.ts.map +1 -1
- package/source/Vector.js +3 -3
- package/source/VectorTile.d.ts +4 -17
- package/source/VectorTile.d.ts.map +1 -1
- package/source/VectorTile.js +10 -85
- package/source/WMTS.d.ts +2 -2
- package/source/WMTS.js +3 -3
- package/source/XYZ.d.ts +14 -17
- package/source/XYZ.d.ts.map +1 -1
- package/source/XYZ.js +7 -8
- package/source/Zoomify.d.ts +2 -2
- package/source/Zoomify.d.ts.map +1 -1
- package/source/Zoomify.js +3 -2
- package/source.d.ts +1 -0
- package/source.d.ts.map +1 -1
- package/source.js +1 -0
- package/tilecoord.d.ts +7 -0
- package/tilecoord.d.ts.map +1 -1
- package/tilecoord.js +11 -1
- package/tileurlfunction.d.ts +3 -7
- package/tileurlfunction.d.ts.map +1 -1
- package/tileurlfunction.js +14 -47
- package/uri.d.ts +23 -3
- package/uri.d.ts.map +1 -1
- package/uri.js +75 -0
- package/util.js +1 -1
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* @module ol/renderer/canvas/TileLayer
|
|
3
3
|
*/
|
|
4
4
|
import CanvasLayerRenderer from './Layer.js';
|
|
5
|
+
import DataTile, {asImageLike} from '../../DataTile.js';
|
|
5
6
|
import ImageTile from '../../ImageTile.js';
|
|
7
|
+
import LRUCache from '../../structs/LRUCache.js';
|
|
8
|
+
import ReprojDataTile from '../../reproj/DataTile.js';
|
|
6
9
|
import ReprojTile from '../../reproj/Tile.js';
|
|
7
10
|
import TileRange from '../../TileRange.js';
|
|
8
11
|
import TileState from '../../TileState.js';
|
|
@@ -16,14 +19,96 @@ import {
|
|
|
16
19
|
createEmpty,
|
|
17
20
|
equals,
|
|
18
21
|
getIntersection,
|
|
19
|
-
getRotatedViewport,
|
|
20
22
|
getTopLeft,
|
|
21
23
|
intersects,
|
|
22
24
|
} from '../../extent.js';
|
|
25
|
+
import {createOrUpdate as createTileCoord, getKeyZXY} from '../../tilecoord.js';
|
|
23
26
|
import {fromUserExtent} from '../../proj.js';
|
|
24
27
|
import {getUid} from '../../util.js';
|
|
25
28
|
import {toSize} from '../../size.js';
|
|
26
29
|
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} sourceKey The source key.
|
|
32
|
+
* @param {number} z The tile z level.
|
|
33
|
+
* @param {number} x The tile x level.
|
|
34
|
+
* @param {number} y The tile y level.
|
|
35
|
+
* @return {string} The cache key.
|
|
36
|
+
*/
|
|
37
|
+
function getCacheKey(sourceKey, z, x, y) {
|
|
38
|
+
return `${sourceKey},${getKeyZXY(z, x, y)}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @typedef {Object<number, Set<import("../../Tile.js").default>>} TileLookup
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Add a tile to the lookup.
|
|
47
|
+
* @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
|
|
48
|
+
* @param {import("../../Tile.js").default} tile A tile.
|
|
49
|
+
* @param {number} z The zoom level.
|
|
50
|
+
* @return {boolean} The tile was added to the lookup.
|
|
51
|
+
*/
|
|
52
|
+
function addTileToLookup(tilesByZ, tile, z) {
|
|
53
|
+
if (!(z in tilesByZ)) {
|
|
54
|
+
tilesByZ[z] = new Set([tile]);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
const set = tilesByZ[z];
|
|
58
|
+
const existing = set.has(tile);
|
|
59
|
+
if (!existing) {
|
|
60
|
+
set.add(tile);
|
|
61
|
+
}
|
|
62
|
+
return !existing;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Remove a tile from the lookup.
|
|
67
|
+
* @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
|
|
68
|
+
* @param {import("../../Tile.js").default} tile A tile.
|
|
69
|
+
* @param {number} z The zoom level.
|
|
70
|
+
* @return {boolean} The tile was removed from the lookup.
|
|
71
|
+
*/
|
|
72
|
+
function removeTileFromLookup(tilesByZ, tile, z) {
|
|
73
|
+
const set = tilesByZ[z];
|
|
74
|
+
if (set) {
|
|
75
|
+
return set.delete(tile);
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
82
|
+
* @param {import("../../extent.js").Extent} extent The frame extent.
|
|
83
|
+
* @return {import("../../extent.js").Extent} Frame extent intersected with layer extents.
|
|
84
|
+
*/
|
|
85
|
+
function getRenderExtent(frameState, extent) {
|
|
86
|
+
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
|
87
|
+
if (layerState.extent) {
|
|
88
|
+
extent = getIntersection(
|
|
89
|
+
extent,
|
|
90
|
+
fromUserExtent(layerState.extent, frameState.viewState.projection),
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const source = /** @type {import("../../source/Tile.js").default} */ (
|
|
94
|
+
layerState.layer.getRenderSource()
|
|
95
|
+
);
|
|
96
|
+
if (!source.getWrapX()) {
|
|
97
|
+
const gridExtent = source
|
|
98
|
+
.getTileGridForProjection(frameState.viewState.projection)
|
|
99
|
+
.getExtent();
|
|
100
|
+
if (gridExtent) {
|
|
101
|
+
extent = getIntersection(extent, gridExtent);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return extent;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @typedef {Object} Options
|
|
109
|
+
* @property {number} [cacheSize=512] The cache size.
|
|
110
|
+
*/
|
|
111
|
+
|
|
27
112
|
/**
|
|
28
113
|
* @classdesc
|
|
29
114
|
* Canvas renderer for tile layers.
|
|
@@ -34,16 +119,25 @@ import {toSize} from '../../size.js';
|
|
|
34
119
|
class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
35
120
|
/**
|
|
36
121
|
* @param {LayerType} tileLayer Tile layer.
|
|
122
|
+
* @param {Options} [options] Options.
|
|
37
123
|
*/
|
|
38
|
-
constructor(tileLayer) {
|
|
124
|
+
constructor(tileLayer, options) {
|
|
39
125
|
super(tileLayer);
|
|
40
126
|
|
|
127
|
+
options = options || {};
|
|
128
|
+
|
|
41
129
|
/**
|
|
42
130
|
* Rendered extent has changed since the previous `renderFrame()` call
|
|
43
131
|
* @type {boolean}
|
|
44
132
|
*/
|
|
45
133
|
this.extentChanged = true;
|
|
46
134
|
|
|
135
|
+
/**
|
|
136
|
+
* The last call to `renderFrame` was completed with all tiles loaded
|
|
137
|
+
* @type {boolean}
|
|
138
|
+
*/
|
|
139
|
+
this.renderComplete = false;
|
|
140
|
+
|
|
47
141
|
/**
|
|
48
142
|
* @private
|
|
49
143
|
* @type {?import("../../extent.js").Extent}
|
|
@@ -76,60 +170,101 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
76
170
|
|
|
77
171
|
/**
|
|
78
172
|
* @private
|
|
79
|
-
* @type {
|
|
173
|
+
* @type {string}
|
|
80
174
|
*/
|
|
81
|
-
this.
|
|
175
|
+
this.renderedSourceKey_;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @private
|
|
179
|
+
* @type {number}
|
|
180
|
+
*/
|
|
181
|
+
this.renderedSourceRevision_;
|
|
82
182
|
|
|
83
183
|
/**
|
|
84
184
|
* @protected
|
|
85
185
|
* @type {import("../../extent.js").Extent}
|
|
86
186
|
*/
|
|
87
|
-
this.
|
|
187
|
+
this.tempExtent = createEmpty();
|
|
88
188
|
|
|
89
189
|
/**
|
|
90
190
|
* @private
|
|
91
191
|
* @type {import("../../TileRange.js").default}
|
|
92
192
|
*/
|
|
93
|
-
this.
|
|
193
|
+
this.tempTileRange_ = new TileRange(0, 0, 0, 0);
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @type {import("../../tilecoord.js").TileCoord}
|
|
197
|
+
* @private
|
|
198
|
+
*/
|
|
199
|
+
this.tempTileCoord_ = createTileCoord(0, 0, 0);
|
|
200
|
+
|
|
201
|
+
const cacheSize = options.cacheSize !== undefined ? options.cacheSize : 512;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @type {import("../../structs/LRUCache.js").default<import("../../Tile.js").default>}
|
|
205
|
+
* @private
|
|
206
|
+
*/
|
|
207
|
+
this.tileCache_ = new LRUCache(cacheSize);
|
|
208
|
+
|
|
209
|
+
this.maxStaleKeys = cacheSize * 0.5;
|
|
94
210
|
}
|
|
95
211
|
|
|
96
212
|
/**
|
|
97
|
-
* @
|
|
98
|
-
* @param {import("../../Tile.js").default} tile Tile.
|
|
99
|
-
* @return {boolean} Tile is drawable.
|
|
213
|
+
* @return {LRUCache} Tile cache.
|
|
100
214
|
*/
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const tileState = tile.getState();
|
|
104
|
-
const useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();
|
|
105
|
-
return (
|
|
106
|
-
tileState == TileState.LOADED ||
|
|
107
|
-
tileState == TileState.EMPTY ||
|
|
108
|
-
(tileState == TileState.ERROR && !useInterimTilesOnError)
|
|
109
|
-
);
|
|
215
|
+
getTileCache() {
|
|
216
|
+
return this.tileCache_;
|
|
110
217
|
}
|
|
111
218
|
|
|
112
219
|
/**
|
|
220
|
+
* Get a tile from the cache or create one if needed.
|
|
221
|
+
*
|
|
113
222
|
* @param {number} z Tile coordinate z.
|
|
114
223
|
* @param {number} x Tile coordinate x.
|
|
115
224
|
* @param {number} y Tile coordinate y.
|
|
116
225
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
117
|
-
* @return {
|
|
226
|
+
* @return {import("../../Tile.js").default|null} Tile (or null if outside source extent).
|
|
227
|
+
* @protected
|
|
118
228
|
*/
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
const projection = frameState.viewState.projection;
|
|
229
|
+
getOrCreateTile(z, x, y, frameState) {
|
|
230
|
+
const tileCache = this.tileCache_;
|
|
122
231
|
const tileLayer = this.getLayer();
|
|
123
232
|
const tileSource = tileLayer.getSource();
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
233
|
+
const cacheKey = getCacheKey(tileSource.getKey(), z, x, y);
|
|
234
|
+
|
|
235
|
+
/** @type {import("../../Tile.js").default} */
|
|
236
|
+
let tile;
|
|
237
|
+
|
|
238
|
+
if (tileCache.containsKey(cacheKey)) {
|
|
239
|
+
tile = tileCache.get(cacheKey);
|
|
240
|
+
} else {
|
|
241
|
+
tile = tileSource.getTile(
|
|
242
|
+
z,
|
|
243
|
+
x,
|
|
244
|
+
y,
|
|
245
|
+
frameState.pixelRatio,
|
|
246
|
+
frameState.viewState.projection,
|
|
247
|
+
);
|
|
248
|
+
if (!tile) {
|
|
249
|
+
return null;
|
|
129
250
|
}
|
|
251
|
+
tileCache.set(cacheKey, tile);
|
|
130
252
|
}
|
|
131
|
-
|
|
132
|
-
|
|
253
|
+
return tile;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @param {number} z Tile coordinate z.
|
|
258
|
+
* @param {number} x Tile coordinate x.
|
|
259
|
+
* @param {number} y Tile coordinate y.
|
|
260
|
+
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
261
|
+
* @return {import("../../Tile.js").default|null} Tile (or null if outside source extent).
|
|
262
|
+
* @protected
|
|
263
|
+
*/
|
|
264
|
+
getTile(z, x, y, frameState) {
|
|
265
|
+
const tile = this.getOrCreateTile(z, x, y, frameState);
|
|
266
|
+
if (!tile) {
|
|
267
|
+
return null;
|
|
133
268
|
}
|
|
134
269
|
return tile;
|
|
135
270
|
}
|
|
@@ -157,8 +292,6 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
157
292
|
}
|
|
158
293
|
}
|
|
159
294
|
|
|
160
|
-
const pixelRatio = frameState.pixelRatio;
|
|
161
|
-
const projection = frameState.viewState.projection;
|
|
162
295
|
const viewState = frameState.viewState;
|
|
163
296
|
const source = layer.getRenderSource();
|
|
164
297
|
const tileGrid = source.getTileGridForProjection(viewState.projection);
|
|
@@ -170,21 +303,8 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
170
303
|
--z
|
|
171
304
|
) {
|
|
172
305
|
const tileCoord = tileGrid.getTileCoordForCoordAndZ(coordinate, z);
|
|
173
|
-
const tile =
|
|
174
|
-
|
|
175
|
-
tileCoord[1],
|
|
176
|
-
tileCoord[2],
|
|
177
|
-
pixelRatio,
|
|
178
|
-
projection,
|
|
179
|
-
);
|
|
180
|
-
if (
|
|
181
|
-
!(tile instanceof ImageTile || tile instanceof ReprojTile) ||
|
|
182
|
-
(tile instanceof ReprojTile && tile.getState() === TileState.EMPTY)
|
|
183
|
-
) {
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (tile.getState() !== TileState.LOADED) {
|
|
306
|
+
const tile = this.getTile(z, tileCoord[1], tileCoord[2], frameState);
|
|
307
|
+
if (!tile || tile.getState() !== TileState.LOADED) {
|
|
188
308
|
continue;
|
|
189
309
|
}
|
|
190
310
|
|
|
@@ -192,6 +312,21 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
192
312
|
const tileSize = toSize(tileGrid.getTileSize(z));
|
|
193
313
|
const tileResolution = tileGrid.getResolution(z);
|
|
194
314
|
|
|
315
|
+
/**
|
|
316
|
+
* @type {import('../../DataTile.js').ImageLike}
|
|
317
|
+
*/
|
|
318
|
+
let image;
|
|
319
|
+
if (tile instanceof ImageTile) {
|
|
320
|
+
image = tile.getImage();
|
|
321
|
+
} else if (tile instanceof DataTile) {
|
|
322
|
+
image = asImageLike(tile.getData());
|
|
323
|
+
if (!image) {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
|
|
195
330
|
const col = Math.floor(
|
|
196
331
|
tilePixelRatio *
|
|
197
332
|
((coordinate[0] - tileOrigin[0]) / tileResolution -
|
|
@@ -208,47 +343,208 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
208
343
|
tilePixelRatio * source.getGutterForProjection(viewState.projection),
|
|
209
344
|
);
|
|
210
345
|
|
|
211
|
-
return this.getImageData(
|
|
346
|
+
return this.getImageData(image, col + gutter, row + gutter);
|
|
212
347
|
}
|
|
213
348
|
|
|
214
349
|
return null;
|
|
215
350
|
}
|
|
216
351
|
|
|
217
352
|
/**
|
|
218
|
-
*
|
|
219
|
-
* @param {
|
|
220
|
-
* @
|
|
221
|
-
* @return {boolean|void} If `false`, the tile will not be considered loaded.
|
|
353
|
+
* Determine whether render should be called.
|
|
354
|
+
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
355
|
+
* @return {boolean} Layer is ready to be rendered.
|
|
222
356
|
*/
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
357
|
+
prepareFrame(frameState) {
|
|
358
|
+
const source = this.getLayer().getSource();
|
|
359
|
+
if (!source) {
|
|
360
|
+
return false;
|
|
226
361
|
}
|
|
227
|
-
|
|
362
|
+
const sourceRevision = this.getLayer().getSource().getRevision();
|
|
363
|
+
if (!this.renderedRevision_) {
|
|
364
|
+
this.renderedRevision_ = sourceRevision;
|
|
365
|
+
} else if (this.renderedRevision_ !== sourceRevision) {
|
|
366
|
+
this.renderedRevision_ = sourceRevision;
|
|
367
|
+
if (this.renderedSourceKey_ === source.getKey()) {
|
|
368
|
+
this.tileCache_.clear();
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return true;
|
|
228
372
|
}
|
|
229
373
|
|
|
230
374
|
/**
|
|
231
|
-
* Determine whether render should be called.
|
|
232
375
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
233
|
-
* @
|
|
376
|
+
* @param {import("../../extent.js").Extent} extent The extent to be rendered.
|
|
377
|
+
* @param {number} initialZ The zoom level.
|
|
378
|
+
* @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
|
|
379
|
+
* @param {number} preload Number of additional levels to load.
|
|
234
380
|
*/
|
|
235
|
-
|
|
236
|
-
|
|
381
|
+
enqueueTiles(frameState, extent, initialZ, tilesByZ, preload) {
|
|
382
|
+
const viewState = frameState.viewState;
|
|
383
|
+
const tileLayer = this.getLayer();
|
|
384
|
+
const tileSource = tileLayer.getRenderSource();
|
|
385
|
+
const tileGrid = tileSource.getTileGridForProjection(viewState.projection);
|
|
386
|
+
|
|
387
|
+
const tileSourceKey = getUid(tileSource);
|
|
388
|
+
if (!(tileSourceKey in frameState.wantedTiles)) {
|
|
389
|
+
frameState.wantedTiles[tileSourceKey] = {};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const wantedTiles = frameState.wantedTiles[tileSourceKey];
|
|
393
|
+
|
|
394
|
+
const map = tileLayer.getMapInternal();
|
|
395
|
+
const minZ = Math.max(
|
|
396
|
+
initialZ - preload,
|
|
397
|
+
tileGrid.getMinZoom(),
|
|
398
|
+
tileGrid.getZForResolution(
|
|
399
|
+
Math.min(
|
|
400
|
+
tileLayer.getMaxResolution(),
|
|
401
|
+
map
|
|
402
|
+
? map
|
|
403
|
+
.getView()
|
|
404
|
+
.getResolutionForZoom(Math.max(tileLayer.getMinZoom(), 0))
|
|
405
|
+
: tileGrid.getResolution(0),
|
|
406
|
+
),
|
|
407
|
+
tileSource.zDirection,
|
|
408
|
+
),
|
|
409
|
+
);
|
|
410
|
+
for (let z = initialZ; z >= minZ; --z) {
|
|
411
|
+
const tileRange = tileGrid.getTileRangeForExtentAndZ(
|
|
412
|
+
extent,
|
|
413
|
+
z,
|
|
414
|
+
this.tempTileRange_,
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
const tileResolution = tileGrid.getResolution(z);
|
|
418
|
+
|
|
419
|
+
for (let x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
|
420
|
+
for (let y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
|
421
|
+
const tile = this.getTile(z, x, y, frameState);
|
|
422
|
+
if (!tile) {
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
const added = addTileToLookup(tilesByZ, tile, z);
|
|
426
|
+
if (!added) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const tileQueueKey = tile.getKey();
|
|
431
|
+
wantedTiles[tileQueueKey] = true;
|
|
432
|
+
|
|
433
|
+
if (tile.getState() === TileState.IDLE) {
|
|
434
|
+
if (!frameState.tileQueue.isKeyQueued(tileQueueKey)) {
|
|
435
|
+
const tileCoord = createTileCoord(z, x, y, this.tempTileCoord_);
|
|
436
|
+
frameState.tileQueue.enqueue([
|
|
437
|
+
tile,
|
|
438
|
+
tileSourceKey,
|
|
439
|
+
tileGrid.getTileCoordCenter(tileCoord),
|
|
440
|
+
tileResolution,
|
|
441
|
+
]);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Look for tiles covering the provided tile coordinate at an alternate
|
|
451
|
+
* zoom level. Loaded tiles will be added to the provided tile texture lookup.
|
|
452
|
+
* @param {import("../../tilecoord.js").TileCoord} tileCoord The target tile coordinate.
|
|
453
|
+
* @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
|
|
454
|
+
* @return {boolean} The tile coordinate is covered by loaded tiles at the alternate zoom level.
|
|
455
|
+
* @private
|
|
456
|
+
*/
|
|
457
|
+
findStaleTile_(tileCoord, tilesByZ) {
|
|
458
|
+
const tileCache = this.tileCache_;
|
|
459
|
+
const z = tileCoord[0];
|
|
460
|
+
const x = tileCoord[1];
|
|
461
|
+
const y = tileCoord[2];
|
|
462
|
+
const staleKeys = this.getStaleKeys();
|
|
463
|
+
for (let i = 0; i < staleKeys.length; ++i) {
|
|
464
|
+
const cacheKey = getCacheKey(staleKeys[i], z, x, y);
|
|
465
|
+
if (tileCache.containsKey(cacheKey)) {
|
|
466
|
+
const tile = tileCache.get(cacheKey);
|
|
467
|
+
if (tile.getState() === TileState.LOADED) {
|
|
468
|
+
tile.endTransition(getUid(this));
|
|
469
|
+
addTileToLookup(tilesByZ, tile, z);
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Look for tiles covering the provided tile coordinate at an alternate
|
|
479
|
+
* zoom level. Loaded tiles will be added to the provided tile texture lookup.
|
|
480
|
+
* @param {import("../../tilegrid/TileGrid.js").default} tileGrid The tile grid.
|
|
481
|
+
* @param {import("../../tilecoord.js").TileCoord} tileCoord The target tile coordinate.
|
|
482
|
+
* @param {number} altZ The alternate zoom level.
|
|
483
|
+
* @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
|
|
484
|
+
* @return {boolean} The tile coordinate is covered by loaded tiles at the alternate zoom level.
|
|
485
|
+
* @private
|
|
486
|
+
*/
|
|
487
|
+
findAltTiles_(tileGrid, tileCoord, altZ, tilesByZ) {
|
|
488
|
+
const tileRange = tileGrid.getTileRangeForTileCoordAndZ(
|
|
489
|
+
tileCoord,
|
|
490
|
+
altZ,
|
|
491
|
+
this.tempTileRange_,
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
if (!tileRange) {
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
let covered = true;
|
|
499
|
+
const tileCache = this.tileCache_;
|
|
500
|
+
const source = this.getLayer().getRenderSource();
|
|
501
|
+
const sourceKey = source.getKey();
|
|
502
|
+
for (let x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
|
503
|
+
for (let y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
|
504
|
+
const cacheKey = getCacheKey(sourceKey, altZ, x, y);
|
|
505
|
+
let loaded = false;
|
|
506
|
+
if (tileCache.containsKey(cacheKey)) {
|
|
507
|
+
const tile = tileCache.get(cacheKey);
|
|
508
|
+
if (tile.getState() === TileState.LOADED) {
|
|
509
|
+
addTileToLookup(tilesByZ, tile, altZ);
|
|
510
|
+
loaded = true;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if (!loaded) {
|
|
514
|
+
covered = false;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return covered;
|
|
237
519
|
}
|
|
238
520
|
|
|
239
521
|
/**
|
|
240
522
|
* Render the layer.
|
|
523
|
+
*
|
|
524
|
+
* The frame rendering logic has three parts:
|
|
525
|
+
*
|
|
526
|
+
* 1. Enqueue tiles
|
|
527
|
+
* 2. Find alt tiles for those that are not yet loaded
|
|
528
|
+
* 3. Render loaded tiles
|
|
529
|
+
*
|
|
241
530
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
242
531
|
* @param {HTMLElement} target Target that may be used to render content to.
|
|
243
532
|
* @return {HTMLElement} The rendered element.
|
|
244
533
|
*/
|
|
245
534
|
renderFrame(frameState, target) {
|
|
535
|
+
this.renderComplete = true;
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* TODO:
|
|
539
|
+
* * maybe skip transition when not fully opaque
|
|
540
|
+
* * decide if this.renderComplete is useful
|
|
541
|
+
*/
|
|
542
|
+
|
|
246
543
|
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
|
247
544
|
const viewState = frameState.viewState;
|
|
248
545
|
const projection = viewState.projection;
|
|
249
546
|
const viewResolution = viewState.resolution;
|
|
250
547
|
const viewCenter = viewState.center;
|
|
251
|
-
const rotation = viewState.rotation;
|
|
252
548
|
const pixelRatio = frameState.pixelRatio;
|
|
253
549
|
|
|
254
550
|
const tileLayer = this.getLayer();
|
|
@@ -258,8 +554,15 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
258
554
|
const z = tileGrid.getZForResolution(viewResolution, tileSource.zDirection);
|
|
259
555
|
const tileResolution = tileGrid.getResolution(z);
|
|
260
556
|
|
|
261
|
-
|
|
262
|
-
|
|
557
|
+
const sourceKey = tileSource.getKey();
|
|
558
|
+
if (!this.renderedSourceKey_) {
|
|
559
|
+
this.renderedSourceKey_ = sourceKey;
|
|
560
|
+
} else if (this.renderedSourceKey_ !== sourceKey) {
|
|
561
|
+
this.prependStaleKey(this.renderedSourceKey_);
|
|
562
|
+
this.renderedSourceKey_ = sourceKey;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
let frameExtent = frameState.extent;
|
|
263
566
|
const tilePixelRatio = tileSource.getTilePixelRatio(pixelRatio);
|
|
264
567
|
|
|
265
568
|
this.prepareContainer(frameState, target);
|
|
@@ -271,8 +574,8 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
271
574
|
const layerExtent =
|
|
272
575
|
layerState.extent && fromUserExtent(layerState.extent, projection);
|
|
273
576
|
if (layerExtent) {
|
|
274
|
-
|
|
275
|
-
|
|
577
|
+
frameExtent = getIntersection(
|
|
578
|
+
frameExtent,
|
|
276
579
|
fromUserExtent(layerState.extent, projection),
|
|
277
580
|
);
|
|
278
581
|
}
|
|
@@ -286,84 +589,107 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
286
589
|
viewCenter[1] + dy,
|
|
287
590
|
];
|
|
288
591
|
|
|
289
|
-
|
|
592
|
+
/**
|
|
593
|
+
* @type {TileLookup}
|
|
594
|
+
*/
|
|
595
|
+
const tilesByZ = {};
|
|
290
596
|
|
|
291
597
|
/**
|
|
292
|
-
*
|
|
598
|
+
* Part 1: Enqueue tiles
|
|
293
599
|
*/
|
|
294
|
-
const tilesToDrawByZ = {};
|
|
295
|
-
tilesToDrawByZ[z] = {};
|
|
296
600
|
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
601
|
+
const preload = tileLayer.getPreload();
|
|
602
|
+
if (frameState.nextExtent) {
|
|
603
|
+
const targetZ = tileGrid.getZForResolution(
|
|
604
|
+
viewState.nextResolution,
|
|
605
|
+
tileSource.zDirection,
|
|
606
|
+
);
|
|
607
|
+
const nextExtent = getRenderExtent(frameState, frameState.nextExtent);
|
|
608
|
+
this.enqueueTiles(frameState, nextExtent, targetZ, tilesByZ, preload);
|
|
609
|
+
}
|
|
302
610
|
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
611
|
+
const renderExtent = getRenderExtent(frameState, frameExtent);
|
|
612
|
+
this.enqueueTiles(frameState, renderExtent, z, tilesByZ, 0);
|
|
613
|
+
if (preload > 0) {
|
|
614
|
+
setTimeout(() => {
|
|
615
|
+
this.enqueueTiles(
|
|
616
|
+
frameState,
|
|
617
|
+
renderExtent,
|
|
618
|
+
z - 1,
|
|
619
|
+
tilesByZ,
|
|
620
|
+
preload - 1,
|
|
621
|
+
);
|
|
622
|
+
}, 0);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Part 2: Find alt tiles for those that are not yet loaded
|
|
627
|
+
*/
|
|
628
|
+
|
|
629
|
+
const uid = getUid(this);
|
|
630
|
+
const time = frameState.time;
|
|
631
|
+
|
|
632
|
+
// look for cached tiles to use if a target tile is not ready
|
|
633
|
+
for (const tile of tilesByZ[z]) {
|
|
634
|
+
const tileState = tile.getState();
|
|
635
|
+
if (
|
|
636
|
+
(tile instanceof ReprojTile || tile instanceof ReprojDataTile) &&
|
|
637
|
+
tileState === TileState.EMPTY
|
|
638
|
+
) {
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
const tileCoord = tile.tileCoord;
|
|
642
|
+
|
|
643
|
+
if (tileState === TileState.LOADED) {
|
|
644
|
+
const alpha = tile.getAlpha(uid, time);
|
|
645
|
+
if (alpha === 1) {
|
|
646
|
+
// no need to look for alt tiles
|
|
647
|
+
tile.endTransition(uid);
|
|
320
648
|
continue;
|
|
321
649
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const uid = getUid(this);
|
|
325
|
-
if (tile.getState() == TileState.LOADED) {
|
|
326
|
-
tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
|
|
327
|
-
let inTransition = tile.inTransition(uid);
|
|
328
|
-
if (inTransition && layerState.opacity !== 1) {
|
|
329
|
-
// Skipping transition when layer is not fully opaque avoids visual artifacts.
|
|
330
|
-
tile.endTransition(uid);
|
|
331
|
-
inTransition = false;
|
|
332
|
-
}
|
|
333
|
-
if (
|
|
334
|
-
!this.newTiles_ &&
|
|
335
|
-
(inTransition || !this.renderedTiles.includes(tile))
|
|
336
|
-
) {
|
|
337
|
-
this.newTiles_ = true;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
if (tile.getAlpha(uid, frameState.time) === 1) {
|
|
341
|
-
// don't look for alt tiles if alpha is 1
|
|
342
|
-
continue;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
650
|
+
}
|
|
651
|
+
this.renderComplete = false;
|
|
345
652
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
653
|
+
const hasStaleTile = this.findStaleTile_(tileCoord, tilesByZ);
|
|
654
|
+
if (hasStaleTile) {
|
|
655
|
+
// use the stale tile before the new tile's transition has completed
|
|
656
|
+
removeTileFromLookup(tilesByZ, tile, z);
|
|
657
|
+
frameState.animate = true;
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// first look for child tiles (at z + 1)
|
|
662
|
+
const coveredByChildren = this.findAltTiles_(
|
|
663
|
+
tileGrid,
|
|
664
|
+
tileCoord,
|
|
665
|
+
z + 1,
|
|
666
|
+
tilesByZ,
|
|
667
|
+
);
|
|
668
|
+
|
|
669
|
+
if (coveredByChildren) {
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// next look for parent tiles
|
|
674
|
+
const minZoom = tileGrid.getMinZoom();
|
|
675
|
+
for (let parentZ = z - 1; parentZ >= minZoom; --parentZ) {
|
|
676
|
+
const coveredByParent = this.findAltTiles_(
|
|
677
|
+
tileGrid,
|
|
678
|
+
tileCoord,
|
|
679
|
+
parentZ,
|
|
680
|
+
tilesByZ,
|
|
350
681
|
);
|
|
351
682
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
covered = findLoadedTiles(z + 1, childTileRange);
|
|
355
|
-
}
|
|
356
|
-
if (!covered) {
|
|
357
|
-
tileGrid.forEachTileCoordParentTileRange(
|
|
358
|
-
tile.tileCoord,
|
|
359
|
-
findLoadedTiles,
|
|
360
|
-
tmpTileRange,
|
|
361
|
-
tmpExtent,
|
|
362
|
-
);
|
|
683
|
+
if (coveredByParent) {
|
|
684
|
+
break;
|
|
363
685
|
}
|
|
364
686
|
}
|
|
365
687
|
}
|
|
366
688
|
|
|
689
|
+
/**
|
|
690
|
+
* Part 3: Render loaded tiles
|
|
691
|
+
*/
|
|
692
|
+
|
|
367
693
|
const canvasScale =
|
|
368
694
|
((tileResolution / viewResolution) * pixelRatio) / tilePixelRatio;
|
|
369
695
|
|
|
@@ -381,7 +707,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
381
707
|
-height / 2,
|
|
382
708
|
);
|
|
383
709
|
|
|
384
|
-
if (
|
|
710
|
+
if (layerState.extent) {
|
|
385
711
|
this.clipUnrotated(context, frameState, layerExtent);
|
|
386
712
|
}
|
|
387
713
|
|
|
@@ -393,20 +719,12 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
393
719
|
|
|
394
720
|
this.renderedTiles.length = 0;
|
|
395
721
|
/** @type {Array<number>} */
|
|
396
|
-
|
|
722
|
+
const zs = Object.keys(tilesByZ).map(Number);
|
|
397
723
|
zs.sort(ascending);
|
|
398
724
|
|
|
399
|
-
let
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
(!this.containerReused ||
|
|
403
|
-
tileSource.getOpaque(frameState.viewState.projection))
|
|
404
|
-
) {
|
|
405
|
-
zs = zs.reverse();
|
|
406
|
-
} else {
|
|
407
|
-
clips = [];
|
|
408
|
-
clipZs = [];
|
|
409
|
-
}
|
|
725
|
+
let currentClip;
|
|
726
|
+
const clips = [];
|
|
727
|
+
const clipZs = [];
|
|
410
728
|
for (let i = zs.length - 1; i >= 0; --i) {
|
|
411
729
|
const currentZ = zs[i];
|
|
412
730
|
const currentTilePixelSize = tileSource.getTilePixelSize(
|
|
@@ -431,11 +749,10 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
431
749
|
]);
|
|
432
750
|
const tileGutter =
|
|
433
751
|
tilePixelRatio * tileSource.getGutterForProjection(projection);
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
);
|
|
752
|
+
for (const tile of tilesByZ[currentZ]) {
|
|
753
|
+
if (tile.getState() !== TileState.LOADED) {
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
439
756
|
const tileCoord = tile.tileCoord;
|
|
440
757
|
|
|
441
758
|
// Calculate integer positions and sizes so that tiles align
|
|
@@ -447,67 +764,50 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
447
764
|
const y = Math.round(origin[1] - yIndex * dy);
|
|
448
765
|
const w = nextX - x;
|
|
449
766
|
const h = nextY - y;
|
|
450
|
-
const transition =
|
|
767
|
+
const transition = zs.length === 1;
|
|
451
768
|
|
|
452
|
-
const inTransition =
|
|
453
|
-
transition && tile.getAlpha(getUid(this), frameState.time) !== 1;
|
|
454
769
|
let contextSaved = false;
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
contextSaved = true;
|
|
471
|
-
}
|
|
472
|
-
context.beginPath();
|
|
473
|
-
// counter-clockwise (outer ring) for current tile
|
|
474
|
-
context.moveTo(currentClip[0], currentClip[1]);
|
|
475
|
-
context.lineTo(currentClip[2], currentClip[3]);
|
|
476
|
-
context.lineTo(currentClip[4], currentClip[5]);
|
|
477
|
-
context.lineTo(currentClip[6], currentClip[7]);
|
|
478
|
-
// clockwise (inner ring) for higher z tile
|
|
479
|
-
context.moveTo(clip[6], clip[7]);
|
|
480
|
-
context.lineTo(clip[4], clip[5]);
|
|
481
|
-
context.lineTo(clip[2], clip[3]);
|
|
482
|
-
context.lineTo(clip[0], clip[1]);
|
|
483
|
-
context.clip();
|
|
484
|
-
}
|
|
770
|
+
|
|
771
|
+
// Clip mask for regions in this tile that already filled by a higher z tile
|
|
772
|
+
currentClip = [x, y, x + w, y, x + w, y + h, x, y + h];
|
|
773
|
+
for (let i = 0, ii = clips.length; i < ii; ++i) {
|
|
774
|
+
if (!transition && currentZ < clipZs[i]) {
|
|
775
|
+
const clip = clips[i];
|
|
776
|
+
if (
|
|
777
|
+
intersects(
|
|
778
|
+
[x, y, x + w, y + h],
|
|
779
|
+
[clip[0], clip[3], clip[4], clip[7]],
|
|
780
|
+
)
|
|
781
|
+
) {
|
|
782
|
+
if (!contextSaved) {
|
|
783
|
+
context.save();
|
|
784
|
+
contextSaved = true;
|
|
485
785
|
}
|
|
786
|
+
context.beginPath();
|
|
787
|
+
// counter-clockwise (outer ring) for current tile
|
|
788
|
+
context.moveTo(currentClip[0], currentClip[1]);
|
|
789
|
+
context.lineTo(currentClip[2], currentClip[3]);
|
|
790
|
+
context.lineTo(currentClip[4], currentClip[5]);
|
|
791
|
+
context.lineTo(currentClip[6], currentClip[7]);
|
|
792
|
+
// clockwise (inner ring) for higher z tile
|
|
793
|
+
context.moveTo(clip[6], clip[7]);
|
|
794
|
+
context.lineTo(clip[4], clip[5]);
|
|
795
|
+
context.lineTo(clip[2], clip[3]);
|
|
796
|
+
context.lineTo(clip[0], clip[1]);
|
|
797
|
+
context.clip();
|
|
486
798
|
}
|
|
487
|
-
clips.push(currentClip);
|
|
488
|
-
clipZs.push(currentZ);
|
|
489
|
-
} else {
|
|
490
|
-
context.clearRect(x, y, w, h);
|
|
491
799
|
}
|
|
492
800
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
h,
|
|
500
|
-
tileGutter,
|
|
501
|
-
transition,
|
|
502
|
-
);
|
|
503
|
-
if (clips && !inTransition) {
|
|
504
|
-
if (contextSaved) {
|
|
505
|
-
context.restore();
|
|
506
|
-
}
|
|
507
|
-
this.renderedTiles.unshift(tile);
|
|
508
|
-
} else {
|
|
509
|
-
this.renderedTiles.push(tile);
|
|
801
|
+
clips.push(currentClip);
|
|
802
|
+
clipZs.push(currentZ);
|
|
803
|
+
|
|
804
|
+
this.drawTile(tile, frameState, x, y, w, h, tileGutter, transition);
|
|
805
|
+
if (contextSaved) {
|
|
806
|
+
context.restore();
|
|
510
807
|
}
|
|
808
|
+
this.renderedTiles.unshift(tile);
|
|
809
|
+
|
|
810
|
+
// TODO: decide if this is necessary
|
|
511
811
|
this.updateUsedTiles(frameState.usedTiles, tileSource, tile);
|
|
512
812
|
}
|
|
513
813
|
}
|
|
@@ -520,18 +820,6 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
520
820
|
this.renderedPixelRatio = pixelRatio;
|
|
521
821
|
this.renderedProjection = projection;
|
|
522
822
|
|
|
523
|
-
this.manageTilePyramid(
|
|
524
|
-
frameState,
|
|
525
|
-
tileSource,
|
|
526
|
-
tileGrid,
|
|
527
|
-
pixelRatio,
|
|
528
|
-
projection,
|
|
529
|
-
extent,
|
|
530
|
-
z,
|
|
531
|
-
tileLayer.getPreload(),
|
|
532
|
-
);
|
|
533
|
-
this.scheduleExpireCache(frameState, tileSource);
|
|
534
|
-
|
|
535
823
|
this.postRender(this.context, frameState);
|
|
536
824
|
|
|
537
825
|
if (layerState.extent) {
|
|
@@ -539,11 +827,39 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
539
827
|
}
|
|
540
828
|
context.imageSmoothingEnabled = true;
|
|
541
829
|
|
|
830
|
+
// TODO: let the renderers manage their own cache instead of managing the source cache
|
|
831
|
+
/**
|
|
832
|
+
* Here we unconditionally expire the source cache since the renderer maintains
|
|
833
|
+
* its own cache.
|
|
834
|
+
* @param {import("../../Map.js").default} map Map.
|
|
835
|
+
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
836
|
+
*/
|
|
837
|
+
const postRenderFunction = (map, frameState) => {
|
|
838
|
+
const tileSourceKey = getUid(tileSource);
|
|
839
|
+
const wantedTiles = frameState.wantedTiles[tileSourceKey];
|
|
840
|
+
const tilesCount = wantedTiles ? Object.keys(wantedTiles).length : 0;
|
|
841
|
+
this.updateCacheSize(tilesCount);
|
|
842
|
+
this.tileCache_.expireCache();
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
frameState.postRenderFunctions.push(postRenderFunction);
|
|
846
|
+
|
|
542
847
|
return this.container;
|
|
543
848
|
}
|
|
544
849
|
|
|
545
850
|
/**
|
|
546
|
-
*
|
|
851
|
+
* Increases the cache size if needed
|
|
852
|
+
* @param {number} tileCount Minimum number of tiles needed.
|
|
853
|
+
*/
|
|
854
|
+
updateCacheSize(tileCount) {
|
|
855
|
+
this.tileCache_.highWaterMark = Math.max(
|
|
856
|
+
this.tileCache_.highWaterMark,
|
|
857
|
+
tileCount * 2,
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* @param {import("../../Tile.js").default} tile Tile.
|
|
547
863
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
548
864
|
* @param {number} x Left of the tile.
|
|
549
865
|
* @param {number} y Top of the tile.
|
|
@@ -551,9 +867,20 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
551
867
|
* @param {number} h Height of the tile.
|
|
552
868
|
* @param {number} gutter Tile gutter.
|
|
553
869
|
* @param {boolean} transition Apply an alpha transition.
|
|
870
|
+
* @protected
|
|
554
871
|
*/
|
|
555
|
-
|
|
556
|
-
|
|
872
|
+
drawTile(tile, frameState, x, y, w, h, gutter, transition) {
|
|
873
|
+
let image;
|
|
874
|
+
if (tile instanceof DataTile) {
|
|
875
|
+
image = asImageLike(tile.getData());
|
|
876
|
+
if (!image) {
|
|
877
|
+
throw new Error('Rendering array data is not yet supported');
|
|
878
|
+
}
|
|
879
|
+
} else {
|
|
880
|
+
image = this.getTileImage(
|
|
881
|
+
/** @type {import("../../ImageTile.js").default} */ (tile),
|
|
882
|
+
);
|
|
883
|
+
}
|
|
557
884
|
if (!image) {
|
|
558
885
|
return;
|
|
559
886
|
}
|
|
@@ -608,36 +935,6 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
608
935
|
return tile.getImage();
|
|
609
936
|
}
|
|
610
937
|
|
|
611
|
-
/**
|
|
612
|
-
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
613
|
-
* @param {import("../../source/Tile.js").default} tileSource Tile source.
|
|
614
|
-
* @protected
|
|
615
|
-
*/
|
|
616
|
-
scheduleExpireCache(frameState, tileSource) {
|
|
617
|
-
if (tileSource.canExpireCache()) {
|
|
618
|
-
/**
|
|
619
|
-
* @param {import("../../source/Tile.js").default} tileSource Tile source.
|
|
620
|
-
* @param {import("../../Map.js").default} map Map.
|
|
621
|
-
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
622
|
-
*/
|
|
623
|
-
const postRenderFunction = function (tileSource, map, frameState) {
|
|
624
|
-
const tileSourceKey = getUid(tileSource);
|
|
625
|
-
if (tileSourceKey in frameState.usedTiles) {
|
|
626
|
-
tileSource.expireCache(
|
|
627
|
-
frameState.viewState.projection,
|
|
628
|
-
frameState.usedTiles[tileSourceKey],
|
|
629
|
-
);
|
|
630
|
-
}
|
|
631
|
-
}.bind(null, tileSource);
|
|
632
|
-
|
|
633
|
-
frameState.postRenderFunctions.push(
|
|
634
|
-
/** @type {import("../../Map.js").PostRenderFunction} */ (
|
|
635
|
-
postRenderFunction
|
|
636
|
-
),
|
|
637
|
-
);
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
|
|
641
938
|
/**
|
|
642
939
|
* @param {!Object<string, !Object<string, boolean>>} usedTiles Used tiles.
|
|
643
940
|
* @param {import("../../source/Tile.js").default} tileSource Tile source.
|
|
@@ -652,90 +949,6 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
|
|
652
949
|
}
|
|
653
950
|
usedTiles[tileSourceKey][tile.getKey()] = true;
|
|
654
951
|
}
|
|
655
|
-
|
|
656
|
-
/**
|
|
657
|
-
* Manage tile pyramid.
|
|
658
|
-
* This function performs a number of functions related to the tiles at the
|
|
659
|
-
* current zoom and lower zoom levels:
|
|
660
|
-
* - registers idle tiles in frameState.wantedTiles so that they are not
|
|
661
|
-
* discarded by the tile queue
|
|
662
|
-
* - enqueues missing tiles
|
|
663
|
-
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
664
|
-
* @param {import("../../source/Tile.js").default} tileSource Tile source.
|
|
665
|
-
* @param {import("../../tilegrid/TileGrid.js").default} tileGrid Tile grid.
|
|
666
|
-
* @param {number} pixelRatio Pixel ratio.
|
|
667
|
-
* @param {import("../../proj/Projection.js").default} projection Projection.
|
|
668
|
-
* @param {import("../../extent.js").Extent} extent Extent.
|
|
669
|
-
* @param {number} currentZ Current Z.
|
|
670
|
-
* @param {number} preload Load low resolution tiles up to `preload` levels.
|
|
671
|
-
* @param {function(import("../../Tile.js").default):void} [tileCallback] Tile callback.
|
|
672
|
-
* @protected
|
|
673
|
-
*/
|
|
674
|
-
manageTilePyramid(
|
|
675
|
-
frameState,
|
|
676
|
-
tileSource,
|
|
677
|
-
tileGrid,
|
|
678
|
-
pixelRatio,
|
|
679
|
-
projection,
|
|
680
|
-
extent,
|
|
681
|
-
currentZ,
|
|
682
|
-
preload,
|
|
683
|
-
tileCallback,
|
|
684
|
-
) {
|
|
685
|
-
const tileSourceKey = getUid(tileSource);
|
|
686
|
-
if (!(tileSourceKey in frameState.wantedTiles)) {
|
|
687
|
-
frameState.wantedTiles[tileSourceKey] = {};
|
|
688
|
-
}
|
|
689
|
-
const wantedTiles = frameState.wantedTiles[tileSourceKey];
|
|
690
|
-
const tileQueue = frameState.tileQueue;
|
|
691
|
-
const minZoom = tileGrid.getMinZoom();
|
|
692
|
-
const rotation = frameState.viewState.rotation;
|
|
693
|
-
const viewport = rotation
|
|
694
|
-
? getRotatedViewport(
|
|
695
|
-
frameState.viewState.center,
|
|
696
|
-
frameState.viewState.resolution,
|
|
697
|
-
rotation,
|
|
698
|
-
frameState.size,
|
|
699
|
-
)
|
|
700
|
-
: undefined;
|
|
701
|
-
let tileCount = 0;
|
|
702
|
-
let tile, tileRange, tileResolution, x, y, z;
|
|
703
|
-
for (z = minZoom; z <= currentZ; ++z) {
|
|
704
|
-
tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z, tileRange);
|
|
705
|
-
tileResolution = tileGrid.getResolution(z);
|
|
706
|
-
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
|
707
|
-
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
|
708
|
-
if (
|
|
709
|
-
rotation &&
|
|
710
|
-
!tileGrid.tileCoordIntersectsViewport([z, x, y], viewport)
|
|
711
|
-
) {
|
|
712
|
-
continue;
|
|
713
|
-
}
|
|
714
|
-
if (currentZ - z <= preload) {
|
|
715
|
-
++tileCount;
|
|
716
|
-
tile = tileSource.getTile(z, x, y, pixelRatio, projection);
|
|
717
|
-
if (tile.getState() == TileState.IDLE) {
|
|
718
|
-
wantedTiles[tile.getKey()] = true;
|
|
719
|
-
if (!tileQueue.isKeyQueued(tile.getKey())) {
|
|
720
|
-
tileQueue.enqueue([
|
|
721
|
-
tile,
|
|
722
|
-
tileSourceKey,
|
|
723
|
-
tileGrid.getTileCoordCenter(tile.tileCoord),
|
|
724
|
-
tileResolution,
|
|
725
|
-
]);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
if (tileCallback !== undefined) {
|
|
729
|
-
tileCallback(tile);
|
|
730
|
-
}
|
|
731
|
-
} else {
|
|
732
|
-
tileSource.useTile(z, x, y, projection);
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
tileSource.updateCacheSize(tileCount, projection);
|
|
738
|
-
}
|
|
739
952
|
}
|
|
740
953
|
|
|
741
954
|
export default CanvasTileLayerRenderer;
|