/**
|
* @module olcs.core.OLImageryProvider
|
*/
|
import {get as getProjection} from 'ol/proj.js';
|
import olcsUtil from '../util.js';
|
import {Tile as TileSource} from 'ol/source.js';
|
import {attributionsFunctionToCredits} from '../core.js';
|
|
|
const olUseNewCoordinates = (function() {
|
const tileSource = new TileSource({
|
projection: 'EPSG:3857',
|
wrapX: true
|
});
|
const tileCoord = tileSource.getTileCoordForTileUrlFunction([6, -31, 22]);
|
return tileCoord && tileCoord[1] === 33 && tileCoord[2] === 22;
|
// See b/test/spec/ol/source/tile.test.js
|
// of e9a30c5cb7e3721d9370025fbe5472c322847b35 in OpenLayers repository
|
})();
|
|
|
class OLImageryProvider /* should not extend Cesium.ImageryProvider */ {
|
/**
|
* Special class derived from Cesium.ImageryProvider
|
* that is connected to the given ol.source.TileImage.
|
* @param {!ol.Map} olMap
|
* @param {!ol.source.TileImage} source
|
* @param {ol.proj.Projection=} opt_fallbackProj Projection to assume if the
|
* projection of the source is not defined.
|
* @constructor
|
* @extends {Cesium.ImageryProvider}
|
*/
|
constructor(olMap, source, opt_fallbackProj) {
|
// Do not extend or call super constructor from
|
// Cesium.ImageryProvider since this particular function is a
|
// 'non instanciable interface' which throws on instanciation.
|
|
/**
|
* @type {!ol.source.TileImage}
|
* @private
|
*/
|
this.source_ = source;
|
|
/**
|
* @type {?ol.proj.Projection}
|
* @private
|
*/
|
this.projection_ = null;
|
|
/**
|
* @type {?ol.proj.Projection}
|
* @private
|
*/
|
this.fallbackProj_ = opt_fallbackProj || null;
|
|
/**
|
* @type {boolean}
|
* @private
|
*/
|
this.ready_ = false;
|
|
/**
|
* @type {?Cesium.TilingScheme}
|
* @private
|
*/
|
this.tilingScheme_ = null;
|
|
/**
|
* @type {?Cesium.Rectangle}
|
* @private
|
*/
|
this.rectangle_ = null;
|
|
/**
|
* @type {!ol.Map}
|
* @private
|
*/
|
this.map_ = olMap;
|
|
|
/**
|
* @type {boolean}
|
* @private
|
*/
|
this.shouldRequestNextLevel = false;
|
|
const proxy = this.source_.get('olcs.proxy');
|
if (proxy) {
|
if (typeof proxy === 'function') {
|
this.proxy_ = {
|
'getURL': proxy
|
};
|
} else if (typeof proxy === 'string') {
|
this.proxy_ = new Cesium.DefaultProxy(proxy);
|
}
|
}
|
|
this.errorEvent_ = new Cesium.Event();
|
|
this.emptyCanvas_ = document.createElement('canvas');
|
this.emptyCanvas_.width = 1;
|
this.emptyCanvas_.height = 1;
|
|
this.source_.on('change', (e) => {
|
this.handleSourceChanged_();
|
});
|
this.handleSourceChanged_();
|
}
|
|
/**
|
* Checks if the underlying source is ready and cached required data.
|
* @private
|
*/
|
handleSourceChanged_(frameState) {
|
if (!this.ready_ && this.source_.getState() == 'ready') {
|
this.projection_ = olcsUtil.getSourceProjection(this.source_) || this.fallbackProj_;
|
const options = {numberOfLevelZeroTilesX: 1, numberOfLevelZeroTilesY: 1};
|
|
if (this.source_.tileGrid !== null) {
|
// Get the number of tiles at level 0 if it is defined
|
this.source_.tileGrid.forEachTileCoord(this.projection_.getExtent(), 0, ([zoom, xIndex, yIndex]) => {
|
options.numberOfLevelZeroTilesX = xIndex + 1;
|
options.numberOfLevelZeroTilesY = yIndex + 1;
|
});
|
}
|
|
if (this.projection_ == getProjection('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_ == getProjection('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.
|
* @export
|
* @override
|
*/
|
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);
|
}
|
|
/**
|
* @export
|
* @override
|
*/
|
requestImage(x, y, level) {
|
const tileUrlFunction = this.source_.getTileUrlFunction();
|
if (tileUrlFunction && this.projection_) {
|
|
const z_ = this.shouldRequestNextLevel ? level + 1 : level;
|
|
let y_ = y;
|
if (!olUseNewCoordinates) {
|
// OpenLayers version 3 to 5 tile coordinates increase from bottom to top
|
y_ = -y - 1;
|
}
|
let url = tileUrlFunction.call(this.source_, [z_, x, y_], 1, this.projection_);
|
if (this.proxy_) {
|
url = this.proxy_.getURL(url);
|
}
|
return url ? Cesium.ImageryProvider.loadImage(this, url) : this.emptyCanvas_;
|
} else {
|
// return empty canvas to stop Cesium from retrying later
|
return this.emptyCanvas_;
|
}
|
}
|
}
|
|
// definitions of getters that are required to be present
|
// in the Cesium.ImageryProvider instance:
|
Object.defineProperties(OLImageryProvider.prototype, {
|
'ready': {
|
'get': /** @this {olcs.core.OLImageryProvider} */
|
function() {return this.ready_;}
|
},
|
|
'rectangle': {
|
'get': /** @this {olcs.core.OLImageryProvider} */
|
function() {return this.rectangle_;}
|
},
|
|
'tileWidth': {
|
'get': /** @this {olcs.core.OLImageryProvider} */
|
function() {
|
const tg = this.source_.getTileGrid();
|
return tg ? (Array.isArray(tg.getTileSize(0)) ? tg.getTileSize(0)[0] : tg.getTileSize(0)) : 256;
|
}
|
},
|
|
'tileHeight': {
|
'get': /** @this {olcs.core.OLImageryProvider} */
|
function() {
|
const tg = this.source_.getTileGrid();
|
return tg ? (Array.isArray(tg.getTileSize(0)) ? tg.getTileSize(0)[1] : tg.getTileSize(0)) : 256;
|
}
|
},
|
|
'maximumLevel': {
|
'get': /** @this {olcs.core.OLImageryProvider} */
|
function() {
|
const tg = this.source_.getTileGrid();
|
return tg ? tg.getMaxZoom() : 18;
|
}
|
},
|
|
'minimumLevel': {
|
'get': /** @this {olcs.core.OLImageryProvider} */
|
function() {
|
// 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;
|
}
|
},
|
|
'tilingScheme': {
|
'get': /** @this {olcs.core.OLImageryProvider} */
|
function() {return this.tilingScheme_;}
|
},
|
|
'tileDiscardPolicy': {
|
'get': function() {return undefined;}
|
},
|
|
'errorEvent': {
|
'get': /** @this {olcs.core.OLImageryProvider} */
|
function() {return this.errorEvent_;}
|
},
|
|
'proxy': {
|
'get': /** @this {olcs.core.OLImageryProvider} */
|
function() {return this.proxy_;}
|
},
|
|
'hasAlphaChannel': {
|
'get': function() {return true;}
|
},
|
|
'pickFeatures': {
|
'get': function() {return undefined;}
|
}
|
});
|
|
|
export default OLImageryProvider;
|