1254 lines
37 KiB
JavaScript
1254 lines
37 KiB
JavaScript
import {
|
|
Layer_default2 as Layer_default
|
|
} from "./chunk-ZUI5NXIU.js";
|
|
import {
|
|
Layer_default as Layer_default2
|
|
} from "./chunk-I6K7MRGV.js";
|
|
import {
|
|
ImageTile_default,
|
|
TileRange_default,
|
|
Tile_default,
|
|
Tile_default2,
|
|
createOrUpdate2 as createOrUpdate,
|
|
getCacheKey
|
|
} from "./chunk-7XMWB3J4.js";
|
|
import {
|
|
TileState_default
|
|
} from "./chunk-5D2XPBR2.js";
|
|
import {
|
|
toSize
|
|
} from "./chunk-SHUBVYN4.js";
|
|
import {
|
|
apply,
|
|
compose
|
|
} from "./chunk-X52LGBOS.js";
|
|
import {
|
|
assert
|
|
} from "./chunk-QFCIXVZ3.js";
|
|
import {
|
|
equivalent,
|
|
fromUserExtent
|
|
} from "./chunk-A3RXLHYB.js";
|
|
import {
|
|
createCanvasContext2D
|
|
} from "./chunk-UPTVWZ45.js";
|
|
import {
|
|
getUid
|
|
} from "./chunk-Q5ZULJHM.js";
|
|
import {
|
|
Disposable_default
|
|
} from "./chunk-NGFXCWUF.js";
|
|
import {
|
|
ascending
|
|
} from "./chunk-K25ZO44T.js";
|
|
import {
|
|
containsCoordinate,
|
|
createEmpty,
|
|
equals,
|
|
getIntersection,
|
|
getRotatedViewport,
|
|
getTopLeft,
|
|
intersects
|
|
} from "./chunk-SRXHWJOY.js";
|
|
|
|
// node_modules/ol/DataTile.js
|
|
function asImageLike(data) {
|
|
return data instanceof Image || data instanceof HTMLCanvasElement || data instanceof HTMLVideoElement || data instanceof ImageBitmap ? data : null;
|
|
}
|
|
function asArrayLike(data) {
|
|
return data instanceof Uint8Array || data instanceof Uint8ClampedArray || data instanceof Float32Array || data instanceof DataView ? data : null;
|
|
}
|
|
var disposedError = new Error("disposed");
|
|
var sharedContext = null;
|
|
function toArray(image) {
|
|
if (!sharedContext) {
|
|
sharedContext = createCanvasContext2D(
|
|
image.width,
|
|
image.height,
|
|
void 0,
|
|
{ willReadFrequently: true }
|
|
);
|
|
}
|
|
const canvas = sharedContext.canvas;
|
|
const width = image.width;
|
|
if (canvas.width !== width) {
|
|
canvas.width = width;
|
|
}
|
|
const height = image.height;
|
|
if (canvas.height !== height) {
|
|
canvas.height = height;
|
|
}
|
|
sharedContext.clearRect(0, 0, width, height);
|
|
sharedContext.drawImage(image, 0, 0);
|
|
return sharedContext.getImageData(0, 0, width, height).data;
|
|
}
|
|
var defaultSize = [256, 256];
|
|
var DataTile = class extends Tile_default {
|
|
/**
|
|
* @param {Options} options Tile options.
|
|
*/
|
|
constructor(options) {
|
|
const state = TileState_default.IDLE;
|
|
super(options.tileCoord, state, {
|
|
transition: options.transition,
|
|
interpolate: options.interpolate
|
|
});
|
|
this.loader_ = options.loader;
|
|
this.data_ = null;
|
|
this.error_ = null;
|
|
this.size_ = options.size || null;
|
|
this.controller_ = options.controller || null;
|
|
}
|
|
/**
|
|
* Get the tile size.
|
|
* @return {import('./size.js').Size} Tile size.
|
|
*/
|
|
getSize() {
|
|
if (this.size_) {
|
|
return this.size_;
|
|
}
|
|
const imageData = asImageLike(this.data_);
|
|
if (imageData) {
|
|
return [imageData.width, imageData.height];
|
|
}
|
|
return defaultSize;
|
|
}
|
|
/**
|
|
* Get the data for the tile.
|
|
* @return {Data} Tile data.
|
|
* @api
|
|
*/
|
|
getData() {
|
|
return this.data_;
|
|
}
|
|
/**
|
|
* Get any loading error.
|
|
* @return {Error} Loading error.
|
|
* @api
|
|
*/
|
|
getError() {
|
|
return this.error_;
|
|
}
|
|
/**
|
|
* Load the tile data.
|
|
* @api
|
|
* @override
|
|
*/
|
|
load() {
|
|
if (this.state !== TileState_default.IDLE && this.state !== TileState_default.ERROR) {
|
|
return;
|
|
}
|
|
this.state = TileState_default.LOADING;
|
|
this.changed();
|
|
const self = this;
|
|
this.loader_().then(function(data) {
|
|
self.data_ = data;
|
|
self.state = TileState_default.LOADED;
|
|
self.changed();
|
|
}).catch(function(error) {
|
|
self.error_ = error;
|
|
self.state = TileState_default.ERROR;
|
|
self.changed();
|
|
});
|
|
}
|
|
/**
|
|
* Clean up.
|
|
* @override
|
|
*/
|
|
disposeInternal() {
|
|
if (this.controller_) {
|
|
this.controller_.abort(disposedError);
|
|
this.controller_ = null;
|
|
}
|
|
super.disposeInternal();
|
|
}
|
|
};
|
|
var DataTile_default = DataTile;
|
|
|
|
// node_modules/ol/structs/LRUCache.js
|
|
var LRUCache = class {
|
|
/**
|
|
* @param {number} [highWaterMark] High water mark.
|
|
*/
|
|
constructor(highWaterMark) {
|
|
this.highWaterMark = highWaterMark !== void 0 ? highWaterMark : 2048;
|
|
this.count_ = 0;
|
|
this.entries_ = {};
|
|
this.oldest_ = null;
|
|
this.newest_ = null;
|
|
}
|
|
deleteOldest() {
|
|
const entry = this.pop();
|
|
if (entry instanceof Disposable_default) {
|
|
entry.dispose();
|
|
}
|
|
}
|
|
/**
|
|
* @return {boolean} Can expire cache.
|
|
*/
|
|
canExpireCache() {
|
|
return this.highWaterMark > 0 && this.getCount() > this.highWaterMark;
|
|
}
|
|
/**
|
|
* Expire the cache. When the cache entry is a {@link module:ol/Disposable~Disposable},
|
|
* the entry will be disposed.
|
|
* @param {!Object<string, boolean>} [keep] Keys to keep. To be implemented by subclasses.
|
|
*/
|
|
expireCache(keep) {
|
|
while (this.canExpireCache()) {
|
|
this.deleteOldest();
|
|
}
|
|
}
|
|
/**
|
|
* FIXME empty description for jsdoc
|
|
*/
|
|
clear() {
|
|
while (this.oldest_) {
|
|
this.deleteOldest();
|
|
}
|
|
}
|
|
/**
|
|
* @param {string} key Key.
|
|
* @return {boolean} Contains key.
|
|
*/
|
|
containsKey(key) {
|
|
return this.entries_.hasOwnProperty(key);
|
|
}
|
|
/**
|
|
* @param {function(T, string, LRUCache<T>): ?} f The function
|
|
* to call for every entry from the oldest to the newer. This function takes
|
|
* 3 arguments (the entry value, the entry key and the LRUCache object).
|
|
* The return value is ignored.
|
|
*/
|
|
forEach(f) {
|
|
let entry = this.oldest_;
|
|
while (entry) {
|
|
f(entry.value_, entry.key_, this);
|
|
entry = entry.newer;
|
|
}
|
|
}
|
|
/**
|
|
* @param {string} key Key.
|
|
* @param {*} [options] Options (reserved for subclasses).
|
|
* @return {T} Value.
|
|
*/
|
|
get(key, options) {
|
|
const entry = this.entries_[key];
|
|
assert(
|
|
entry !== void 0,
|
|
"Tried to get a value for a key that does not exist in the cache"
|
|
);
|
|
if (entry === this.newest_) {
|
|
return entry.value_;
|
|
}
|
|
if (entry === this.oldest_) {
|
|
this.oldest_ = /** @type {Entry} */
|
|
this.oldest_.newer;
|
|
this.oldest_.older = null;
|
|
} else {
|
|
entry.newer.older = entry.older;
|
|
entry.older.newer = entry.newer;
|
|
}
|
|
entry.newer = null;
|
|
entry.older = this.newest_;
|
|
this.newest_.newer = entry;
|
|
this.newest_ = entry;
|
|
return entry.value_;
|
|
}
|
|
/**
|
|
* Remove an entry from the cache.
|
|
* @param {string} key The entry key.
|
|
* @return {T} The removed entry.
|
|
*/
|
|
remove(key) {
|
|
const entry = this.entries_[key];
|
|
assert(
|
|
entry !== void 0,
|
|
"Tried to get a value for a key that does not exist in the cache"
|
|
);
|
|
if (entry === this.newest_) {
|
|
this.newest_ = /** @type {Entry} */
|
|
entry.older;
|
|
if (this.newest_) {
|
|
this.newest_.newer = null;
|
|
}
|
|
} else if (entry === this.oldest_) {
|
|
this.oldest_ = /** @type {Entry} */
|
|
entry.newer;
|
|
if (this.oldest_) {
|
|
this.oldest_.older = null;
|
|
}
|
|
} else {
|
|
entry.newer.older = entry.older;
|
|
entry.older.newer = entry.newer;
|
|
}
|
|
delete this.entries_[key];
|
|
--this.count_;
|
|
return entry.value_;
|
|
}
|
|
/**
|
|
* @return {number} Count.
|
|
*/
|
|
getCount() {
|
|
return this.count_;
|
|
}
|
|
/**
|
|
* @return {Array<string>} Keys.
|
|
*/
|
|
getKeys() {
|
|
const keys = new Array(this.count_);
|
|
let i = 0;
|
|
let entry;
|
|
for (entry = this.newest_; entry; entry = entry.older) {
|
|
keys[i++] = entry.key_;
|
|
}
|
|
return keys;
|
|
}
|
|
/**
|
|
* @return {Array<T>} Values.
|
|
*/
|
|
getValues() {
|
|
const values = new Array(this.count_);
|
|
let i = 0;
|
|
let entry;
|
|
for (entry = this.newest_; entry; entry = entry.older) {
|
|
values[i++] = entry.value_;
|
|
}
|
|
return values;
|
|
}
|
|
/**
|
|
* @return {T} Last value.
|
|
*/
|
|
peekLast() {
|
|
return this.oldest_.value_;
|
|
}
|
|
/**
|
|
* @return {string} Last key.
|
|
*/
|
|
peekLastKey() {
|
|
return this.oldest_.key_;
|
|
}
|
|
/**
|
|
* Get the key of the newest item in the cache. Throws if the cache is empty.
|
|
* @return {string} The newest key.
|
|
*/
|
|
peekFirstKey() {
|
|
return this.newest_.key_;
|
|
}
|
|
/**
|
|
* Return an entry without updating least recently used time.
|
|
* @param {string} key Key.
|
|
* @return {T|undefined} Value.
|
|
*/
|
|
peek(key) {
|
|
var _a;
|
|
return (_a = this.entries_[key]) == null ? void 0 : _a.value_;
|
|
}
|
|
/**
|
|
* @return {T} value Value.
|
|
*/
|
|
pop() {
|
|
const entry = this.oldest_;
|
|
delete this.entries_[entry.key_];
|
|
if (entry.newer) {
|
|
entry.newer.older = null;
|
|
}
|
|
this.oldest_ = /** @type {Entry} */
|
|
entry.newer;
|
|
if (!this.oldest_) {
|
|
this.newest_ = null;
|
|
}
|
|
--this.count_;
|
|
return entry.value_;
|
|
}
|
|
/**
|
|
* @param {string} key Key.
|
|
* @param {T} value Value.
|
|
*/
|
|
replace(key, value) {
|
|
this.get(key);
|
|
this.entries_[key].value_ = value;
|
|
}
|
|
/**
|
|
* @param {string} key Key.
|
|
* @param {T} value Value.
|
|
*/
|
|
set(key, value) {
|
|
assert(
|
|
!(key in this.entries_),
|
|
"Tried to set a value for a key that is used already"
|
|
);
|
|
const entry = {
|
|
key_: key,
|
|
newer: null,
|
|
older: this.newest_,
|
|
value_: value
|
|
};
|
|
if (!this.newest_) {
|
|
this.oldest_ = entry;
|
|
} else {
|
|
this.newest_.newer = entry;
|
|
}
|
|
this.newest_ = entry;
|
|
this.entries_[key] = entry;
|
|
++this.count_;
|
|
}
|
|
/**
|
|
* Set a maximum number of entries for the cache.
|
|
* @param {number} size Cache size.
|
|
* @api
|
|
*/
|
|
setSize(size) {
|
|
this.highWaterMark = size;
|
|
}
|
|
};
|
|
var LRUCache_default = LRUCache;
|
|
|
|
// node_modules/ol/renderer/canvas/TileLayer.js
|
|
function addTileToLookup(tilesByZ, tile, z) {
|
|
if (!(z in tilesByZ)) {
|
|
tilesByZ[z] = /* @__PURE__ */ new Set([tile]);
|
|
return true;
|
|
}
|
|
const set = tilesByZ[z];
|
|
const existing = set.has(tile);
|
|
if (!existing) {
|
|
set.add(tile);
|
|
}
|
|
return !existing;
|
|
}
|
|
function removeTileFromLookup(tilesByZ, tile, z) {
|
|
const set = tilesByZ[z];
|
|
if (set) {
|
|
return set.delete(tile);
|
|
}
|
|
return false;
|
|
}
|
|
function getRenderExtent(frameState, extent) {
|
|
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
|
if (layerState.extent) {
|
|
extent = getIntersection(
|
|
extent,
|
|
fromUserExtent(layerState.extent, frameState.viewState.projection)
|
|
);
|
|
}
|
|
const source = (
|
|
/** @type {import("../../source/Tile.js").default} */
|
|
layerState.layer.getRenderSource()
|
|
);
|
|
if (!source.getWrapX()) {
|
|
const gridExtent = source.getTileGridForProjection(frameState.viewState.projection).getExtent();
|
|
if (gridExtent) {
|
|
extent = getIntersection(extent, gridExtent);
|
|
}
|
|
}
|
|
return extent;
|
|
}
|
|
var CanvasTileLayerRenderer = class extends Layer_default {
|
|
/**
|
|
* @param {LayerType} tileLayer Tile layer.
|
|
* @param {Options} [options] Options.
|
|
*/
|
|
constructor(tileLayer, options) {
|
|
super(tileLayer);
|
|
options = options || {};
|
|
this.extentChanged = true;
|
|
this.renderComplete = false;
|
|
this.renderedExtent_ = null;
|
|
this.renderedPixelRatio;
|
|
this.renderedProjection = null;
|
|
this.renderedTiles = [];
|
|
this.renderedSourceKey_;
|
|
this.renderedSourceRevision_;
|
|
this.tempExtent = createEmpty();
|
|
this.tempTileRange_ = new TileRange_default(0, 0, 0, 0);
|
|
this.tempTileCoord_ = createOrUpdate(0, 0, 0);
|
|
const cacheSize = options.cacheSize !== void 0 ? options.cacheSize : 512;
|
|
this.tileCache_ = new LRUCache_default(cacheSize);
|
|
this.sourceTileCache_ = null;
|
|
this.maxStaleKeys = cacheSize * 0.5;
|
|
}
|
|
/**
|
|
* @return {LRUCache} Tile cache.
|
|
*/
|
|
getTileCache() {
|
|
return this.tileCache_;
|
|
}
|
|
/**
|
|
* @return {LRUCache} Tile cache.
|
|
*/
|
|
getSourceTileCache() {
|
|
if (!this.sourceTileCache_) {
|
|
this.sourceTileCache_ = new LRUCache_default(512);
|
|
}
|
|
return this.sourceTileCache_;
|
|
}
|
|
/**
|
|
* Get a tile from the cache or create one if needed.
|
|
*
|
|
* @param {number} z Tile coordinate z.
|
|
* @param {number} x Tile coordinate x.
|
|
* @param {number} y Tile coordinate y.
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
* @return {import("../../Tile.js").default|null} Tile (or null if outside source extent).
|
|
* @protected
|
|
*/
|
|
getOrCreateTile(z, x, y, frameState) {
|
|
const tileCache = this.tileCache_;
|
|
const tileLayer = this.getLayer();
|
|
const tileSource = tileLayer.getSource();
|
|
const cacheKey = getCacheKey(tileSource, tileSource.getKey(), z, x, y);
|
|
let tile;
|
|
if (tileCache.containsKey(cacheKey)) {
|
|
tile = tileCache.get(cacheKey);
|
|
} else {
|
|
const projection = frameState.viewState.projection;
|
|
const sourceProjection = tileSource.getProjection();
|
|
tile = tileSource.getTile(
|
|
z,
|
|
x,
|
|
y,
|
|
frameState.pixelRatio,
|
|
projection,
|
|
!sourceProjection || equivalent(sourceProjection, projection) ? void 0 : this.getSourceTileCache()
|
|
);
|
|
if (!tile) {
|
|
return null;
|
|
}
|
|
tileCache.set(cacheKey, tile);
|
|
}
|
|
return tile;
|
|
}
|
|
/**
|
|
* @param {number} z Tile coordinate z.
|
|
* @param {number} x Tile coordinate x.
|
|
* @param {number} y Tile coordinate y.
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
* @return {import("../../Tile.js").default|null} Tile (or null if outside source extent).
|
|
* @protected
|
|
*/
|
|
getTile(z, x, y, frameState) {
|
|
const tile = this.getOrCreateTile(z, x, y, frameState);
|
|
if (!tile) {
|
|
return null;
|
|
}
|
|
return tile;
|
|
}
|
|
/**
|
|
* @param {import("../../pixel.js").Pixel} pixel Pixel.
|
|
* @return {Uint8ClampedArray} Data at the pixel location.
|
|
* @override
|
|
*/
|
|
getData(pixel) {
|
|
const frameState = this.frameState;
|
|
if (!frameState) {
|
|
return null;
|
|
}
|
|
const layer = this.getLayer();
|
|
const coordinate = apply(
|
|
frameState.pixelToCoordinateTransform,
|
|
pixel.slice()
|
|
);
|
|
const layerExtent = layer.getExtent();
|
|
if (layerExtent) {
|
|
if (!containsCoordinate(layerExtent, coordinate)) {
|
|
return null;
|
|
}
|
|
}
|
|
const viewState = frameState.viewState;
|
|
const source = layer.getRenderSource();
|
|
const tileGrid = source.getTileGridForProjection(viewState.projection);
|
|
const tilePixelRatio = source.getTilePixelRatio(frameState.pixelRatio);
|
|
for (let z = tileGrid.getZForResolution(viewState.resolution); z >= tileGrid.getMinZoom(); --z) {
|
|
const tileCoord = tileGrid.getTileCoordForCoordAndZ(coordinate, z);
|
|
const tile = this.getTile(z, tileCoord[1], tileCoord[2], frameState);
|
|
if (!tile || tile.getState() !== TileState_default.LOADED) {
|
|
continue;
|
|
}
|
|
const tileOrigin = tileGrid.getOrigin(z);
|
|
const tileSize = toSize(tileGrid.getTileSize(z));
|
|
const tileResolution = tileGrid.getResolution(z);
|
|
let image;
|
|
if (tile instanceof ImageTile_default || tile instanceof Tile_default2) {
|
|
image = tile.getImage();
|
|
} else if (tile instanceof DataTile_default) {
|
|
image = asImageLike(tile.getData());
|
|
if (!image) {
|
|
continue;
|
|
}
|
|
} else {
|
|
continue;
|
|
}
|
|
const col = Math.floor(
|
|
tilePixelRatio * ((coordinate[0] - tileOrigin[0]) / tileResolution - tileCoord[1] * tileSize[0])
|
|
);
|
|
const row = Math.floor(
|
|
tilePixelRatio * ((tileOrigin[1] - coordinate[1]) / tileResolution - tileCoord[2] * tileSize[1])
|
|
);
|
|
const gutter = Math.round(
|
|
tilePixelRatio * source.getGutterForProjection(viewState.projection)
|
|
);
|
|
return this.getImageData(image, col + gutter, row + gutter);
|
|
}
|
|
return null;
|
|
}
|
|
/**
|
|
* Determine whether render should be called.
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
* @return {boolean} Layer is ready to be rendered.
|
|
* @override
|
|
*/
|
|
prepareFrame(frameState) {
|
|
var _a;
|
|
if (!this.renderedProjection) {
|
|
this.renderedProjection = frameState.viewState.projection;
|
|
} else if (frameState.viewState.projection !== this.renderedProjection) {
|
|
this.tileCache_.clear();
|
|
this.renderedProjection = frameState.viewState.projection;
|
|
}
|
|
const source = this.getLayer().getSource();
|
|
if (!source) {
|
|
return false;
|
|
}
|
|
const sourceRevision = source.getRevision();
|
|
if (!this.renderedSourceRevision_) {
|
|
this.renderedSourceRevision_ = sourceRevision;
|
|
} else if (this.renderedSourceRevision_ !== sourceRevision) {
|
|
this.renderedSourceRevision_ = sourceRevision;
|
|
if (this.renderedSourceKey_ === source.getKey()) {
|
|
this.tileCache_.clear();
|
|
(_a = this.sourceTileCache_) == null ? void 0 : _a.clear();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
/**
|
|
* Determine whether tiles for next extent should be enqueued for rendering.
|
|
* @return {boolean} Rendering tiles for next extent is supported.
|
|
* @protected
|
|
*/
|
|
enqueueTilesForNextExtent() {
|
|
return true;
|
|
}
|
|
/**
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
* @param {import("../../extent.js").Extent} extent The extent to be rendered.
|
|
* @param {number} initialZ The zoom level.
|
|
* @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
|
|
* @param {number} preload Number of additional levels to load.
|
|
*/
|
|
enqueueTiles(frameState, extent, initialZ, tilesByZ, preload) {
|
|
const viewState = frameState.viewState;
|
|
const tileLayer = this.getLayer();
|
|
const tileSource = tileLayer.getRenderSource();
|
|
const tileGrid = tileSource.getTileGridForProjection(viewState.projection);
|
|
const tileSourceKey = getUid(tileSource);
|
|
if (!(tileSourceKey in frameState.wantedTiles)) {
|
|
frameState.wantedTiles[tileSourceKey] = {};
|
|
}
|
|
const wantedTiles = frameState.wantedTiles[tileSourceKey];
|
|
const map = tileLayer.getMapInternal();
|
|
const minZ = Math.max(
|
|
initialZ - preload,
|
|
tileGrid.getMinZoom(),
|
|
tileGrid.getZForResolution(
|
|
Math.min(
|
|
tileLayer.getMaxResolution(),
|
|
map ? map.getView().getResolutionForZoom(Math.max(tileLayer.getMinZoom(), 0)) : tileGrid.getResolution(0)
|
|
),
|
|
tileSource.zDirection
|
|
)
|
|
);
|
|
const rotation = viewState.rotation;
|
|
const viewport = rotation ? getRotatedViewport(
|
|
viewState.center,
|
|
viewState.resolution,
|
|
rotation,
|
|
frameState.size
|
|
) : void 0;
|
|
for (let z = initialZ; z >= minZ; --z) {
|
|
const tileRange = tileGrid.getTileRangeForExtentAndZ(
|
|
extent,
|
|
z,
|
|
this.tempTileRange_
|
|
);
|
|
const tileResolution = tileGrid.getResolution(z);
|
|
for (let x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
|
for (let y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
|
if (rotation && !tileGrid.tileCoordIntersectsViewport([z, x, y], viewport)) {
|
|
continue;
|
|
}
|
|
const tile = this.getTile(z, x, y, frameState);
|
|
if (!tile) {
|
|
continue;
|
|
}
|
|
const added = addTileToLookup(tilesByZ, tile, z);
|
|
if (!added) {
|
|
continue;
|
|
}
|
|
const tileQueueKey = tile.getKey();
|
|
wantedTiles[tileQueueKey] = true;
|
|
if (tile.getState() === TileState_default.IDLE) {
|
|
if (!frameState.tileQueue.isKeyQueued(tileQueueKey)) {
|
|
const tileCoord = createOrUpdate(z, x, y, this.tempTileCoord_);
|
|
frameState.tileQueue.enqueue([
|
|
tile,
|
|
tileSourceKey,
|
|
tileGrid.getTileCoordCenter(tileCoord),
|
|
tileResolution
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Look for tiles covering the provided tile coordinate at an alternate
|
|
* zoom level. Loaded tiles will be added to the provided tile texture lookup.
|
|
* @param {import("../../tilecoord.js").TileCoord} tileCoord The target tile coordinate.
|
|
* @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
|
|
* @return {boolean} The tile coordinate is covered by loaded tiles at the alternate zoom level.
|
|
* @private
|
|
*/
|
|
findStaleTile_(tileCoord, tilesByZ) {
|
|
const tileCache = this.tileCache_;
|
|
const z = tileCoord[0];
|
|
const x = tileCoord[1];
|
|
const y = tileCoord[2];
|
|
const staleKeys = this.getStaleKeys();
|
|
for (let i = 0; i < staleKeys.length; ++i) {
|
|
const cacheKey = getCacheKey(
|
|
this.getLayer().getSource(),
|
|
staleKeys[i],
|
|
z,
|
|
x,
|
|
y
|
|
);
|
|
if (tileCache.containsKey(cacheKey)) {
|
|
const tile = tileCache.peek(cacheKey);
|
|
if (tile.getState() === TileState_default.LOADED) {
|
|
tile.endTransition(getUid(this));
|
|
addTileToLookup(tilesByZ, tile, z);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* Look for tiles covering the provided tile coordinate at an alternate
|
|
* zoom level. Loaded tiles will be added to the provided tile texture lookup.
|
|
* @param {import("../../tilegrid/TileGrid.js").default} tileGrid The tile grid.
|
|
* @param {import("../../tilecoord.js").TileCoord} tileCoord The target tile coordinate.
|
|
* @param {number} altZ The alternate zoom level.
|
|
* @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
|
|
* @return {boolean} The tile coordinate is covered by loaded tiles at the alternate zoom level.
|
|
* @private
|
|
*/
|
|
findAltTiles_(tileGrid, tileCoord, altZ, tilesByZ) {
|
|
const tileRange = tileGrid.getTileRangeForTileCoordAndZ(
|
|
tileCoord,
|
|
altZ,
|
|
this.tempTileRange_
|
|
);
|
|
if (!tileRange) {
|
|
return false;
|
|
}
|
|
let covered = true;
|
|
const tileCache = this.tileCache_;
|
|
const source = this.getLayer().getRenderSource();
|
|
const sourceKey = source.getKey();
|
|
for (let x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
|
for (let y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
|
const cacheKey = getCacheKey(source, sourceKey, altZ, x, y);
|
|
let loaded = false;
|
|
if (tileCache.containsKey(cacheKey)) {
|
|
const tile = tileCache.peek(cacheKey);
|
|
if (tile.getState() === TileState_default.LOADED) {
|
|
addTileToLookup(tilesByZ, tile, altZ);
|
|
loaded = true;
|
|
}
|
|
}
|
|
if (!loaded) {
|
|
covered = false;
|
|
}
|
|
}
|
|
}
|
|
return covered;
|
|
}
|
|
/**
|
|
* Render the layer.
|
|
*
|
|
* The frame rendering logic has three parts:
|
|
*
|
|
* 1. Enqueue tiles
|
|
* 2. Find alt tiles for those that are not yet loaded
|
|
* 3. Render loaded tiles
|
|
*
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
* @param {HTMLElement} target Target that may be used to render content to.
|
|
* @return {HTMLElement} The rendered element.
|
|
* @override
|
|
*/
|
|
renderFrame(frameState, target) {
|
|
this.renderComplete = true;
|
|
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
|
const viewState = frameState.viewState;
|
|
const projection = viewState.projection;
|
|
const viewResolution = viewState.resolution;
|
|
const viewCenter = viewState.center;
|
|
const pixelRatio = frameState.pixelRatio;
|
|
const tileLayer = this.getLayer();
|
|
const tileSource = tileLayer.getSource();
|
|
const tileGrid = tileSource.getTileGridForProjection(projection);
|
|
const z = tileGrid.getZForResolution(viewResolution, tileSource.zDirection);
|
|
const tileResolution = tileGrid.getResolution(z);
|
|
const sourceKey = tileSource.getKey();
|
|
if (!this.renderedSourceKey_) {
|
|
this.renderedSourceKey_ = sourceKey;
|
|
} else if (this.renderedSourceKey_ !== sourceKey) {
|
|
this.prependStaleKey(this.renderedSourceKey_);
|
|
this.renderedSourceKey_ = sourceKey;
|
|
}
|
|
let frameExtent = frameState.extent;
|
|
const tilePixelRatio = tileSource.getTilePixelRatio(pixelRatio);
|
|
this.prepareContainer(frameState, target);
|
|
const width = this.context.canvas.width;
|
|
const height = this.context.canvas.height;
|
|
const layerExtent = layerState.extent && fromUserExtent(layerState.extent, projection);
|
|
if (layerExtent) {
|
|
frameExtent = getIntersection(
|
|
frameExtent,
|
|
fromUserExtent(layerState.extent, projection)
|
|
);
|
|
}
|
|
const dx = tileResolution * width / 2 / tilePixelRatio;
|
|
const dy = tileResolution * height / 2 / tilePixelRatio;
|
|
const canvasExtent = [
|
|
viewCenter[0] - dx,
|
|
viewCenter[1] - dy,
|
|
viewCenter[0] + dx,
|
|
viewCenter[1] + dy
|
|
];
|
|
const tilesByZ = {};
|
|
this.renderedTiles.length = 0;
|
|
const preload = tileLayer.getPreload();
|
|
if (frameState.nextExtent && this.enqueueTilesForNextExtent()) {
|
|
const targetZ = tileGrid.getZForResolution(
|
|
viewState.nextResolution,
|
|
tileSource.zDirection
|
|
);
|
|
const nextExtent = getRenderExtent(frameState, frameState.nextExtent);
|
|
this.enqueueTiles(frameState, nextExtent, targetZ, tilesByZ, preload);
|
|
}
|
|
const renderExtent = getRenderExtent(frameState, frameExtent);
|
|
this.enqueueTiles(frameState, renderExtent, z, tilesByZ, 0);
|
|
if (preload > 0) {
|
|
setTimeout(() => {
|
|
this.enqueueTiles(
|
|
frameState,
|
|
renderExtent,
|
|
z - 1,
|
|
tilesByZ,
|
|
preload - 1
|
|
);
|
|
}, 0);
|
|
}
|
|
if (!(z in tilesByZ)) {
|
|
return this.container;
|
|
}
|
|
const uid = getUid(this);
|
|
const time = frameState.time;
|
|
for (const tile of tilesByZ[z]) {
|
|
const tileState = tile.getState();
|
|
if (tileState === TileState_default.EMPTY) {
|
|
continue;
|
|
}
|
|
const tileCoord = tile.tileCoord;
|
|
if (tileState === TileState_default.LOADED) {
|
|
const alpha = tile.getAlpha(uid, time);
|
|
if (alpha === 1) {
|
|
tile.endTransition(uid);
|
|
continue;
|
|
}
|
|
}
|
|
if (tileState !== TileState_default.ERROR) {
|
|
this.renderComplete = false;
|
|
}
|
|
const hasStaleTile = this.findStaleTile_(tileCoord, tilesByZ);
|
|
if (hasStaleTile) {
|
|
removeTileFromLookup(tilesByZ, tile, z);
|
|
frameState.animate = true;
|
|
continue;
|
|
}
|
|
const coveredByChildren = this.findAltTiles_(
|
|
tileGrid,
|
|
tileCoord,
|
|
z + 1,
|
|
tilesByZ
|
|
);
|
|
if (coveredByChildren) {
|
|
continue;
|
|
}
|
|
const minZoom = tileGrid.getMinZoom();
|
|
for (let parentZ = z - 1; parentZ >= minZoom; --parentZ) {
|
|
const coveredByParent = this.findAltTiles_(
|
|
tileGrid,
|
|
tileCoord,
|
|
parentZ,
|
|
tilesByZ
|
|
);
|
|
if (coveredByParent) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
const canvasScale = tileResolution / viewResolution * pixelRatio / tilePixelRatio;
|
|
const context = this.getRenderContext(frameState);
|
|
compose(
|
|
this.tempTransform,
|
|
width / 2,
|
|
height / 2,
|
|
canvasScale,
|
|
canvasScale,
|
|
0,
|
|
-width / 2,
|
|
-height / 2
|
|
);
|
|
if (layerState.extent) {
|
|
this.clipUnrotated(context, frameState, layerExtent);
|
|
}
|
|
if (!tileSource.getInterpolate()) {
|
|
context.imageSmoothingEnabled = false;
|
|
}
|
|
this.preRender(context, frameState);
|
|
const zs = Object.keys(tilesByZ).map(Number);
|
|
zs.sort(ascending);
|
|
let currentClip;
|
|
const clips = [];
|
|
const clipZs = [];
|
|
for (let i = zs.length - 1; i >= 0; --i) {
|
|
const currentZ = zs[i];
|
|
const currentTilePixelSize = tileSource.getTilePixelSize(
|
|
currentZ,
|
|
pixelRatio,
|
|
projection
|
|
);
|
|
const currentResolution = tileGrid.getResolution(currentZ);
|
|
const currentScale = currentResolution / tileResolution;
|
|
const dx2 = currentTilePixelSize[0] * currentScale * canvasScale;
|
|
const dy2 = currentTilePixelSize[1] * currentScale * canvasScale;
|
|
const originTileCoord = tileGrid.getTileCoordForCoordAndZ(
|
|
getTopLeft(canvasExtent),
|
|
currentZ
|
|
);
|
|
const originTileExtent = tileGrid.getTileCoordExtent(originTileCoord);
|
|
const origin = apply(this.tempTransform, [
|
|
tilePixelRatio * (originTileExtent[0] - canvasExtent[0]) / tileResolution,
|
|
tilePixelRatio * (canvasExtent[3] - originTileExtent[3]) / tileResolution
|
|
]);
|
|
const tileGutter = tilePixelRatio * tileSource.getGutterForProjection(projection);
|
|
for (const tile of tilesByZ[currentZ]) {
|
|
if (tile.getState() !== TileState_default.LOADED) {
|
|
continue;
|
|
}
|
|
const tileCoord = tile.tileCoord;
|
|
const xIndex = originTileCoord[1] - tileCoord[1];
|
|
const nextX = Math.round(origin[0] - (xIndex - 1) * dx2);
|
|
const yIndex = originTileCoord[2] - tileCoord[2];
|
|
const nextY = Math.round(origin[1] - (yIndex - 1) * dy2);
|
|
const x = Math.round(origin[0] - xIndex * dx2);
|
|
const y = Math.round(origin[1] - yIndex * dy2);
|
|
const w = nextX - x;
|
|
const h = nextY - y;
|
|
const transition = zs.length === 1;
|
|
let contextSaved = false;
|
|
currentClip = [x, y, x + w, y, x + w, y + h, x, y + h];
|
|
for (let i2 = 0, ii = clips.length; i2 < ii; ++i2) {
|
|
if (!transition && currentZ < clipZs[i2]) {
|
|
const clip = clips[i2];
|
|
if (intersects(
|
|
[x, y, x + w, y + h],
|
|
[clip[0], clip[3], clip[4], clip[7]]
|
|
)) {
|
|
if (!contextSaved) {
|
|
context.save();
|
|
contextSaved = true;
|
|
}
|
|
context.beginPath();
|
|
context.moveTo(currentClip[0], currentClip[1]);
|
|
context.lineTo(currentClip[2], currentClip[3]);
|
|
context.lineTo(currentClip[4], currentClip[5]);
|
|
context.lineTo(currentClip[6], currentClip[7]);
|
|
context.moveTo(clip[6], clip[7]);
|
|
context.lineTo(clip[4], clip[5]);
|
|
context.lineTo(clip[2], clip[3]);
|
|
context.lineTo(clip[0], clip[1]);
|
|
context.clip();
|
|
}
|
|
}
|
|
}
|
|
clips.push(currentClip);
|
|
clipZs.push(currentZ);
|
|
this.drawTile(tile, frameState, x, y, w, h, tileGutter, transition);
|
|
if (contextSaved) {
|
|
context.restore();
|
|
}
|
|
this.renderedTiles.unshift(tile);
|
|
this.updateUsedTiles(frameState.usedTiles, tileSource, tile);
|
|
}
|
|
}
|
|
this.renderedResolution = tileResolution;
|
|
this.extentChanged = !this.renderedExtent_ || !equals(this.renderedExtent_, canvasExtent);
|
|
this.renderedExtent_ = canvasExtent;
|
|
this.renderedPixelRatio = pixelRatio;
|
|
this.postRender(this.context, frameState);
|
|
if (layerState.extent) {
|
|
context.restore();
|
|
}
|
|
context.imageSmoothingEnabled = true;
|
|
if (this.renderComplete) {
|
|
const postRenderFunction = (map, frameState2) => {
|
|
var _a;
|
|
const tileSourceKey = getUid(tileSource);
|
|
const wantedTiles = frameState2.wantedTiles[tileSourceKey];
|
|
const tilesCount = wantedTiles ? Object.keys(wantedTiles).length : 0;
|
|
this.updateCacheSize(tilesCount);
|
|
this.tileCache_.expireCache();
|
|
(_a = this.sourceTileCache_) == null ? void 0 : _a.expireCache();
|
|
};
|
|
frameState.postRenderFunctions.push(postRenderFunction);
|
|
}
|
|
return this.container;
|
|
}
|
|
/**
|
|
* Increases the cache size if needed
|
|
* @param {number} tileCount Minimum number of tiles needed.
|
|
*/
|
|
updateCacheSize(tileCount) {
|
|
this.tileCache_.highWaterMark = Math.max(
|
|
this.tileCache_.highWaterMark,
|
|
tileCount * 2
|
|
);
|
|
}
|
|
/**
|
|
* @param {import("../../Tile.js").default} tile Tile.
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
|
* @param {number} x Left of the tile.
|
|
* @param {number} y Top of the tile.
|
|
* @param {number} w Width of the tile.
|
|
* @param {number} h Height of the tile.
|
|
* @param {number} gutter Tile gutter.
|
|
* @param {boolean} transition Apply an alpha transition.
|
|
* @protected
|
|
*/
|
|
drawTile(tile, frameState, x, y, w, h, gutter, transition) {
|
|
let image;
|
|
if (tile instanceof DataTile_default) {
|
|
image = asImageLike(tile.getData());
|
|
if (!image) {
|
|
throw new Error("Rendering array data is not yet supported");
|
|
}
|
|
} else {
|
|
image = this.getTileImage(
|
|
/** @type {import("../../ImageTile.js").default} */
|
|
tile
|
|
);
|
|
}
|
|
if (!image) {
|
|
return;
|
|
}
|
|
const context = this.getRenderContext(frameState);
|
|
const uid = getUid(this);
|
|
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
|
const alpha = layerState.opacity * (transition ? tile.getAlpha(uid, frameState.time) : 1);
|
|
const alphaChanged = alpha !== context.globalAlpha;
|
|
if (alphaChanged) {
|
|
context.save();
|
|
context.globalAlpha = alpha;
|
|
}
|
|
context.drawImage(
|
|
image,
|
|
gutter,
|
|
gutter,
|
|
image.width - 2 * gutter,
|
|
image.height - 2 * gutter,
|
|
x,
|
|
y,
|
|
w,
|
|
h
|
|
);
|
|
if (alphaChanged) {
|
|
context.restore();
|
|
}
|
|
if (alpha !== layerState.opacity) {
|
|
frameState.animate = true;
|
|
} else if (transition) {
|
|
tile.endTransition(uid);
|
|
}
|
|
}
|
|
/**
|
|
* @return {HTMLCanvasElement|OffscreenCanvas} Image
|
|
*/
|
|
getImage() {
|
|
const context = this.context;
|
|
return context ? context.canvas : null;
|
|
}
|
|
/**
|
|
* Get the image from a tile.
|
|
* @param {import("../../ImageTile.js").default} tile Tile.
|
|
* @return {HTMLCanvasElement|OffscreenCanvas|HTMLImageElement|HTMLVideoElement} Image.
|
|
* @protected
|
|
*/
|
|
getTileImage(tile) {
|
|
return tile.getImage();
|
|
}
|
|
/**
|
|
* @param {!Object<string, !Object<string, boolean>>} usedTiles Used tiles.
|
|
* @param {import("../../source/Tile.js").default} tileSource Tile source.
|
|
* @param {import('../../Tile.js').default} tile Tile.
|
|
* @protected
|
|
*/
|
|
updateUsedTiles(usedTiles, tileSource, tile) {
|
|
const tileSourceKey = getUid(tileSource);
|
|
if (!(tileSourceKey in usedTiles)) {
|
|
usedTiles[tileSourceKey] = {};
|
|
}
|
|
usedTiles[tileSourceKey][tile.getKey()] = true;
|
|
}
|
|
};
|
|
var TileLayer_default = CanvasTileLayerRenderer;
|
|
|
|
// node_modules/ol/layer/TileProperty.js
|
|
var TileProperty_default = {
|
|
PRELOAD: "preload",
|
|
USE_INTERIM_TILES_ON_ERROR: "useInterimTilesOnError"
|
|
};
|
|
|
|
// node_modules/ol/layer/BaseTile.js
|
|
var BaseTileLayer = class extends Layer_default2 {
|
|
/**
|
|
* @param {Options<TileSourceType>} [options] Tile layer options.
|
|
*/
|
|
constructor(options) {
|
|
options = options ? options : {};
|
|
const baseOptions = Object.assign({}, options);
|
|
const cacheSize = options.cacheSize;
|
|
delete options.cacheSize;
|
|
delete baseOptions.preload;
|
|
delete baseOptions.useInterimTilesOnError;
|
|
super(baseOptions);
|
|
this.on;
|
|
this.once;
|
|
this.un;
|
|
this.cacheSize_ = cacheSize;
|
|
this.setPreload(options.preload !== void 0 ? options.preload : 0);
|
|
this.setUseInterimTilesOnError(
|
|
options.useInterimTilesOnError !== void 0 ? options.useInterimTilesOnError : true
|
|
);
|
|
}
|
|
/**
|
|
* @return {number|undefined} The suggested cache size
|
|
* @protected
|
|
*/
|
|
getCacheSize() {
|
|
return this.cacheSize_;
|
|
}
|
|
/**
|
|
* Return the level as number to which we will preload tiles up to.
|
|
* @return {number} The level to preload tiles up to.
|
|
* @observable
|
|
* @api
|
|
*/
|
|
getPreload() {
|
|
return (
|
|
/** @type {number} */
|
|
this.get(TileProperty_default.PRELOAD)
|
|
);
|
|
}
|
|
/**
|
|
* Set the level as number to which we will preload tiles up to.
|
|
* @param {number} preload The level to preload tiles up to.
|
|
* @observable
|
|
* @api
|
|
*/
|
|
setPreload(preload) {
|
|
this.set(TileProperty_default.PRELOAD, preload);
|
|
}
|
|
/**
|
|
* Deprecated. Whether we use interim tiles on error.
|
|
* @return {boolean} Use interim tiles on error.
|
|
* @observable
|
|
* @api
|
|
*/
|
|
getUseInterimTilesOnError() {
|
|
return (
|
|
/** @type {boolean} */
|
|
this.get(TileProperty_default.USE_INTERIM_TILES_ON_ERROR)
|
|
);
|
|
}
|
|
/**
|
|
* Deprecated. Set whether we use interim tiles on error.
|
|
* @param {boolean} useInterimTilesOnError Use interim tiles on error.
|
|
* @observable
|
|
* @api
|
|
*/
|
|
setUseInterimTilesOnError(useInterimTilesOnError) {
|
|
this.set(TileProperty_default.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError);
|
|
}
|
|
/**
|
|
* Get data for a pixel location. The return type depends on the source data. For image tiles,
|
|
* a four element RGBA array will be returned. For data tiles, the array length will match the
|
|
* number of bands in the dataset. For requests outside the layer extent, `null` will be returned.
|
|
* Data for a image tiles can only be retrieved if the source's `crossOrigin` property is set.
|
|
*
|
|
* ```js
|
|
* // display layer data on every pointer move
|
|
* map.on('pointermove', (event) => {
|
|
* console.log(layer.getData(event.pixel));
|
|
* });
|
|
* ```
|
|
* @param {import("../pixel").Pixel} pixel Pixel.
|
|
* @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView|null} Pixel data.
|
|
* @api
|
|
* @override
|
|
*/
|
|
getData(pixel) {
|
|
return super.getData(pixel);
|
|
}
|
|
};
|
|
var BaseTile_default = BaseTileLayer;
|
|
|
|
// node_modules/ol/layer/Tile.js
|
|
var TileLayer = class extends BaseTile_default {
|
|
/**
|
|
* @param {import("./BaseTile.js").Options<TileSourceType>} [options] Tile layer options.
|
|
*/
|
|
constructor(options) {
|
|
super(options);
|
|
}
|
|
/**
|
|
* @override
|
|
*/
|
|
createRenderer() {
|
|
return new TileLayer_default(this, {
|
|
cacheSize: this.getCacheSize()
|
|
});
|
|
}
|
|
};
|
|
var Tile_default3 = TileLayer;
|
|
|
|
export {
|
|
asImageLike,
|
|
asArrayLike,
|
|
toArray,
|
|
DataTile_default,
|
|
LRUCache_default,
|
|
TileLayer_default,
|
|
TileProperty_default,
|
|
BaseTile_default,
|
|
Tile_default3 as Tile_default
|
|
};
|
|
//# sourceMappingURL=chunk-UNDFRJ2M.js.map
|