ol-cesium
Version:
OpenLayers Cesium integration library
245 lines • 19 kB
JavaScript
import MVT from 'ol/format/MVT.js';
import Style, {} from 'ol/style/Style.js';
import Stroke from 'ol/style/Stroke.js';
import { toContext } from 'ol/render.js';
import { get as getProjection } from 'ol/proj.js';
import { VERSION as OL_VERSION } from 'ol/util.js';
import LRUCache from 'ol/structs/LRUCache.js';
import { getForProjection as getTilegridForProjection } from 'ol/tilegrid.js';
import { createFromTemplates as createTileUrlFunctions } from 'ol/tileurlfunction.js';
import RenderFeature from 'ol/render/Feature.js';
import { createEmptyCanvas } from './core/OLImageryProvider';
const format = new MVT({
featureClass: RenderFeature
});
const styles = [new Style({
stroke: new Stroke({
color: 'blue',
width: 2
})
})];
export default class MVTImageryProvider {
urls;
emptyCanvas_ = createEmptyCanvas();
emptyCanvasPromise_ = Promise.resolve(this.emptyCanvas_);
tilingScheme_ = new Cesium.WebMercatorTilingScheme;
ready_ = true;
rectangle_;
tileRectangle_;
tileWidth = 256;
tileHeight = 256;
maximumLevel = 20;
minimumLevel_ = 0;
get minimumLevel() {
return this.minimumLevel_;
}
featureCache;
tileCache;
tileFunction_;
styleFunction_;
projection_ = getProjection('EPSG:3857');
/**
* 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;
getTileCredits(x, y, level) {
return [];
}
/**
* Gets the proxy used by this provider.
*/
proxy;
get _ready() {
return this.ready_;
}
/**
* 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;
}
constructor(options) {
this.urls = options.urls;
this.rectangle_ = options.rectangle || this.tilingScheme.rectangle;
this.credit = options.credit;
this.styleFunction_ = options.styleFunction || (() => styles);
this.tileRectangle_ = new Cesium.Rectangle();
// to avoid too frequent cache grooming we allow x2 capacity
const cacheSize = options.cacheSize !== undefined ? options.cacheSize : 50;
this.tileCache = new LRUCache(cacheSize);
this.featureCache = options.featureCache || new LRUCache(cacheSize);
this.minimumLevel_ = options.minimumLevel || 0;
const tileGrid = getTilegridForProjection(this.projection_);
this.tileFunction_ = createTileUrlFunctions(this.urls, tileGrid);
}
getTileFeatures(z, x, y) {
const cacheKey = this.getCacheKey_(z, x, y);
let promise;
if (this.featureCache.containsKey(cacheKey)) {
promise = this.featureCache.get(cacheKey);
}
if (!promise) {
const url = this.getUrl_(z, x, y);
promise = fetch(url)
.then(r => (r.ok ? r : Promise.reject(r)))
.then(r => r.arrayBuffer())
.then(buffer => this.readFeaturesFromBuffer(buffer));
this.featureCache.set(cacheKey, promise);
if (this.featureCache.getCount() > 2 * this.featureCache.highWaterMark) {
while (this.featureCache.canExpireCache()) {
this.featureCache.pop();
}
}
}
return promise;
}
readFeaturesFromBuffer(buffer) {
let options;
if (OL_VERSION <= '6.4.4') {
// See https://github.com/openlayers/openlayers/pull/11540
options = {
extent: [0, 0, 4096, 4096],
dataProjection: this.projection_,
featureProjection: this.projection_
};
}
const features = format.readFeatures(buffer, options);
const scaleFactor = this.tileWidth / 4096;
features.forEach((f) => {
const flatCoordinates = f.getFlatCoordinates();
let flip = false;
for (let i = 0; i < flatCoordinates.length; ++i) {
flatCoordinates[i] *= scaleFactor;
if (flip) {
// FIXME: why do we need this now?
flatCoordinates[i] = this.tileWidth - flatCoordinates[i];
}
if (OL_VERSION <= '6.4.4') {
// LEGACY
flip = !flip;
}
}
});
return features;
}
getUrl_(z, x, y) {
// FIXME: probably we should not pass 1 as pixelRatio
const url = this.tileFunction_([z, x, y], 1, this.projection_);
return url;
}
getCacheKey_(z, x, y) {
return `${z}_${x}_${y}`;
}
requestImage(x, y, z, request) {
if (z < this.minimumLevel_) {
return this.emptyCanvasPromise_;
}
try {
const cacheKey = this.getCacheKey_(z, x, y);
let promise;
if (this.tileCache.containsKey(cacheKey)) {
promise = this.tileCache.get(cacheKey);
}
if (!promise) {
promise = this.getTileFeatures(z, x, y)
.then((features) => {
// FIXME: here we suppose the 2D projection is in meters
this.tilingScheme.tileXYToNativeRectangle(x, y, z, this.tileRectangle_);
const resolution = (this.tileRectangle_.east - this.tileRectangle_.west) / this.tileWidth;
return this.rasterizeFeatures(features, this.styleFunction_, resolution);
});
this.tileCache.set(cacheKey, promise);
if (this.tileCache.getCount() > 2 * this.tileCache.highWaterMark) {
while (this.tileCache.canExpireCache()) {
this.tileCache.pop();
}
}
}
return promise;
}
catch (e) {
console.trace(e);
// FIXME: open PR on Cesium to fix incorrect typing
// @ts-ignore
this.errorEvent.raiseEvent('could not render pbf to tile', e);
}
}
rasterizeFeatures(features, styleFunction, resolution) {
const canvas = document.createElement('canvas');
const vectorContext = toContext(canvas.getContext('2d'), { size: [this.tileWidth, this.tileHeight] });
features.forEach((f) => {
const styles = styleFunction(f, resolution);
if (styles) {
if (Array.isArray(styles)) {
styles.forEach((style) => {
vectorContext.setStyle(style);
vectorContext.drawGeometry(f);
});
}
else {
vectorContext.setStyle(styles);
vectorContext.drawGeometry(f);
}
}
});
return canvas;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTVZUSW1hZ2VyeVByb3ZpZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL29sY3MvTVZUSW1hZ2VyeVByb3ZpZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sR0FBRyxNQUFNLGtCQUFrQixDQUFDO0FBQ25DLE9BQU8sS0FBSyxFQUFFLEVBQW9CLE1BQU0sbUJBQW1CLENBQUM7QUFDNUQsT0FBTyxNQUFNLE1BQU0sb0JBQW9CLENBQUM7QUFDeEMsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLGNBQWMsQ0FBQztBQUN2QyxPQUFPLEVBQUMsR0FBRyxJQUFJLGFBQWEsRUFBQyxNQUFNLFlBQVksQ0FBQztBQUNoRCxPQUFPLEVBQUMsT0FBTyxJQUFJLFVBQVUsRUFBQyxNQUFNLFlBQVksQ0FBQztBQUNqRCxPQUFPLFFBQVEsTUFBTSx3QkFBd0IsQ0FBQztBQUM5QyxPQUFPLEVBQUMsZ0JBQWdCLElBQUksd0JBQXdCLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUM1RSxPQUFPLEVBQUMsbUJBQW1CLElBQUksc0JBQXNCLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUdwRixPQUFPLGFBQWEsTUFBTSxzQkFBc0IsQ0FBQztBQUNqRCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQWEzRCxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsQ0FBQztJQUNyQixZQUFZLEVBQUUsYUFBYTtDQUM1QixDQUFDLENBQUM7QUFFSCxNQUFNLE1BQU0sR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDO1FBQ3hCLE1BQU0sRUFBRSxJQUFJLE1BQU0sQ0FBQztZQUNqQixLQUFLLEVBQUUsTUFBTTtZQUNiLEtBQUssRUFBRSxDQUFDO1NBQ1QsQ0FBQztLQUNILENBQUMsQ0FBQyxDQUFDO0FBR0osTUFBTSxDQUFDLE9BQU8sT0FBTyxrQkFBa0I7SUFDN0IsSUFBSSxDQUFXO0lBQ2YsWUFBWSxHQUFzQixpQkFBaUIsRUFB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