UNPKG

ev-olcs

Version:

OpenLayers Cesium integration and plugin library

258 lines 17.7 kB
import { getSourceProjection } from '../util.js'; import {} from 'ol/source.js'; import { attributionsFunctionToCredits } from '../core.js'; export function createEmptyCanvas() { const canvas = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; return canvas; } export default class OLImageryProvider { source_; projection_; fallbackProj_; map_; shouldRequestNextLevel; emptyCanvas_ = createEmptyCanvas(); emptyCanvasPromise_ = Promise.resolve(this.emptyCanvas_); tilingScheme_; ready_; rectangle_; /** * When <code>true</code>, this model is ready to render, i.e., the external binary, image, * and shader files were downloaded and the WebGL resources were created. */ get ready() { return this.ready_; } /** * Gets the rectangle, in radians, of the imagery provided by the instance. */ get rectangle() { return this.rectangle_; } /** * Gets the tiling scheme used by the provider. */ get tilingScheme() { return this.tilingScheme_; } /** * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing * to the event, you will be notified of the error and can potentially recover from it. Event listeners * are passed an instance of {@link Cesium.TileProviderError}. */ errorEvent = new Cesium.Event(); /** * Gets the credit to display when this imagery provider is active. Typically this is used to credit * the source of the imagery. */ credit; /** * Gets the proxy used by this provider. */ proxy; get _ready() { return this.ready_; } /** * Gets the width of each tile, in pixels. */ get tileWidth() { const tileGrid = this.source_.getTileGrid(); if (tileGrid) { const tileSizeAtZoom0 = tileGrid.getTileSize(0); if (Array.isArray(tileSizeAtZoom0)) { return tileSizeAtZoom0[0]; } else { return tileSizeAtZoom0; // same width and height } } return 256; } /** * Gets the height of each tile, in pixels. */ get tileHeight() { const tileGrid = this.source_.getTileGrid(); if (tileGrid) { const tileSizeAtZoom0 = tileGrid.getTileSize(0); if (Array.isArray(tileSizeAtZoom0)) { return tileSizeAtZoom0[1]; } else { return tileSizeAtZoom0; // same width and height } } return 256; } /** * Gets the maximum level-of-detail that can be requested. */ get maximumLevel() { const tileGrid = this.source_.getTileGrid(); if (tileGrid) { return tileGrid.getMaxZoom(); } else { return 18; // some arbitrary value } } // FIXME: to implement, we could check the number of tiles at minzoom (for this rectangle) and return 0 if too big /** * Gets the minimum level-of-detail that can be requested. Generally, * a minimum level should only be used when the rectangle of the imagery is small * enough that the number of tiles at the minimum level is small. An imagery * provider with more than a few tiles at the minimum level will lead to * rendering problems. */ get minimumLevel() { // WARNING: Do not use the minimum level (at least until the extent is // properly set). Cesium assumes the minimumLevel to contain only // a few tiles and tries to load them all at once -- this can // freeze and/or crash the browser ! return 0; //var tg = this.source_.getTileGrid(); //return tg ? tg.getMinZoom() : 0; } /** * Gets the tile discard policy. If not undefined, the discard policy is responsible * for filtering out "missing" tiles via its shouldDiscardImage function. If this function * returns undefined, no tiles are filtered. */ get tileDiscardPolicy() { return undefined; } // FIXME: this might be exposed /** * Gets a value indicating whether or not the images provided by this imagery provider * include an alpha channel. If this property is false, an alpha channel, if present, will * be ignored. If this property is true, any images without an alpha channel will be treated * as if their alpha is 1.0 everywhere. When this property is false, memory usage * and texture upload time are reduced. */ get hasAlphaChannel() { return true; } // FIXME: this could be implemented by proxying to OL /** * Asynchronously determines what features, if any, are located at a given longitude and latitude within * a tile. * This function is optional, so it may not exist on all ImageryProviders. * @param x - The tile X coordinate. * @param y - The tile Y coordinate. * @param level - The tile level. * @param longitude - The longitude at which to pick features. * @param latitude - The latitude at which to pick features. * @return A promise for the picked features that will resolve when the asynchronous * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo} * instances. The array may be empty if no features are found at the given location. * It may also be undefined if picking is not supported. */ pickFeatures(x, y, level, longitude, latitude) { return undefined; } /** * Special class derived from Cesium.ImageryProvider * that is connected to the given ol.source.TileImage. * @param olMap OL map * @param source Tile image source * @param [opt_fallbackProj] Projection to assume if source has no projection */ constructor(olMap, source, opt_fallbackProj) { this.source_ = source; this.projection_ = null; this.ready_ = false; this.fallbackProj_ = opt_fallbackProj || null; // cesium v107+ don't wait for ready anymore so we put somehing here while it loads this.tilingScheme_ = new Cesium.WebMercatorTilingScheme(); this.rectangle_ = null; this.map_ = olMap; this.shouldRequestNextLevel = false; const proxy = this.source_.get('olcs_proxy'); if (proxy) { if (typeof proxy === 'function') { // Duck typing a proxy this.proxy = { 'getURL': proxy }; } else if (typeof proxy === 'string') { this.proxy = new Cesium.DefaultProxy(proxy); } } this.source_.on('change', (e) => { this.handleSourceChanged_(); }); this.handleSourceChanged_(); } /** * Checks if the underlying source is ready and cached required data. */ handleSourceChanged_() { if (!this.ready_ && this.source_.getState() == 'ready') { this.projection_ = getSourceProjection(this.source_) || this.fallbackProj_; const options = { numberOfLevelZeroTilesX: 1, numberOfLevelZeroTilesY: 1 }; if (this.source_.getTileGrid() !== null) { // Get the number of tiles at level 0 if it is defined this.source_.getTileGrid().forEachTileCoord(this.projection_.getExtent(), 0, ([zoom, xIndex, yIndex]) => { options.numberOfLevelZeroTilesX = xIndex + 1; options.numberOfLevelZeroTilesY = yIndex + 1; }); } if (this.projection_.getCode() === 'EPSG:4326') { // Cesium zoom level 0 is OpenLayers zoom level 1 for layer in EPSG:4326 with a single tile on level 0 this.shouldRequestNextLevel = options.numberOfLevelZeroTilesX === 1 && options.numberOfLevelZeroTilesY === 1; this.tilingScheme_ = new Cesium.GeographicTilingScheme(options); } else if (this.projection_.getCode() === 'EPSG:3857') { this.shouldRequestNextLevel = false; this.tilingScheme_ = new Cesium.WebMercatorTilingScheme(options); } else { return; } this.rectangle_ = this.tilingScheme_.rectangle; this.ready_ = true; } } /** * Generates the proper attributions for a given position and zoom * level. * @implements */ getTileCredits(x, y, level) { const attributionsFunction = this.source_.getAttributions(); if (!attributionsFunction) { return []; } const extent = this.map_.getView().calculateExtent(this.map_.getSize()); const center = this.map_.getView().getCenter(); const zoom = this.shouldRequestNextLevel ? level + 1 : level; return attributionsFunctionToCredits(attributionsFunction, zoom, center, extent); } /** * @implements */ requestImage(x, y, level, request) { const tileUrlFunction = this.source_.getTileUrlFunction(); if (tileUrlFunction && this.projection_) { const z_ = this.shouldRequestNextLevel ? level + 1 : level; let url = tileUrlFunction.call(this.source_, [z_, x, y], 1, this.projection_); if (this.proxy) { url = this.proxy.getURL(url); } if (url) { // It is probably safe to cast here return Cesium.ImageryProvider.loadImage(this, url); } return this.emptyCanvasPromise_; } else { // return empty canvas to stop Cesium from retrying later return this.emptyCanvasPromise_; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT0xJbWFnZXJ5UHJvdmlkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvb2xjcy9jb3JlL09MSW1hZ2VyeVByb3ZpZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxtQkFBbUIsRUFBQyxNQUFNLFlBQVksQ0FBQztBQUMvQyxPQUFPLEVBQWdCLE1BQU0sY0FBYyxDQUFDO0FBQzVDLE9BQU8sRUFBQyw2QkFBNkIsRUFBQyxNQUFNLFlBQVksQ0FBQztBQU16RCxNQUFNLFVBQVUsaUJBQWlCO0lBQy9CLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDaEQsTUFBTSxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUM7SUFDakIsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDbEIsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQztBQUVELE1BQU0sQ0FBQyxPQUFPLE9BQU8saUJBQWlCO0lBQzVCLE9BQU8sQ0FBWTtJQUNuQixXQUFXLENBQXlCO0lBQ3BDLGFBQWEsQ0FBeUI7SUFDdEMsSUFBSSxDQUFNO0lBQ1Ysc0JBQXNCLENBQVU7SUFDaEMsWUFBWSxHQUFzQixpQkFBaUIsRUFBRSxDQUFDO0lBQ3RELG1CQUFtQixHQUErQixPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUNyRixhQUFhLENBQWU7SUFDNUIsTUFBTSxDQUFVO0lBQ2hCLFVBQVUsQ0FBWTtJQUU5Qjs7O0tBR0M7SUFDRCxJQUFJLEtBQUs7UUFDUCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDckIsQ0FBQztJQUVEOztLQUVDO0lBQ0QsSUFBSSxTQUFTO1FBQ1gsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksWUFBWTtRQUNkLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQztJQUM1QixD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