This commit is contained in:
335
node_modules/ol/src/source/BingMaps.js
generated
vendored
Normal file
335
node_modules/ol/src/source/BingMaps.js
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
/**
|
||||
* @module ol/source/BingMaps
|
||||
*/
|
||||
|
||||
import TileImage from './TileImage.js';
|
||||
import {applyTransform, intersects} from '../extent.js';
|
||||
import {createFromTileUrlFunctions} from '../tileurlfunction.js';
|
||||
import {createOrUpdate} from '../tilecoord.js';
|
||||
import {createXYZ, extentFromProjection} from '../tilegrid.js';
|
||||
import {get as getProjection, getTransformFromProjections} from '../proj.js';
|
||||
import {jsonp as requestJSONP} from '../net.js';
|
||||
|
||||
/**
|
||||
* @param {import('../tilecoord.js').TileCoord} tileCoord Tile coord.
|
||||
* @return {string} Quad key.
|
||||
*/
|
||||
export function quadKey(tileCoord) {
|
||||
const z = tileCoord[0];
|
||||
const digits = new Array(z);
|
||||
let mask = 1 << (z - 1);
|
||||
let i, charCode;
|
||||
for (i = 0; i < z; ++i) {
|
||||
// 48 is charCode for 0 - '0'.charCodeAt(0)
|
||||
charCode = 48;
|
||||
if (tileCoord[1] & mask) {
|
||||
charCode += 1;
|
||||
}
|
||||
if (tileCoord[2] & mask) {
|
||||
charCode += 2;
|
||||
}
|
||||
digits[i] = String.fromCharCode(charCode);
|
||||
mask >>= 1;
|
||||
}
|
||||
return digits.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* The attribution containing a link to the Microsoft® Bing™ Maps Platform APIs’
|
||||
* Terms Of Use.
|
||||
* @const
|
||||
* @type {string}
|
||||
*/
|
||||
const TOS_ATTRIBUTION =
|
||||
'<a class="ol-attribution-bing-tos" ' +
|
||||
'href="https://www.microsoft.com/maps/product/terms.html" target="_blank">' +
|
||||
'Terms of Use</a>';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {boolean} [hidpi=false] If `true` hidpi tiles will be requested.
|
||||
* @property {string} [culture='en-us'] Culture code.
|
||||
* @property {string} key Bing Maps API key. Get yours at https://www.bingmapsportal.com/.
|
||||
* @property {string} imagerySet Type of imagery.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {number} [maxZoom=21] Max zoom. Default is what's advertized by the BingMaps service.
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is
|
||||
* ```js
|
||||
* function(imageTile, src) {
|
||||
* imageTile.getImage().src = src;
|
||||
* };
|
||||
* ```
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* @property {number} [transition] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} BingMapsImageryMetadataResponse
|
||||
* @property {number} statusCode The response status code
|
||||
* @property {string} statusDescription The response status description
|
||||
* @property {string} authenticationResultCode The authentication result code
|
||||
* @property {Array<ResourceSet>} resourceSets The array of resource sets
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ResourceSet
|
||||
* @property {Array<Resource>} resources Resources.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Resource
|
||||
* @property {number} imageHeight The image height
|
||||
* @property {number} imageWidth The image width
|
||||
* @property {number} zoomMin The minimum zoom level
|
||||
* @property {number} zoomMax The maximum zoom level
|
||||
* @property {string} imageUrl The image URL
|
||||
* @property {Array<string>} imageUrlSubdomains The image URL subdomains for rotation
|
||||
* @property {Array<ImageryProvider>} [imageryProviders] The array of ImageryProviders
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ImageryProvider
|
||||
* @property {Array<CoverageArea>} coverageAreas The coverage areas
|
||||
* @property {string} [attribution] The attribution
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} CoverageArea
|
||||
* @property {number} zoomMin The minimum zoom
|
||||
* @property {number} zoomMax The maximum zoom
|
||||
* @property {Array<number>} bbox The coverage bounding box
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for Bing Maps tile data.
|
||||
* @api
|
||||
*/
|
||||
class BingMaps extends TileImage {
|
||||
/**
|
||||
* @param {Options} options Bing Maps options.
|
||||
*/
|
||||
constructor(options) {
|
||||
const hidpi = options.hidpi !== undefined ? options.hidpi : false;
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: 'anonymous',
|
||||
interpolate: interpolate,
|
||||
opaque: true,
|
||||
projection: getProjection('EPSG:3857'),
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
state: 'loading',
|
||||
tileLoadFunction: options.tileLoadFunction,
|
||||
tilePixelRatio: hidpi ? 2 : 1,
|
||||
wrapX: options.wrapX !== undefined ? options.wrapX : true,
|
||||
transition: options.transition,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hidpi_ = hidpi;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.culture_ = options.culture !== undefined ? options.culture : 'en-us';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxZoom_ = options.maxZoom !== undefined ? options.maxZoom : -1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.apiKey_ = options.key;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.imagerySet_ = options.imagerySet;
|
||||
|
||||
const url =
|
||||
'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' +
|
||||
this.imagerySet_ +
|
||||
'?uriScheme=https&include=ImageryProviders&key=' +
|
||||
this.apiKey_ +
|
||||
'&c=' +
|
||||
this.culture_;
|
||||
|
||||
requestJSONP(
|
||||
url,
|
||||
this.handleImageryMetadataResponse.bind(this),
|
||||
undefined,
|
||||
'jsonp'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the api key used for this source.
|
||||
*
|
||||
* @return {string} The api key.
|
||||
* @api
|
||||
*/
|
||||
getApiKey() {
|
||||
return this.apiKey_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the imagery set associated with this source.
|
||||
*
|
||||
* @return {string} The imagery set.
|
||||
* @api
|
||||
*/
|
||||
getImagerySet() {
|
||||
return this.imagerySet_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BingMapsImageryMetadataResponse} response Response.
|
||||
*/
|
||||
handleImageryMetadataResponse(response) {
|
||||
if (
|
||||
response.statusCode != 200 ||
|
||||
response.statusDescription != 'OK' ||
|
||||
response.authenticationResultCode != 'ValidCredentials' ||
|
||||
response.resourceSets.length != 1 ||
|
||||
response.resourceSets[0].resources.length != 1
|
||||
) {
|
||||
this.setState('error');
|
||||
return;
|
||||
}
|
||||
|
||||
const resource = response.resourceSets[0].resources[0];
|
||||
const maxZoom = this.maxZoom_ == -1 ? resource.zoomMax : this.maxZoom_;
|
||||
|
||||
const sourceProjection = this.getProjection();
|
||||
const extent = extentFromProjection(sourceProjection);
|
||||
const scale = this.hidpi_ ? 2 : 1;
|
||||
const tileSize =
|
||||
resource.imageWidth == resource.imageHeight
|
||||
? resource.imageWidth / scale
|
||||
: [resource.imageWidth / scale, resource.imageHeight / scale];
|
||||
|
||||
const tileGrid = createXYZ({
|
||||
extent: extent,
|
||||
minZoom: resource.zoomMin,
|
||||
maxZoom: maxZoom,
|
||||
tileSize: tileSize,
|
||||
});
|
||||
this.tileGrid = tileGrid;
|
||||
|
||||
const culture = this.culture_;
|
||||
const hidpi = this.hidpi_;
|
||||
this.tileUrlFunction = createFromTileUrlFunctions(
|
||||
resource.imageUrlSubdomains.map(function (subdomain) {
|
||||
/** @type {import('../tilecoord.js').TileCoord} */
|
||||
const quadKeyTileCoord = [0, 0, 0];
|
||||
const imageUrl = resource.imageUrl
|
||||
.replace('{subdomain}', subdomain)
|
||||
.replace('{culture}', culture);
|
||||
return (
|
||||
/**
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {string|undefined} Tile URL.
|
||||
*/
|
||||
function (tileCoord, pixelRatio, projection) {
|
||||
if (!tileCoord) {
|
||||
return undefined;
|
||||
} else {
|
||||
createOrUpdate(
|
||||
tileCoord[0],
|
||||
tileCoord[1],
|
||||
tileCoord[2],
|
||||
quadKeyTileCoord
|
||||
);
|
||||
let url = imageUrl;
|
||||
if (hidpi) {
|
||||
url += '&dpi=d1&device=mobile';
|
||||
}
|
||||
return url.replace('{quadkey}', quadKey(quadKeyTileCoord));
|
||||
}
|
||||
}
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
if (resource.imageryProviders) {
|
||||
const transform = getTransformFromProjections(
|
||||
getProjection('EPSG:4326'),
|
||||
this.getProjection()
|
||||
);
|
||||
|
||||
this.setAttributions(
|
||||
function (frameState) {
|
||||
const attributions = [];
|
||||
const viewState = frameState.viewState;
|
||||
const tileGrid = this.getTileGrid();
|
||||
const z = tileGrid.getZForResolution(
|
||||
viewState.resolution,
|
||||
this.zDirection
|
||||
);
|
||||
const tileCoord = tileGrid.getTileCoordForCoordAndZ(
|
||||
viewState.center,
|
||||
z
|
||||
);
|
||||
const zoom = tileCoord[0];
|
||||
resource.imageryProviders.map(function (imageryProvider) {
|
||||
let intersecting = false;
|
||||
const coverageAreas = imageryProvider.coverageAreas;
|
||||
for (let i = 0, ii = coverageAreas.length; i < ii; ++i) {
|
||||
const coverageArea = coverageAreas[i];
|
||||
if (
|
||||
zoom >= coverageArea.zoomMin &&
|
||||
zoom <= coverageArea.zoomMax
|
||||
) {
|
||||
const bbox = coverageArea.bbox;
|
||||
const epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]];
|
||||
const extent = applyTransform(epsg4326Extent, transform);
|
||||
if (intersects(extent, frameState.extent)) {
|
||||
intersecting = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intersecting) {
|
||||
attributions.push(imageryProvider.attribution);
|
||||
}
|
||||
});
|
||||
|
||||
attributions.push(TOS_ATTRIBUTION);
|
||||
return attributions;
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
this.setState('ready');
|
||||
}
|
||||
}
|
||||
|
||||
export default BingMaps;
|
||||
204
node_modules/ol/src/source/CartoDB.js
generated
vendored
Normal file
204
node_modules/ol/src/source/CartoDB.js
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* @module ol/source/CartoDB
|
||||
*/
|
||||
|
||||
import XYZ from './XYZ.js';
|
||||
import {assign} from '../obj.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Projection.
|
||||
* @property {number} [maxZoom=18] Max zoom.
|
||||
* @property {number} [minZoom] Minimum zoom.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* @property {Object} [config] If using anonymous maps, the CartoDB config to use. See
|
||||
* https://carto.com/developers/maps-api/guides/anonymous-maps/
|
||||
* for more detail.
|
||||
* If using named maps, a key-value lookup with the template parameters.
|
||||
* See https://carto.com/developers/maps-api/guides/named-maps/
|
||||
* for more detail.
|
||||
* @property {string} [map] If using named maps, this will be the name of the template to load.
|
||||
* See https://carto.com/developers/maps-api/guides/named-maps/
|
||||
* for more detail.
|
||||
* @property {string} [account] Username as used to access public Carto dashboard at https://{username}.carto.com/.
|
||||
* @property {number} [transition=250] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} CartoDBLayerInfo
|
||||
* @property {string} layergroupid The layer group ID
|
||||
* @property {{https: string}} cdn_url The CDN URL
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for the CartoDB Maps API.
|
||||
* @api
|
||||
*/
|
||||
class CartoDB extends XYZ {
|
||||
/**
|
||||
* @param {Options} options CartoDB options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: options.crossOrigin,
|
||||
maxZoom: options.maxZoom !== undefined ? options.maxZoom : 18,
|
||||
minZoom: options.minZoom,
|
||||
projection: options.projection,
|
||||
transition: options.transition,
|
||||
wrapX: options.wrapX,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.account_ = options.account;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.mapId_ = options.map || '';
|
||||
|
||||
/**
|
||||
* @type {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.config_ = options.config || {};
|
||||
|
||||
/**
|
||||
* @type {!Object<string, CartoDBLayerInfo>}
|
||||
* @private
|
||||
*/
|
||||
this.templateCache_ = {};
|
||||
|
||||
this.initializeMap_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current config.
|
||||
* @return {!Object} The current configuration.
|
||||
* @api
|
||||
*/
|
||||
getConfig() {
|
||||
return this.config_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the carto db config.
|
||||
* @param {Object} config a key-value lookup. Values will replace current values
|
||||
* in the config.
|
||||
* @api
|
||||
*/
|
||||
updateConfig(config) {
|
||||
assign(this.config_, config);
|
||||
this.initializeMap_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the CartoDB config
|
||||
* @param {Object} config In the case of anonymous maps, a CartoDB configuration
|
||||
* object.
|
||||
* If using named maps, a key-value lookup with the template parameters.
|
||||
* @api
|
||||
*/
|
||||
setConfig(config) {
|
||||
this.config_ = config || {};
|
||||
this.initializeMap_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue a request to initialize the CartoDB map.
|
||||
* @private
|
||||
*/
|
||||
initializeMap_() {
|
||||
const paramHash = JSON.stringify(this.config_);
|
||||
if (this.templateCache_[paramHash]) {
|
||||
this.applyTemplate_(this.templateCache_[paramHash]);
|
||||
return;
|
||||
}
|
||||
let mapUrl = 'https://' + this.account_ + '.carto.com/api/v1/map';
|
||||
|
||||
if (this.mapId_) {
|
||||
mapUrl += '/named/' + this.mapId_;
|
||||
}
|
||||
|
||||
const client = new XMLHttpRequest();
|
||||
client.addEventListener(
|
||||
'load',
|
||||
this.handleInitResponse_.bind(this, paramHash)
|
||||
);
|
||||
client.addEventListener('error', this.handleInitError_.bind(this));
|
||||
client.open('POST', mapUrl);
|
||||
client.setRequestHeader('Content-type', 'application/json');
|
||||
client.send(JSON.stringify(this.config_));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle map initialization response.
|
||||
* @param {string} paramHash a hash representing the parameter set that was used
|
||||
* for the request
|
||||
* @param {Event} event Event.
|
||||
* @private
|
||||
*/
|
||||
handleInitResponse_(paramHash, event) {
|
||||
const client = /** @type {XMLHttpRequest} */ (event.target);
|
||||
// status will be 0 for file:// urls
|
||||
if (!client.status || (client.status >= 200 && client.status < 300)) {
|
||||
let response;
|
||||
try {
|
||||
response = /** @type {CartoDBLayerInfo} */ (
|
||||
JSON.parse(client.responseText)
|
||||
);
|
||||
} catch (err) {
|
||||
this.setState('error');
|
||||
return;
|
||||
}
|
||||
this.applyTemplate_(response);
|
||||
this.templateCache_[paramHash] = response;
|
||||
this.setState('ready');
|
||||
} else {
|
||||
this.setState('error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event Event.
|
||||
*/
|
||||
handleInitError_(event) {
|
||||
this.setState('error');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the new tile urls returned by carto db
|
||||
* @param {CartoDBLayerInfo} data Result of carto db call.
|
||||
* @private
|
||||
*/
|
||||
applyTemplate_(data) {
|
||||
const tilesUrl =
|
||||
'https://' +
|
||||
data.cdn_url.https +
|
||||
'/' +
|
||||
this.account_ +
|
||||
'/api/v1/map/' +
|
||||
data.layergroupid +
|
||||
'/{z}/{x}/{y}.png';
|
||||
this.setUrl(tilesUrl);
|
||||
}
|
||||
}
|
||||
|
||||
export default CartoDB;
|
||||
328
node_modules/ol/src/source/Cluster.js
generated
vendored
Normal file
328
node_modules/ol/src/source/Cluster.js
generated
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
/**
|
||||
* @module ol/source/Cluster
|
||||
*/
|
||||
|
||||
import EventType from '../events/EventType.js';
|
||||
import Feature from '../Feature.js';
|
||||
import Point from '../geom/Point.js';
|
||||
import VectorSource from './Vector.js';
|
||||
import {add as addCoordinate, scale as scaleCoordinate} from '../coordinate.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {
|
||||
buffer,
|
||||
createEmpty,
|
||||
createOrUpdateFromCoordinate,
|
||||
getCenter,
|
||||
} from '../extent.js';
|
||||
import {getUid} from '../util.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {number} [distance=20] Distance in pixels within which features will
|
||||
* be clustered together.
|
||||
* @property {number} [minDistance=0] Minimum distance in pixels between clusters.
|
||||
* Will be capped at the configured distance.
|
||||
* By default no minimum distance is guaranteed. This config can be used to avoid
|
||||
* overlapping icons. As a tradoff, the cluster feature's position will no longer be
|
||||
* the center of all its features.
|
||||
* @property {function(Feature):Point} [geometryFunction]
|
||||
* Function that takes an {@link module:ol/Feature~Feature} as argument and returns an
|
||||
* {@link module:ol/geom/Point~Point} as cluster calculation point for the feature. When a
|
||||
* feature should not be considered for clustering, the function should return
|
||||
* `null`. The default, which works when the underlying source contains point
|
||||
* features only, is
|
||||
* ```js
|
||||
* function(feature) {
|
||||
* return feature.getGeometry();
|
||||
* }
|
||||
* ```
|
||||
* See {@link module:ol/geom/Polygon~Polygon#getInteriorPoint} for a way to get a cluster
|
||||
* calculation point for polygons.
|
||||
* @property {function(Point, Array<Feature>):Feature} [createCluster]
|
||||
* Function that takes the cluster's center {@link module:ol/geom/Point~Point} and an array
|
||||
* of {@link module:ol/Feature~Feature} included in this cluster. Must return a
|
||||
* {@link module:ol/Feature~Feature} that will be used to render. Default implementation is:
|
||||
* ```js
|
||||
* function(point, features) {
|
||||
* return new Feature({
|
||||
* geometry: point,
|
||||
* features: features
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
* @property {VectorSource} [source=null] Source.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source to cluster vector data. Works out of the box with point
|
||||
* geometries. For other geometry types, or if not all geometries should be
|
||||
* considered for clustering, a custom `geometryFunction` can be defined.
|
||||
*
|
||||
* If the instance is disposed without also disposing the underlying
|
||||
* source `setSource(null)` has to be called to remove the listener reference
|
||||
* from the wrapped source.
|
||||
* @api
|
||||
*/
|
||||
class Cluster extends VectorSource {
|
||||
/**
|
||||
* @param {Options} options Cluster options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
wrapX: options.wrapX,
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @protected
|
||||
*/
|
||||
this.resolution = undefined;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @protected
|
||||
*/
|
||||
this.distance = options.distance !== undefined ? options.distance : 20;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @protected
|
||||
*/
|
||||
this.minDistance = options.minDistance || 0;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @protected
|
||||
*/
|
||||
this.interpolationRatio = 0;
|
||||
|
||||
/**
|
||||
* @type {Array<Feature>}
|
||||
* @protected
|
||||
*/
|
||||
this.features = [];
|
||||
|
||||
/**
|
||||
* @param {Feature} feature Feature.
|
||||
* @return {Point} Cluster calculation point.
|
||||
* @protected
|
||||
*/
|
||||
this.geometryFunction =
|
||||
options.geometryFunction ||
|
||||
function (feature) {
|
||||
const geometry = /** @type {Point} */ (feature.getGeometry());
|
||||
assert(geometry.getType() == 'Point', 10); // The default `geometryFunction` can only handle `Point` geometries
|
||||
return geometry;
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {function(Point, Array<Feature>):Feature}
|
||||
* @private
|
||||
*/
|
||||
this.createCustomCluster_ = options.createCluster;
|
||||
|
||||
/**
|
||||
* @type {VectorSource|null}
|
||||
* @protected
|
||||
*/
|
||||
this.source = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this.boundRefresh_ = this.refresh.bind(this);
|
||||
|
||||
this.updateDistance(this.distance, this.minDistance);
|
||||
this.setSource(options.source || null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all features from the source.
|
||||
* @param {boolean} [opt_fast] Skip dispatching of {@link module:ol/source/VectorEventType~VectorEventType#removefeature} events.
|
||||
* @api
|
||||
*/
|
||||
clear(opt_fast) {
|
||||
this.features.length = 0;
|
||||
super.clear(opt_fast);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance in pixels between clusters.
|
||||
* @return {number} Distance.
|
||||
* @api
|
||||
*/
|
||||
getDistance() {
|
||||
return this.distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the wrapped source.
|
||||
* @return {VectorSource|null} Source.
|
||||
* @api
|
||||
*/
|
||||
getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
*/
|
||||
loadFeatures(extent, resolution, projection) {
|
||||
this.source.loadFeatures(extent, resolution, projection);
|
||||
if (resolution !== this.resolution) {
|
||||
this.resolution = resolution;
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the distance within which features will be clusterd together.
|
||||
* @param {number} distance The distance in pixels.
|
||||
* @api
|
||||
*/
|
||||
setDistance(distance) {
|
||||
this.updateDistance(distance, this.minDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum distance between clusters. Will be capped at the
|
||||
* configured distance.
|
||||
* @param {number} minDistance The minimum distance in pixels.
|
||||
* @api
|
||||
*/
|
||||
setMinDistance(minDistance) {
|
||||
this.updateDistance(this.distance, minDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* The configured minimum distance between clusters.
|
||||
* @return {number} The minimum distance in pixels.
|
||||
* @api
|
||||
*/
|
||||
getMinDistance() {
|
||||
return this.minDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the wrapped source.
|
||||
* @param {VectorSource|null} source The new source for this instance.
|
||||
* @api
|
||||
*/
|
||||
setSource(source) {
|
||||
if (this.source) {
|
||||
this.source.removeEventListener(EventType.CHANGE, this.boundRefresh_);
|
||||
}
|
||||
this.source = source;
|
||||
if (source) {
|
||||
source.addEventListener(EventType.CHANGE, this.boundRefresh_);
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the source changing.
|
||||
*/
|
||||
refresh() {
|
||||
this.clear();
|
||||
this.cluster();
|
||||
this.addFeatures(this.features);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the distances and refresh the source if necessary.
|
||||
* @param {number} distance The new distance.
|
||||
* @param {number} minDistance The new minimum distance.
|
||||
*/
|
||||
updateDistance(distance, minDistance) {
|
||||
const ratio =
|
||||
distance === 0 ? 0 : Math.min(minDistance, distance) / distance;
|
||||
const changed =
|
||||
distance !== this.distance || this.interpolationRatio !== ratio;
|
||||
this.distance = distance;
|
||||
this.minDistance = minDistance;
|
||||
this.interpolationRatio = ratio;
|
||||
if (changed) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
cluster() {
|
||||
if (this.resolution === undefined || !this.source) {
|
||||
return;
|
||||
}
|
||||
const extent = createEmpty();
|
||||
const mapDistance = this.distance * this.resolution;
|
||||
const features = this.source.getFeatures();
|
||||
|
||||
/** @type {Object<string, true>} */
|
||||
const clustered = {};
|
||||
|
||||
for (let i = 0, ii = features.length; i < ii; i++) {
|
||||
const feature = features[i];
|
||||
if (!(getUid(feature) in clustered)) {
|
||||
const geometry = this.geometryFunction(feature);
|
||||
if (geometry) {
|
||||
const coordinates = geometry.getCoordinates();
|
||||
createOrUpdateFromCoordinate(coordinates, extent);
|
||||
buffer(extent, mapDistance, extent);
|
||||
|
||||
const neighbors = this.source
|
||||
.getFeaturesInExtent(extent)
|
||||
.filter(function (neighbor) {
|
||||
const uid = getUid(neighbor);
|
||||
if (uid in clustered) {
|
||||
return false;
|
||||
}
|
||||
clustered[uid] = true;
|
||||
return true;
|
||||
});
|
||||
this.features.push(this.createCluster(neighbors, extent));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<Feature>} features Features
|
||||
* @param {import("../extent.js").Extent} extent The searched extent for these features.
|
||||
* @return {Feature} The cluster feature.
|
||||
* @protected
|
||||
*/
|
||||
createCluster(features, extent) {
|
||||
const centroid = [0, 0];
|
||||
for (let i = features.length - 1; i >= 0; --i) {
|
||||
const geometry = this.geometryFunction(features[i]);
|
||||
if (geometry) {
|
||||
addCoordinate(centroid, geometry.getCoordinates());
|
||||
} else {
|
||||
features.splice(i, 1);
|
||||
}
|
||||
}
|
||||
scaleCoordinate(centroid, 1 / features.length);
|
||||
const searchCenter = getCenter(extent);
|
||||
const ratio = this.interpolationRatio;
|
||||
const geometry = new Point([
|
||||
centroid[0] * (1 - ratio) + searchCenter[0] * ratio,
|
||||
centroid[1] * (1 - ratio) + searchCenter[1] * ratio,
|
||||
]);
|
||||
if (this.createCustomCluster_) {
|
||||
return this.createCustomCluster_(geometry, features);
|
||||
} else {
|
||||
return new Feature({
|
||||
geometry,
|
||||
features,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Cluster;
|
||||
244
node_modules/ol/src/source/DataTile.js
generated
vendored
Normal file
244
node_modules/ol/src/source/DataTile.js
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* @module ol/source/DataTile
|
||||
*/
|
||||
import DataTile from '../DataTile.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import TileEventType from './TileEventType.js';
|
||||
import TileSource, {TileSourceEvent} from './Tile.js';
|
||||
import TileState from '../TileState.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {createXYZ, extentFromProjection} from '../tilegrid.js';
|
||||
import {getKeyZXY} from '../tilecoord.js';
|
||||
import {getUid} from '../util.js';
|
||||
import {toPromise} from '../functions.js';
|
||||
import {toSize} from '../size.js';
|
||||
|
||||
/**
|
||||
* Data tile loading function. The function is called with z, x, and y tile coordinates and
|
||||
* returns {@link import("../DataTile.js").Data data} for a tile or a promise for the same.
|
||||
* @typedef {function(number, number, number) : (import("../DataTile.js").Data|Promise<import("../DataTile.js").Data>)} Loader
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {Loader} [loader] Data loader. Called with z, x, and y tile coordinates.
|
||||
* Returns {@link import("../DataTile.js").Data data} for a tile or a promise for the same.
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {number} [maxZoom=42] Optional max zoom level. Not used if `tileGrid` is provided.
|
||||
* @property {number} [minZoom=0] Optional min zoom level. Not used if `tileGrid` is provided.
|
||||
* @property {number|import("../size.js").Size} [tileSize=[256, 256]] The pixel width and height of the source tiles.
|
||||
* This may be different than the rendered pixel size if a `tileGrid` is provided.
|
||||
* @property {number} [gutter=0] The size in pixels of the gutter around data tiles to ignore.
|
||||
* This allows artifacts of rendering at tile edges to be ignored.
|
||||
* Supported data should be wider and taller than the tile size by a value of `2 x gutter`.
|
||||
* @property {number} [maxResolution] Optional tile grid resolution at level zero. Not used if `tileGrid` is provided.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Tile projection.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
|
||||
* @property {boolean} [opaque=false] Whether the layer is opaque.
|
||||
* @property {import("./Source.js").State} [state] The source state.
|
||||
* @property {number} [tilePixelRatio] Deprecated. To have tiles scaled, pass a `tileSize` representing
|
||||
* the source tile size and a `tileGrid` with the desired rendered tile size.
|
||||
* @property {boolean} [wrapX=false] Render tiles beyond the antimeridian.
|
||||
* @property {number} [transition] Transition time when fading in new tiles (in miliseconds).
|
||||
* @property {number} [bandCount=4] Number of bands represented in the data.
|
||||
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||
* the nearest neighbor is used when resampling.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A source for typed array data tiles.
|
||||
*
|
||||
* @fires import("./Tile.js").TileSourceEvent
|
||||
* @api
|
||||
*/
|
||||
class DataTileSource extends TileSource {
|
||||
/**
|
||||
* @param {Options} options Image tile options.
|
||||
*/
|
||||
constructor(options) {
|
||||
const projection =
|
||||
options.projection === undefined ? 'EPSG:3857' : options.projection;
|
||||
|
||||
let tileGrid = options.tileGrid;
|
||||
if (tileGrid === undefined && projection) {
|
||||
tileGrid = createXYZ({
|
||||
extent: extentFromProjection(projection),
|
||||
maxResolution: options.maxResolution,
|
||||
maxZoom: options.maxZoom,
|
||||
minZoom: options.minZoom,
|
||||
tileSize: options.tileSize,
|
||||
});
|
||||
}
|
||||
|
||||
super({
|
||||
cacheSize: 0.1, // don't cache on the source
|
||||
attributions: options.attributions,
|
||||
attributionsCollapsible: options.attributionsCollapsible,
|
||||
projection: projection,
|
||||
tileGrid: tileGrid,
|
||||
opaque: options.opaque,
|
||||
state: options.state,
|
||||
tilePixelRatio: options.tilePixelRatio,
|
||||
wrapX: options.wrapX,
|
||||
transition: options.transition,
|
||||
interpolate: options.interpolate,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.gutter_ = options.gutter !== undefined ? options.gutter : 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import('../size.js').Size|null}
|
||||
*/
|
||||
this.tileSize_ = options.tileSize ? toSize(options.tileSize) : null;
|
||||
if (!this.tileSize_ && options.tilePixelRatio && tileGrid) {
|
||||
const renderTileSize = toSize(tileGrid.getTileSize(0));
|
||||
this.tileSize_ = [
|
||||
renderTileSize[0] * options.tilePixelRatio,
|
||||
renderTileSize[1] * options.tilePixelRatio,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<import('../size.js').Size>|null}
|
||||
*/
|
||||
this.tileSizes_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object<string, boolean>}
|
||||
*/
|
||||
this.tileLoadingKeys_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this.loader_ = options.loader;
|
||||
|
||||
this.handleTileChange_ = this.handleTileChange_.bind(this);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.bandCount = options.bandCount === undefined ? 4 : options.bandCount; // assume RGBA if undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source tile sizes. The length of the array is expected to match the number of
|
||||
* levels in the tile grid.
|
||||
* @protected
|
||||
* @param {Array<import('../size.js').Size>} tileSizes An array of tile sizes.
|
||||
*/
|
||||
setTileSizes(tileSizes) {
|
||||
this.tileSizes_ = tileSizes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source tile size at the given zoom level. This may be different than the rendered tile
|
||||
* size.
|
||||
* @protected
|
||||
* @param {number} z Tile zoom level.
|
||||
* @return {import('../size.js').Size} The source tile size.
|
||||
*/
|
||||
getTileSize(z) {
|
||||
if (this.tileSizes_) {
|
||||
return this.tileSizes_[z];
|
||||
}
|
||||
if (this.tileSize_) {
|
||||
return this.tileSize_;
|
||||
}
|
||||
const tileGrid = this.getTileGrid();
|
||||
return tileGrid ? toSize(tileGrid.getTileSize(z)) : [256, 256];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {number} Gutter.
|
||||
*/
|
||||
getGutterForProjection(projection) {
|
||||
return this.gutter_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Loader} loader The data loader.
|
||||
* @protected
|
||||
*/
|
||||
setLoader(loader) {
|
||||
this.loader_ = loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {!DataTile} Tile.
|
||||
*/
|
||||
getTile(z, x, y, pixelRatio, projection) {
|
||||
const size = this.getTileSize(z);
|
||||
const tileCoordKey = getKeyZXY(z, x, y);
|
||||
if (this.tileCache.containsKey(tileCoordKey)) {
|
||||
return this.tileCache.get(tileCoordKey);
|
||||
}
|
||||
|
||||
const sourceLoader = this.loader_;
|
||||
|
||||
function loader() {
|
||||
return toPromise(function () {
|
||||
return sourceLoader(z, x, y);
|
||||
});
|
||||
}
|
||||
|
||||
const options = assign(
|
||||
{
|
||||
tileCoord: [z, x, y],
|
||||
loader: loader,
|
||||
size: size,
|
||||
},
|
||||
this.tileOptions
|
||||
);
|
||||
|
||||
const tile = new DataTile(options);
|
||||
tile.key = this.getKey();
|
||||
tile.addEventListener(EventType.CHANGE, this.handleTileChange_);
|
||||
|
||||
this.tileCache.set(tileCoordKey, tile);
|
||||
return tile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle tile change events.
|
||||
* @param {import("../events/Event.js").default} event Event.
|
||||
*/
|
||||
handleTileChange_(event) {
|
||||
const tile = /** @type {import("../Tile.js").default} */ (event.target);
|
||||
const uid = getUid(tile);
|
||||
const tileState = tile.getState();
|
||||
let type;
|
||||
if (tileState == TileState.LOADING) {
|
||||
this.tileLoadingKeys_[uid] = true;
|
||||
type = TileEventType.TILELOADSTART;
|
||||
} else if (uid in this.tileLoadingKeys_) {
|
||||
delete this.tileLoadingKeys_[uid];
|
||||
type =
|
||||
tileState == TileState.ERROR
|
||||
? TileEventType.TILELOADERROR
|
||||
: tileState == TileState.LOADED
|
||||
? TileEventType.TILELOADEND
|
||||
: undefined;
|
||||
}
|
||||
if (type) {
|
||||
this.dispatchEvent(new TileSourceEvent(type, tile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DataTileSource;
|
||||
840
node_modules/ol/src/source/GeoTIFF.js
generated
vendored
Normal file
840
node_modules/ol/src/source/GeoTIFF.js
generated
vendored
Normal file
@@ -0,0 +1,840 @@
|
||||
/**
|
||||
* @module ol/source/GeoTIFF
|
||||
*/
|
||||
import DataTile from './DataTile.js';
|
||||
import TileGrid from '../tilegrid/TileGrid.js';
|
||||
import {
|
||||
Pool,
|
||||
fromBlob as tiffFromBlob,
|
||||
fromUrl as tiffFromUrl,
|
||||
fromUrls as tiffFromUrls,
|
||||
} from 'geotiff';
|
||||
import {
|
||||
Projection,
|
||||
get as getCachedProjection,
|
||||
toUserCoordinate,
|
||||
toUserExtent,
|
||||
} from '../proj.js';
|
||||
import {clamp} from '../math.js';
|
||||
import {getCenter, getIntersection} from '../extent.js';
|
||||
import {fromCode as unitsFromCode} from '../proj/Units.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} SourceInfo
|
||||
* @property {string} [url] URL for the source GeoTIFF.
|
||||
* @property {Array<string>} [overviews] List of any overview URLs, only applies if the url parameter is given.
|
||||
* @property {Blob} [blob] Blob containing the source GeoTIFF. `blob` and `url` are mutually exclusive.
|
||||
* @property {number} [min=0] The minimum source data value. Rendered values are scaled from 0 to 1 based on
|
||||
* the configured min and max. If not provided and raster statistics are available, those will be used instead.
|
||||
* If neither are available, the minimum for the data type will be used. To disable this behavior, set
|
||||
* the `normalize` option to `false` in the constructor.
|
||||
* @property {number} [max] The maximum source data value. Rendered values are scaled from 0 to 1 based on
|
||||
* the configured min and max. If not provided and raster statistics are available, those will be used instead.
|
||||
* If neither are available, the maximum for the data type will be used. To disable this behavior, set
|
||||
* the `normalize` option to `false` in the constructor.
|
||||
* @property {number} [nodata] Values to discard (overriding any nodata values in the metadata).
|
||||
* When provided, an additional alpha band will be added to the data. Often the GeoTIFF metadata
|
||||
* will include information about nodata values, so you should only need to set this property if
|
||||
* you find that it is not already extracted from the metadata.
|
||||
* @property {Array<number>} [bands] Band numbers to be read from (where the first band is `1`). If not provided, all bands will
|
||||
* be read. For example, if a GeoTIFF has blue (1), green (2), red (3), and near-infrared (4) bands, and you only need the
|
||||
* near-infrared band, configure `bands: [4]`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} GeoKeys
|
||||
* @property {number} GTModelTypeGeoKey Model type.
|
||||
* @property {number} GTRasterTypeGeoKey Raster type.
|
||||
* @property {number} GeogAngularUnitsGeoKey Angular units.
|
||||
* @property {number} GeogInvFlatteningGeoKey Inverse flattening.
|
||||
* @property {number} GeogSemiMajorAxisGeoKey Semi-major axis.
|
||||
* @property {number} GeographicTypeGeoKey Geographic coordinate system code.
|
||||
* @property {number} ProjLinearUnitsGeoKey Projected linear unit code.
|
||||
* @property {number} ProjectedCSTypeGeoKey Projected coordinate system code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {import("geotiff").GeoTIFF} GeoTIFF
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {import("geotiff").MultiGeoTIFF} MultiGeoTIFF
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} GDALMetadata
|
||||
* @property {string} STATISTICS_MINIMUM The minimum value (as a string).
|
||||
* @property {string} STATISTICS_MAXIMUM The maximum value (as a string).
|
||||
*/
|
||||
|
||||
const STATISTICS_MAXIMUM = 'STATISTICS_MAXIMUM';
|
||||
const STATISTICS_MINIMUM = 'STATISTICS_MINIMUM';
|
||||
|
||||
/**
|
||||
* @typedef {import("geotiff").GeoTIFFImage} GeoTIFFImage
|
||||
*/
|
||||
|
||||
let workerPool;
|
||||
function getWorkerPool() {
|
||||
if (!workerPool) {
|
||||
workerPool = new Pool();
|
||||
}
|
||||
return workerPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bounding box of an image. If the image does not have an affine transform,
|
||||
* the pixel bounds are returned.
|
||||
* @param {GeoTIFFImage} image The image.
|
||||
* @return {Array<number>} The image bounding box.
|
||||
*/
|
||||
function getBoundingBox(image) {
|
||||
try {
|
||||
return image.getBoundingBox();
|
||||
} catch (_) {
|
||||
const fileDirectory = image.fileDirectory;
|
||||
return [0, 0, fileDirectory.ImageWidth, fileDirectory.ImageLength];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the origin of an image. If the image does not have an affine transform,
|
||||
* the top-left corner of the pixel bounds is returned.
|
||||
* @param {GeoTIFFImage} image The image.
|
||||
* @return {Array<number>} The image origin.
|
||||
*/
|
||||
function getOrigin(image) {
|
||||
try {
|
||||
return image.getOrigin().slice(0, 2);
|
||||
} catch (_) {
|
||||
return [0, image.fileDirectory.ImageLength];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resolution of an image. If the image does not have an affine transform,
|
||||
* the width of the image is compared with the reference image.
|
||||
* @param {GeoTIFFImage} image The image.
|
||||
* @param {GeoTIFFImage} referenceImage The reference image.
|
||||
* @return {Array<number>} The map x and y units per pixel.
|
||||
*/
|
||||
function getResolutions(image, referenceImage) {
|
||||
try {
|
||||
return image.getResolution(referenceImage);
|
||||
} catch (_) {
|
||||
return [
|
||||
referenceImage.fileDirectory.ImageWidth / image.fileDirectory.ImageWidth,
|
||||
referenceImage.fileDirectory.ImageHeight /
|
||||
image.fileDirectory.ImageHeight,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GeoTIFFImage} image A GeoTIFF.
|
||||
* @return {import("../proj/Projection.js").default} The image projection.
|
||||
*/
|
||||
function getProjection(image) {
|
||||
const geoKeys = image.geoKeys;
|
||||
if (!geoKeys) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (geoKeys.ProjectedCSTypeGeoKey) {
|
||||
const code = 'EPSG:' + geoKeys.ProjectedCSTypeGeoKey;
|
||||
let projection = getCachedProjection(code);
|
||||
if (!projection) {
|
||||
const units = unitsFromCode(geoKeys.ProjLinearUnitsGeoKey);
|
||||
if (units) {
|
||||
projection = new Projection({
|
||||
code: code,
|
||||
units: units,
|
||||
});
|
||||
}
|
||||
}
|
||||
return projection;
|
||||
}
|
||||
|
||||
if (geoKeys.GeographicTypeGeoKey) {
|
||||
const code = 'EPSG:' + geoKeys.GeographicTypeGeoKey;
|
||||
let projection = getCachedProjection(code);
|
||||
if (!projection) {
|
||||
const units = unitsFromCode(geoKeys.GeogAngularUnitsGeoKey);
|
||||
if (units) {
|
||||
projection = new Projection({
|
||||
code: code,
|
||||
units: units,
|
||||
});
|
||||
}
|
||||
}
|
||||
return projection;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GeoTIFF|MultiGeoTIFF} tiff A GeoTIFF.
|
||||
* @return {Promise<Array<GeoTIFFImage>>} Resolves to a list of images.
|
||||
*/
|
||||
function getImagesForTIFF(tiff) {
|
||||
return tiff.getImageCount().then(function (count) {
|
||||
const requests = new Array(count);
|
||||
for (let i = 0; i < count; ++i) {
|
||||
requests[i] = tiff.getImage(i);
|
||||
}
|
||||
return Promise.all(requests);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SourceInfo} source The GeoTIFF source.
|
||||
* @param {Object} options Options for the GeoTIFF source.
|
||||
* @return {Promise<Array<GeoTIFFImage>>} Resolves to a list of images.
|
||||
*/
|
||||
function getImagesForSource(source, options) {
|
||||
let request;
|
||||
if (source.blob) {
|
||||
request = tiffFromBlob(source.blob);
|
||||
} else if (source.overviews) {
|
||||
request = tiffFromUrls(source.url, source.overviews, options);
|
||||
} else {
|
||||
request = tiffFromUrl(source.url, options);
|
||||
}
|
||||
return request.then(getImagesForTIFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number|Array<number>|Array<Array<number>>} expected Expected value.
|
||||
* @param {number|Array<number>|Array<Array<number>>} got Actual value.
|
||||
* @param {number} tolerance Accepted tolerance in fraction of expected between expected and got.
|
||||
* @param {string} message The error message.
|
||||
* @param {function(Error):void} rejector A function to be called with any error.
|
||||
*/
|
||||
function assertEqual(expected, got, tolerance, message, rejector) {
|
||||
if (Array.isArray(expected)) {
|
||||
const length = expected.length;
|
||||
if (!Array.isArray(got) || length != got.length) {
|
||||
const error = new Error(message);
|
||||
rejector(error);
|
||||
throw error;
|
||||
}
|
||||
for (let i = 0; i < length; ++i) {
|
||||
assertEqual(expected[i], got[i], tolerance, message, rejector);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
got = /** @type {number} */ (got);
|
||||
if (Math.abs(expected - got) > tolerance * expected) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} array The data array.
|
||||
* @return {number} The minimum value.
|
||||
*/
|
||||
function getMinForDataType(array) {
|
||||
if (array instanceof Int8Array) {
|
||||
return -128;
|
||||
}
|
||||
if (array instanceof Int16Array) {
|
||||
return -32768;
|
||||
}
|
||||
if (array instanceof Int32Array) {
|
||||
return -2147483648;
|
||||
}
|
||||
if (array instanceof Float32Array) {
|
||||
return 1.2e-38;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} array The data array.
|
||||
* @return {number} The maximum value.
|
||||
*/
|
||||
function getMaxForDataType(array) {
|
||||
if (array instanceof Int8Array) {
|
||||
return 127;
|
||||
}
|
||||
if (array instanceof Uint8Array) {
|
||||
return 255;
|
||||
}
|
||||
if (array instanceof Uint8ClampedArray) {
|
||||
return 255;
|
||||
}
|
||||
if (array instanceof Int16Array) {
|
||||
return 32767;
|
||||
}
|
||||
if (array instanceof Uint16Array) {
|
||||
return 65535;
|
||||
}
|
||||
if (array instanceof Int32Array) {
|
||||
return 2147483647;
|
||||
}
|
||||
if (array instanceof Uint32Array) {
|
||||
return 4294967295;
|
||||
}
|
||||
if (array instanceof Float32Array) {
|
||||
return 3.4e38;
|
||||
}
|
||||
return 255;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} GeoTIFFSourceOptions
|
||||
* @property {boolean} [forceXHR=false] Whether to force the usage of the browsers XMLHttpRequest API.
|
||||
* @property {Object<string, string>} [headers] additional key-value pairs of headers to be passed with each request. Key is the header name, value the header value.
|
||||
* @property {string} [credentials] How credentials shall be handled. See
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/fetch for reference and possible values
|
||||
* @property {number} [maxRanges] The maximum amount of ranges to request in a single multi-range request.
|
||||
* By default only a single range is used.
|
||||
* @property {boolean} [allowFullFile=false] Whether or not a full file is accepted when only a portion is
|
||||
* requested. Only use this when you know the source image to be small enough to fit in memory.
|
||||
* @property {number} [blockSize=65536] The block size to use.
|
||||
* @property {number} [cacheSize=100] The number of blocks that shall be held in a LRU cache.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {Array<SourceInfo>} sources List of information about GeoTIFF sources.
|
||||
* Multiple sources can be combined when their resolution sets are equal after applying a scale.
|
||||
* The list of sources defines a mapping between input bands as they are read from each GeoTIFF and
|
||||
* the output bands that are provided by data tiles. To control which bands to read from each GeoTIFF,
|
||||
* use the {@link import("./GeoTIFF.js").SourceInfo bands} property. If, for example, you specify two
|
||||
* sources, one with 3 bands and {@link import("./GeoTIFF.js").SourceInfo nodata} configured, and
|
||||
* another with 1 band, the resulting data tiles will have 5 bands: 3 from the first source, 1 alpha
|
||||
* band from the first source, and 1 band from the second source.
|
||||
* @property {GeoTIFFSourceOptions} [sourceOptions] Additional options to be passed to [geotiff.js](https://geotiffjs.github.io/geotiff.js/module-geotiff.html)'s `fromUrl` or `fromUrls` methods.
|
||||
* @property {boolean} [convertToRGB = false] By default, bands from the sources are read as-is. When
|
||||
* reading GeoTIFFs with the purpose of displaying them as RGB images, setting this to `true` will
|
||||
* convert other color spaces (YCbCr, CMYK) to RGB.
|
||||
* @property {boolean} [normalize=true] By default, the source data is normalized to values between
|
||||
* 0 and 1 with scaling factors based on the raster statistics or `min` and `max` properties of each source.
|
||||
* If instead you want to work with the raw values in a style expression, set this to `false`. Setting this option
|
||||
* to `false` will make it so any `min` and `max` properties on sources are ignored.
|
||||
* @property {boolean} [opaque=false] Whether the layer is opaque.
|
||||
* @property {number} [transition=250] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {boolean} [wrapX=false] Render tiles beyond the tile grid extent.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* the linear interpolation is used to resample the data. If false, nearest neighbor is used.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A source for working with GeoTIFF data.
|
||||
* @api
|
||||
*/
|
||||
class GeoTIFFSource extends DataTile {
|
||||
/**
|
||||
* @param {Options} options Data tile options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super({
|
||||
state: 'loading',
|
||||
tileGrid: null,
|
||||
projection: null,
|
||||
opaque: options.opaque,
|
||||
transition: options.transition,
|
||||
interpolate: options.interpolate !== false,
|
||||
wrapX: options.wrapX,
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {Array<SourceInfo>}
|
||||
* @private
|
||||
*/
|
||||
this.sourceInfo_ = options.sources;
|
||||
|
||||
const numSources = this.sourceInfo_.length;
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this.sourceOptions_ = options.sourceOptions;
|
||||
|
||||
/**
|
||||
* @type {Array<Array<GeoTIFFImage>>}
|
||||
* @private
|
||||
*/
|
||||
this.sourceImagery_ = new Array(numSources);
|
||||
|
||||
/**
|
||||
* @type {Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.resolutionFactors_ = new Array(numSources);
|
||||
|
||||
/**
|
||||
* @type {Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.samplesPerPixel_;
|
||||
|
||||
/**
|
||||
* @type {Array<Array<number>>}
|
||||
* @private
|
||||
*/
|
||||
this.nodataValues_;
|
||||
|
||||
/**
|
||||
* @type {Array<Array<GDALMetadata>>}
|
||||
* @private
|
||||
*/
|
||||
this.metadata_;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.normalize_ = options.normalize !== false;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.addAlpha_ = false;
|
||||
|
||||
/**
|
||||
* @type {Error}
|
||||
* @private
|
||||
*/
|
||||
this.error_ = null;
|
||||
|
||||
/**
|
||||
* @type {'readRasters' | 'readRGB'}
|
||||
*/
|
||||
this.readMethod_ = options.convertToRGB ? 'readRGB' : 'readRasters';
|
||||
|
||||
this.setKey(this.sourceInfo_.map((source) => source.url).join(','));
|
||||
|
||||
const self = this;
|
||||
const requests = new Array(numSources);
|
||||
for (let i = 0; i < numSources; ++i) {
|
||||
requests[i] = getImagesForSource(
|
||||
this.sourceInfo_[i],
|
||||
this.sourceOptions_
|
||||
);
|
||||
}
|
||||
Promise.all(requests)
|
||||
.then(function (sources) {
|
||||
self.configure_(sources);
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
self.error_ = error;
|
||||
self.setState('error');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Error} A source loading error. When the source state is `error`, use this function
|
||||
* to get more information about the error. To debug a faulty configuration, you may want to use
|
||||
* a listener like
|
||||
* ```js
|
||||
* geotiffSource.on('change', () => {
|
||||
* if (geotiffSource.getState() === 'error') {
|
||||
* console.error(geotiffSource.getError());
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
getError() {
|
||||
return this.error_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the tile grid based on images within the source GeoTIFFs. Each GeoTIFF
|
||||
* must have the same internal tiled structure.
|
||||
* @param {Array<Array<GeoTIFFImage>>} sources Each source is a list of images
|
||||
* from a single GeoTIFF.
|
||||
* @private
|
||||
*/
|
||||
configure_(sources) {
|
||||
let extent;
|
||||
let origin;
|
||||
let commonRenderTileSizes;
|
||||
let commonSourceTileSizes;
|
||||
let resolutions;
|
||||
const samplesPerPixel = new Array(sources.length);
|
||||
const nodataValues = new Array(sources.length);
|
||||
const metadata = new Array(sources.length);
|
||||
let minZoom = 0;
|
||||
|
||||
const sourceCount = sources.length;
|
||||
for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
|
||||
const images = sources[sourceIndex];
|
||||
const imageCount = images.length;
|
||||
|
||||
let sourceExtent;
|
||||
let sourceOrigin;
|
||||
const sourceTileSizes = new Array(imageCount);
|
||||
const renderTileSizes = new Array(imageCount);
|
||||
const sourceResolutions = new Array(imageCount);
|
||||
|
||||
nodataValues[sourceIndex] = new Array(imageCount);
|
||||
metadata[sourceIndex] = new Array(imageCount);
|
||||
|
||||
for (let imageIndex = 0; imageIndex < imageCount; ++imageIndex) {
|
||||
const image = images[imageIndex];
|
||||
const nodataValue = image.getGDALNoData();
|
||||
metadata[sourceIndex][imageIndex] = image.getGDALMetadata(0);
|
||||
nodataValues[sourceIndex][imageIndex] = nodataValue;
|
||||
|
||||
const wantedSamples = this.sourceInfo_[sourceIndex].bands;
|
||||
samplesPerPixel[sourceIndex] = wantedSamples
|
||||
? wantedSamples.length
|
||||
: image.getSamplesPerPixel();
|
||||
const level = imageCount - (imageIndex + 1);
|
||||
|
||||
if (!sourceExtent) {
|
||||
sourceExtent = getBoundingBox(image);
|
||||
}
|
||||
|
||||
if (!sourceOrigin) {
|
||||
sourceOrigin = getOrigin(image);
|
||||
}
|
||||
|
||||
const imageResolutions = getResolutions(image, images[0]);
|
||||
sourceResolutions[level] = imageResolutions[0];
|
||||
|
||||
const sourceTileSize = [image.getTileWidth(), image.getTileHeight()];
|
||||
sourceTileSizes[level] = sourceTileSize;
|
||||
|
||||
const aspectRatio = imageResolutions[0] / Math.abs(imageResolutions[1]);
|
||||
renderTileSizes[level] = [
|
||||
sourceTileSize[0],
|
||||
sourceTileSize[1] / aspectRatio,
|
||||
];
|
||||
}
|
||||
|
||||
if (!extent) {
|
||||
extent = sourceExtent;
|
||||
} else {
|
||||
getIntersection(extent, sourceExtent, extent);
|
||||
}
|
||||
|
||||
if (!origin) {
|
||||
origin = sourceOrigin;
|
||||
} else {
|
||||
const message = `Origin mismatch for source ${sourceIndex}, got [${sourceOrigin}] but expected [${origin}]`;
|
||||
assertEqual(origin, sourceOrigin, 0, message, this.viewRejector);
|
||||
}
|
||||
|
||||
if (!resolutions) {
|
||||
resolutions = sourceResolutions;
|
||||
this.resolutionFactors_[sourceIndex] = 1;
|
||||
} else {
|
||||
if (resolutions.length - minZoom > sourceResolutions.length) {
|
||||
minZoom = resolutions.length - sourceResolutions.length;
|
||||
}
|
||||
const resolutionFactor =
|
||||
resolutions[resolutions.length - 1] /
|
||||
sourceResolutions[sourceResolutions.length - 1];
|
||||
this.resolutionFactors_[sourceIndex] = resolutionFactor;
|
||||
const scaledSourceResolutions = sourceResolutions.map(
|
||||
(resolution) => (resolution *= resolutionFactor)
|
||||
);
|
||||
const message = `Resolution mismatch for source ${sourceIndex}, got [${scaledSourceResolutions}] but expected [${resolutions}]`;
|
||||
assertEqual(
|
||||
resolutions.slice(minZoom, resolutions.length),
|
||||
scaledSourceResolutions,
|
||||
0.02,
|
||||
message,
|
||||
this.viewRejector
|
||||
);
|
||||
}
|
||||
|
||||
if (!commonRenderTileSizes) {
|
||||
commonRenderTileSizes = renderTileSizes;
|
||||
} else {
|
||||
assertEqual(
|
||||
commonRenderTileSizes.slice(minZoom, commonRenderTileSizes.length),
|
||||
renderTileSizes,
|
||||
0.01,
|
||||
`Tile size mismatch for source ${sourceIndex}`,
|
||||
this.viewRejector
|
||||
);
|
||||
}
|
||||
|
||||
if (!commonSourceTileSizes) {
|
||||
commonSourceTileSizes = sourceTileSizes;
|
||||
} else {
|
||||
assertEqual(
|
||||
commonSourceTileSizes.slice(minZoom, commonSourceTileSizes.length),
|
||||
sourceTileSizes,
|
||||
0,
|
||||
`Tile size mismatch for source ${sourceIndex}`,
|
||||
this.viewRejector
|
||||
);
|
||||
}
|
||||
|
||||
this.sourceImagery_[sourceIndex] = images.reverse();
|
||||
}
|
||||
|
||||
for (let i = 0, ii = this.sourceImagery_.length; i < ii; ++i) {
|
||||
const sourceImagery = this.sourceImagery_[i];
|
||||
while (sourceImagery.length < resolutions.length) {
|
||||
sourceImagery.unshift(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.getProjection()) {
|
||||
const firstSource = sources[0];
|
||||
for (let i = firstSource.length - 1; i >= 0; --i) {
|
||||
const image = firstSource[i];
|
||||
const projection = getProjection(image);
|
||||
if (projection) {
|
||||
this.projection = projection;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.samplesPerPixel_ = samplesPerPixel;
|
||||
this.nodataValues_ = nodataValues;
|
||||
this.metadata_ = metadata;
|
||||
|
||||
// decide if we need to add an alpha band to handle nodata
|
||||
outer: for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
|
||||
// option 1: source is configured with a nodata value
|
||||
if (this.sourceInfo_[sourceIndex].nodata !== undefined) {
|
||||
this.addAlpha_ = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const values = nodataValues[sourceIndex];
|
||||
|
||||
// option 2: check image metadata for limited bands
|
||||
const bands = this.sourceInfo_[sourceIndex].bands;
|
||||
if (bands) {
|
||||
for (let i = 0; i < bands.length; ++i) {
|
||||
if (values[bands[i] - 1] !== null) {
|
||||
this.addAlpha_ = true;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// option 3: check image metadata for all bands
|
||||
for (let imageIndex = 0; imageIndex < values.length; ++imageIndex) {
|
||||
if (values[imageIndex] !== null) {
|
||||
this.addAlpha_ = true;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const additionalBands = this.addAlpha_ ? 1 : 0;
|
||||
this.bandCount =
|
||||
samplesPerPixel.reduce((accumulator, value) => {
|
||||
accumulator += value;
|
||||
return accumulator;
|
||||
}, 0) + additionalBands;
|
||||
|
||||
const tileGrid = new TileGrid({
|
||||
extent: extent,
|
||||
minZoom: minZoom,
|
||||
origin: origin,
|
||||
resolutions: resolutions,
|
||||
tileSizes: commonRenderTileSizes,
|
||||
});
|
||||
|
||||
this.tileGrid = tileGrid;
|
||||
this.setTileSizes(commonSourceTileSizes);
|
||||
|
||||
this.setLoader(this.loadTile_.bind(this));
|
||||
this.setState('ready');
|
||||
this.viewResolver({
|
||||
projection: this.projection,
|
||||
resolutions: resolutions,
|
||||
center: toUserCoordinate(getCenter(extent), this.projection),
|
||||
extent: toUserExtent(extent, this.projection),
|
||||
zoom: 0,
|
||||
});
|
||||
}
|
||||
|
||||
loadTile_(z, x, y) {
|
||||
const sourceTileSize = this.getTileSize(z);
|
||||
const sourceCount = this.sourceImagery_.length;
|
||||
const requests = new Array(sourceCount);
|
||||
const addAlpha = this.addAlpha_;
|
||||
const bandCount = this.bandCount;
|
||||
const samplesPerPixel = this.samplesPerPixel_;
|
||||
const nodataValues = this.nodataValues_;
|
||||
const sourceInfo = this.sourceInfo_;
|
||||
for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
|
||||
const source = sourceInfo[sourceIndex];
|
||||
const resolutionFactor = this.resolutionFactors_[sourceIndex];
|
||||
const pixelBounds = [
|
||||
Math.round(x * (sourceTileSize[0] * resolutionFactor)),
|
||||
Math.round(y * (sourceTileSize[1] * resolutionFactor)),
|
||||
Math.round((x + 1) * (sourceTileSize[0] * resolutionFactor)),
|
||||
Math.round((y + 1) * (sourceTileSize[1] * resolutionFactor)),
|
||||
];
|
||||
const image = this.sourceImagery_[sourceIndex][z];
|
||||
let samples;
|
||||
if (source.bands) {
|
||||
samples = source.bands.map(function (bandNumber) {
|
||||
return bandNumber - 1;
|
||||
});
|
||||
}
|
||||
|
||||
/** @type {number|Array<number>} */
|
||||
let fillValue;
|
||||
if ('nodata' in source && source.nodata !== null) {
|
||||
fillValue = source.nodata;
|
||||
} else {
|
||||
if (!samples) {
|
||||
fillValue = nodataValues[sourceIndex];
|
||||
} else {
|
||||
fillValue = samples.map(function (sampleIndex) {
|
||||
return nodataValues[sourceIndex][sampleIndex];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
requests[sourceIndex] = image[this.readMethod_]({
|
||||
window: pixelBounds,
|
||||
width: sourceTileSize[0],
|
||||
height: sourceTileSize[1],
|
||||
samples: samples,
|
||||
fillValue: fillValue,
|
||||
pool: getWorkerPool(),
|
||||
interleave: false,
|
||||
});
|
||||
}
|
||||
|
||||
const pixelCount = sourceTileSize[0] * sourceTileSize[1];
|
||||
const dataLength = pixelCount * bandCount;
|
||||
const normalize = this.normalize_;
|
||||
const metadata = this.metadata_;
|
||||
|
||||
return Promise.all(requests)
|
||||
.then(function (sourceSamples) {
|
||||
/** @type {Uint8Array|Float32Array} */
|
||||
let data;
|
||||
if (normalize) {
|
||||
data = new Uint8Array(dataLength);
|
||||
} else {
|
||||
data = new Float32Array(dataLength);
|
||||
}
|
||||
|
||||
let dataIndex = 0;
|
||||
for (let pixelIndex = 0; pixelIndex < pixelCount; ++pixelIndex) {
|
||||
let transparent = addAlpha;
|
||||
for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
|
||||
const source = sourceInfo[sourceIndex];
|
||||
|
||||
let min = source.min;
|
||||
let max = source.max;
|
||||
let gain, bias;
|
||||
if (normalize) {
|
||||
const stats = metadata[sourceIndex][0];
|
||||
if (min === undefined) {
|
||||
if (stats && STATISTICS_MINIMUM in stats) {
|
||||
min = parseFloat(stats[STATISTICS_MINIMUM]);
|
||||
} else {
|
||||
min = getMinForDataType(sourceSamples[sourceIndex][0]);
|
||||
}
|
||||
}
|
||||
if (max === undefined) {
|
||||
if (stats && STATISTICS_MAXIMUM in stats) {
|
||||
max = parseFloat(stats[STATISTICS_MAXIMUM]);
|
||||
} else {
|
||||
max = getMaxForDataType(sourceSamples[sourceIndex][0]);
|
||||
}
|
||||
}
|
||||
|
||||
gain = 255 / (max - min);
|
||||
bias = -min * gain;
|
||||
}
|
||||
|
||||
for (
|
||||
let sampleIndex = 0;
|
||||
sampleIndex < samplesPerPixel[sourceIndex];
|
||||
++sampleIndex
|
||||
) {
|
||||
const sourceValue =
|
||||
sourceSamples[sourceIndex][sampleIndex][pixelIndex];
|
||||
|
||||
let value;
|
||||
if (normalize) {
|
||||
value = clamp(gain * sourceValue + bias, 0, 255);
|
||||
} else {
|
||||
value = sourceValue;
|
||||
}
|
||||
|
||||
if (!addAlpha) {
|
||||
data[dataIndex] = value;
|
||||
} else {
|
||||
let nodata = source.nodata;
|
||||
if (nodata === undefined) {
|
||||
let bandIndex;
|
||||
if (source.bands) {
|
||||
bandIndex = source.bands[sampleIndex] - 1;
|
||||
} else {
|
||||
bandIndex = sampleIndex;
|
||||
}
|
||||
nodata = nodataValues[sourceIndex][bandIndex];
|
||||
}
|
||||
|
||||
const nodataIsNaN = isNaN(nodata);
|
||||
if (
|
||||
(!nodataIsNaN && sourceValue !== nodata) ||
|
||||
(nodataIsNaN && !isNaN(sourceValue))
|
||||
) {
|
||||
transparent = false;
|
||||
data[dataIndex] = value;
|
||||
}
|
||||
}
|
||||
dataIndex++;
|
||||
}
|
||||
}
|
||||
if (addAlpha) {
|
||||
if (!transparent) {
|
||||
data[dataIndex] = 255;
|
||||
}
|
||||
dataIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
})
|
||||
.catch(function (error) {
|
||||
// output then rethrow
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a promise for view properties based on the source. Use the result of this function
|
||||
* as the `view` option in a map constructor.
|
||||
*
|
||||
* const source = new GeoTIFF(options);
|
||||
*
|
||||
* const map = new Map({
|
||||
* target: 'map',
|
||||
* layers: [
|
||||
* new TileLayer({
|
||||
* source: source,
|
||||
* }),
|
||||
* ],
|
||||
* view: source.getView(),
|
||||
* });
|
||||
*
|
||||
* @function
|
||||
* @return {Promise<import("../View.js").ViewOptions>} A promise for view-related properties.
|
||||
* @api
|
||||
*
|
||||
*/
|
||||
GeoTIFFSource.prototype.getView;
|
||||
|
||||
export default GeoTIFFSource;
|
||||
362
node_modules/ol/src/source/IIIF.js
generated
vendored
Normal file
362
node_modules/ol/src/source/IIIF.js
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
/**
|
||||
* @module ol/source/IIIF
|
||||
*/
|
||||
|
||||
import TileGrid from '../tilegrid/TileGrid.js';
|
||||
import TileImage from './TileImage.js';
|
||||
import {CustomTile} from './Zoomify.js';
|
||||
import {DEFAULT_TILE_SIZE} from '../tilegrid/common.js';
|
||||
import {Versions} from '../format/IIIFInfo.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {getTopLeft} from '../extent.js';
|
||||
import {includes} from '../array.js';
|
||||
import {toSize} from '../size.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {number} [cacheSize] Size of the cache.
|
||||
* @property {null|string} [crossOrigin] The value for the crossOrigin option of the request.
|
||||
* @property {import("../extent.js").Extent} [extent=[0, -height, width, 0]] The extent.
|
||||
* @property {string} [format='jpg'] Requested image format.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection.
|
||||
* @property {string} [quality] Requested IIIF image quality. Default is 'native'
|
||||
* for version 1, 'default' for versions 2 and 3.
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {Array<number>} [resolutions] Supported resolutions as given in IIIF 'scaleFactors'
|
||||
* @property {import("../size.js").Size} size Size of the image [width, height].
|
||||
* @property {Array<import("../size.js").Size>} [sizes] Supported scaled image sizes.
|
||||
* Content of the IIIF info.json 'sizes' property, but as array of Size objects.
|
||||
* @property {import("./Source.js").State} [state] Source state.
|
||||
* @property {Array<string>} [supports=[]] Supported IIIF region and size calculation
|
||||
* features.
|
||||
* @property {number} [tilePixelRatio] Tile pixel ratio.
|
||||
* @property {number|import("../size.js").Size} [tileSize] Tile size.
|
||||
* Same tile size is used for all zoom levels. If tile size is a number,
|
||||
* a square tile is assumed. If the IIIF image service supports arbitrary
|
||||
* tiling (sizeByH, sizeByW, sizeByWh or sizeByPct as well as regionByPx or regionByPct
|
||||
* are supported), the default tilesize is 256.
|
||||
* @property {number} [transition] Transition.
|
||||
* @property {string} [url] Base URL of the IIIF Image service.
|
||||
* This should be the same as the IIIF Image ID.
|
||||
* @property {import("../format/IIIFInfo.js").Versions} [version=Versions.VERSION2] Service's IIIF Image API version.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
function formatPercentage(percentage) {
|
||||
return percentage.toLocaleString('en', {maximumFractionDigits: 10});
|
||||
}
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for IIIF Image API services.
|
||||
* @api
|
||||
*/
|
||||
class IIIF extends TileImage {
|
||||
/**
|
||||
* @param {Options} [opt_options] Tile source options. Use {@link import("../format/IIIFInfo.js").IIIFInfo}
|
||||
* to parse Image API service information responses into constructor options.
|
||||
* @api
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
/**
|
||||
* @type {Partial<Options>}
|
||||
*/
|
||||
const options = opt_options || {};
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
let baseUrl = options.url || '';
|
||||
baseUrl =
|
||||
baseUrl +
|
||||
(baseUrl.lastIndexOf('/') === baseUrl.length - 1 || baseUrl === ''
|
||||
? ''
|
||||
: '/');
|
||||
const version = options.version || Versions.VERSION2;
|
||||
const sizes = options.sizes || [];
|
||||
const size = options.size;
|
||||
assert(
|
||||
size != undefined &&
|
||||
Array.isArray(size) &&
|
||||
size.length == 2 &&
|
||||
!isNaN(size[0]) &&
|
||||
size[0] > 0 &&
|
||||
!isNaN(size[1]) &&
|
||||
size[1] > 0,
|
||||
60
|
||||
);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
const tileSize = options.tileSize;
|
||||
const tilePixelRatio = options.tilePixelRatio || 1;
|
||||
const format = options.format || 'jpg';
|
||||
const quality =
|
||||
options.quality ||
|
||||
(options.version == Versions.VERSION1 ? 'native' : 'default');
|
||||
let resolutions = options.resolutions || [];
|
||||
const supports = options.supports || [];
|
||||
const extent = options.extent || [0, -height, width, 0];
|
||||
|
||||
const supportsListedSizes =
|
||||
sizes != undefined && Array.isArray(sizes) && sizes.length > 0;
|
||||
const supportsListedTiles =
|
||||
tileSize !== undefined &&
|
||||
((typeof tileSize === 'number' &&
|
||||
Number.isInteger(tileSize) &&
|
||||
tileSize > 0) ||
|
||||
(Array.isArray(tileSize) && tileSize.length > 0));
|
||||
const supportsArbitraryTiling =
|
||||
supports != undefined &&
|
||||
Array.isArray(supports) &&
|
||||
(includes(supports, 'regionByPx') || includes(supports, 'regionByPct')) &&
|
||||
(includes(supports, 'sizeByWh') ||
|
||||
includes(supports, 'sizeByH') ||
|
||||
includes(supports, 'sizeByW') ||
|
||||
includes(supports, 'sizeByPct'));
|
||||
|
||||
let tileWidth, tileHeight, maxZoom;
|
||||
|
||||
resolutions.sort(function (a, b) {
|
||||
return b - a;
|
||||
});
|
||||
|
||||
if (supportsListedTiles || supportsArbitraryTiling) {
|
||||
if (tileSize != undefined) {
|
||||
if (
|
||||
typeof tileSize === 'number' &&
|
||||
Number.isInteger(tileSize) &&
|
||||
tileSize > 0
|
||||
) {
|
||||
tileWidth = tileSize;
|
||||
tileHeight = tileSize;
|
||||
} else if (Array.isArray(tileSize) && tileSize.length > 0) {
|
||||
if (
|
||||
tileSize.length == 1 ||
|
||||
(tileSize[1] == undefined && Number.isInteger(tileSize[0]))
|
||||
) {
|
||||
tileWidth = tileSize[0];
|
||||
tileHeight = tileSize[0];
|
||||
}
|
||||
if (tileSize.length == 2) {
|
||||
if (
|
||||
Number.isInteger(tileSize[0]) &&
|
||||
Number.isInteger(tileSize[1])
|
||||
) {
|
||||
tileWidth = tileSize[0];
|
||||
tileHeight = tileSize[1];
|
||||
} else if (
|
||||
tileSize[0] == undefined &&
|
||||
Number.isInteger(tileSize[1])
|
||||
) {
|
||||
tileWidth = tileSize[1];
|
||||
tileHeight = tileSize[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tileWidth === undefined || tileHeight === undefined) {
|
||||
tileWidth = DEFAULT_TILE_SIZE;
|
||||
tileHeight = DEFAULT_TILE_SIZE;
|
||||
}
|
||||
if (resolutions.length == 0) {
|
||||
maxZoom = Math.max(
|
||||
Math.ceil(Math.log(width / tileWidth) / Math.LN2),
|
||||
Math.ceil(Math.log(height / tileHeight) / Math.LN2)
|
||||
);
|
||||
for (let i = maxZoom; i >= 0; i--) {
|
||||
resolutions.push(Math.pow(2, i));
|
||||
}
|
||||
} else {
|
||||
const maxScaleFactor = Math.max(...resolutions);
|
||||
// TODO maxScaleFactor might not be a power to 2
|
||||
maxZoom = Math.round(Math.log(maxScaleFactor) / Math.LN2);
|
||||
}
|
||||
} else {
|
||||
// No tile support.
|
||||
tileWidth = width;
|
||||
tileHeight = height;
|
||||
resolutions = [];
|
||||
if (supportsListedSizes) {
|
||||
/*
|
||||
* 'sizes' provided. Use full region in different resolutions. Every
|
||||
* resolution has only one tile.
|
||||
*/
|
||||
sizes.sort(function (a, b) {
|
||||
return a[0] - b[0];
|
||||
});
|
||||
maxZoom = -1;
|
||||
const ignoredSizesIndex = [];
|
||||
for (let i = 0; i < sizes.length; i++) {
|
||||
const resolution = width / sizes[i][0];
|
||||
if (
|
||||
resolutions.length > 0 &&
|
||||
resolutions[resolutions.length - 1] == resolution
|
||||
) {
|
||||
ignoredSizesIndex.push(i);
|
||||
continue;
|
||||
}
|
||||
resolutions.push(resolution);
|
||||
maxZoom++;
|
||||
}
|
||||
if (ignoredSizesIndex.length > 0) {
|
||||
for (let i = 0; i < ignoredSizesIndex.length; i++) {
|
||||
sizes.splice(ignoredSizesIndex[i] - i, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No useful image information at all. Try pseudo tile with full image.
|
||||
resolutions.push(1);
|
||||
sizes.push([width, height]);
|
||||
maxZoom = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const tileGrid = new TileGrid({
|
||||
tileSize: [tileWidth, tileHeight],
|
||||
extent: extent,
|
||||
origin: getTopLeft(extent),
|
||||
resolutions: resolutions,
|
||||
});
|
||||
|
||||
const tileUrlFunction = function (tileCoord, pixelRatio, projection) {
|
||||
let regionParam, sizeParam;
|
||||
const zoom = tileCoord[0];
|
||||
if (zoom > maxZoom) {
|
||||
return;
|
||||
}
|
||||
const tileX = tileCoord[1],
|
||||
tileY = tileCoord[2],
|
||||
scale = resolutions[zoom];
|
||||
if (
|
||||
tileX === undefined ||
|
||||
tileY === undefined ||
|
||||
scale === undefined ||
|
||||
tileX < 0 ||
|
||||
Math.ceil(width / scale / tileWidth) <= tileX ||
|
||||
tileY < 0 ||
|
||||
Math.ceil(height / scale / tileHeight) <= tileY
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (supportsArbitraryTiling || supportsListedTiles) {
|
||||
const regionX = tileX * tileWidth * scale,
|
||||
regionY = tileY * tileHeight * scale;
|
||||
let regionW = tileWidth * scale,
|
||||
regionH = tileHeight * scale,
|
||||
sizeW = tileWidth,
|
||||
sizeH = tileHeight;
|
||||
if (regionX + regionW > width) {
|
||||
regionW = width - regionX;
|
||||
}
|
||||
if (regionY + regionH > height) {
|
||||
regionH = height - regionY;
|
||||
}
|
||||
if (regionX + tileWidth * scale > width) {
|
||||
sizeW = Math.floor((width - regionX + scale - 1) / scale);
|
||||
}
|
||||
if (regionY + tileHeight * scale > height) {
|
||||
sizeH = Math.floor((height - regionY + scale - 1) / scale);
|
||||
}
|
||||
if (
|
||||
regionX == 0 &&
|
||||
regionW == width &&
|
||||
regionY == 0 &&
|
||||
regionH == height
|
||||
) {
|
||||
// canonical full image region parameter is 'full', not 'x,y,w,h'
|
||||
regionParam = 'full';
|
||||
} else if (
|
||||
!supportsArbitraryTiling ||
|
||||
includes(supports, 'regionByPx')
|
||||
) {
|
||||
regionParam = regionX + ',' + regionY + ',' + regionW + ',' + regionH;
|
||||
} else if (includes(supports, 'regionByPct')) {
|
||||
const pctX = formatPercentage((regionX / width) * 100),
|
||||
pctY = formatPercentage((regionY / height) * 100),
|
||||
pctW = formatPercentage((regionW / width) * 100),
|
||||
pctH = formatPercentage((regionH / height) * 100);
|
||||
regionParam = 'pct:' + pctX + ',' + pctY + ',' + pctW + ',' + pctH;
|
||||
}
|
||||
if (
|
||||
version == Versions.VERSION3 &&
|
||||
(!supportsArbitraryTiling || includes(supports, 'sizeByWh'))
|
||||
) {
|
||||
sizeParam = sizeW + ',' + sizeH;
|
||||
} else if (!supportsArbitraryTiling || includes(supports, 'sizeByW')) {
|
||||
sizeParam = sizeW + ',';
|
||||
} else if (includes(supports, 'sizeByH')) {
|
||||
sizeParam = ',' + sizeH;
|
||||
} else if (includes(supports, 'sizeByWh')) {
|
||||
sizeParam = sizeW + ',' + sizeH;
|
||||
} else if (includes(supports, 'sizeByPct')) {
|
||||
sizeParam = 'pct:' + formatPercentage(100 / scale);
|
||||
}
|
||||
} else {
|
||||
regionParam = 'full';
|
||||
if (supportsListedSizes) {
|
||||
const regionWidth = sizes[zoom][0],
|
||||
regionHeight = sizes[zoom][1];
|
||||
if (version == Versions.VERSION3) {
|
||||
if (regionWidth == width && regionHeight == height) {
|
||||
sizeParam = 'max';
|
||||
} else {
|
||||
sizeParam = regionWidth + ',' + regionHeight;
|
||||
}
|
||||
} else {
|
||||
if (regionWidth == width) {
|
||||
sizeParam = 'full';
|
||||
} else {
|
||||
sizeParam = regionWidth + ',';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sizeParam = version == Versions.VERSION3 ? 'max' : 'full';
|
||||
}
|
||||
}
|
||||
return (
|
||||
baseUrl + regionParam + '/' + sizeParam + '/0/' + quality + '.' + format
|
||||
);
|
||||
};
|
||||
|
||||
const IiifTileClass = CustomTile.bind(
|
||||
null,
|
||||
toSize(tileSize || 256).map(function (size) {
|
||||
return size * tilePixelRatio;
|
||||
})
|
||||
);
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
attributionsCollapsible: options.attributionsCollapsible,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: options.crossOrigin,
|
||||
interpolate: interpolate,
|
||||
projection: options.projection,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
state: options.state,
|
||||
tileClass: IiifTileClass,
|
||||
tileGrid: tileGrid,
|
||||
tilePixelRatio: options.tilePixelRatio,
|
||||
tileUrlFunction: tileUrlFunction,
|
||||
transition: options.transition,
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {number|import("../array.js").NearestDirectionFunction}
|
||||
*/
|
||||
this.zDirection = options.zDirection;
|
||||
}
|
||||
}
|
||||
|
||||
export default IIIF;
|
||||
276
node_modules/ol/src/source/Image.js
generated
vendored
Normal file
276
node_modules/ol/src/source/Image.js
generated
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
/**
|
||||
* @module ol/source/Image
|
||||
*/
|
||||
import Event from '../events/Event.js';
|
||||
import ImageState from '../ImageState.js';
|
||||
import ReprojImage from '../reproj/Image.js';
|
||||
import Source from './Source.js';
|
||||
import {ENABLE_RASTER_REPROJECTION} from '../reproj/common.js';
|
||||
import {abstract} from '../util.js';
|
||||
import {equals} from '../extent.js';
|
||||
import {equivalent} from '../proj.js';
|
||||
import {linearFindNearest} from '../array.js';
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
export const ImageSourceEventType = {
|
||||
/**
|
||||
* Triggered when an image starts loading.
|
||||
* @event module:ol/source/Image.ImageSourceEvent#imageloadstart
|
||||
* @api
|
||||
*/
|
||||
IMAGELOADSTART: 'imageloadstart',
|
||||
|
||||
/**
|
||||
* Triggered when an image finishes loading.
|
||||
* @event module:ol/source/Image.ImageSourceEvent#imageloadend
|
||||
* @api
|
||||
*/
|
||||
IMAGELOADEND: 'imageloadend',
|
||||
|
||||
/**
|
||||
* Triggered if image loading results in an error.
|
||||
* @event module:ol/source/Image.ImageSourceEvent#imageloaderror
|
||||
* @api
|
||||
*/
|
||||
IMAGELOADERROR: 'imageloaderror',
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {'imageloadend'|'imageloaderror'|'imageloadstart'} ImageSourceEventTypes
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Events emitted by {@link module:ol/source/Image~ImageSource} instances are instances of this
|
||||
* type.
|
||||
*/
|
||||
export class ImageSourceEvent extends Event {
|
||||
/**
|
||||
* @param {string} type Type.
|
||||
* @param {import("../Image.js").default} image The image.
|
||||
*/
|
||||
constructor(type, image) {
|
||||
super(type);
|
||||
|
||||
/**
|
||||
* The image related to the event.
|
||||
* @type {import("../Image.js").default}
|
||||
* @api
|
||||
*/
|
||||
this.image = image;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* @template Return
|
||||
* @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> &
|
||||
* import("../Observable").OnSignature<import("../ObjectEventType").Types, import("../Object").ObjectEvent, Return> &
|
||||
* import("../Observable").OnSignature<ImageSourceEventTypes, ImageSourceEvent, Return> &
|
||||
* import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("../ObjectEventType").Types
|
||||
* |ImageSourceEventTypes, Return>} ImageSourceOnSignature
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection.
|
||||
* @property {Array<number>} [resolutions] Resolutions.
|
||||
* @property {import("./Source.js").State} [state] State.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Abstract base class; normally only used for creating subclasses and not
|
||||
* instantiated in apps.
|
||||
* Base class for sources providing a single image.
|
||||
* @abstract
|
||||
* @fires module:ol/source/Image.ImageSourceEvent
|
||||
* @api
|
||||
*/
|
||||
class ImageSource extends Source {
|
||||
/**
|
||||
* @param {Options} options Single image source options.
|
||||
*/
|
||||
constructor(options) {
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
projection: options.projection,
|
||||
state: options.state,
|
||||
interpolate: interpolate,
|
||||
});
|
||||
|
||||
/***
|
||||
* @type {ImageSourceOnSignature<import("../events").EventsKey>}
|
||||
*/
|
||||
this.on;
|
||||
|
||||
/***
|
||||
* @type {ImageSourceOnSignature<import("../events").EventsKey>}
|
||||
*/
|
||||
this.once;
|
||||
|
||||
/***
|
||||
* @type {ImageSourceOnSignature<void>}
|
||||
*/
|
||||
this.un;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<number>|null}
|
||||
*/
|
||||
this.resolutions_ =
|
||||
options.resolutions !== undefined ? options.resolutions : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../reproj/Image.js").default}
|
||||
*/
|
||||
this.reprojectedImage_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.reprojectedRevision_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array<number>|null} Resolutions.
|
||||
*/
|
||||
getResolutions() {
|
||||
return this.resolutions_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @param {number} resolution Resolution.
|
||||
* @return {number} Resolution.
|
||||
*/
|
||||
findNearestResolution(resolution) {
|
||||
if (this.resolutions_) {
|
||||
const idx = linearFindNearest(this.resolutions_, resolution, 0);
|
||||
resolution = this.resolutions_[idx];
|
||||
}
|
||||
return resolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../ImageBase.js").default} Single image.
|
||||
*/
|
||||
getImage(extent, resolution, pixelRatio, projection) {
|
||||
const sourceProjection = this.getProjection();
|
||||
if (
|
||||
!ENABLE_RASTER_REPROJECTION ||
|
||||
!sourceProjection ||
|
||||
!projection ||
|
||||
equivalent(sourceProjection, projection)
|
||||
) {
|
||||
if (sourceProjection) {
|
||||
projection = sourceProjection;
|
||||
}
|
||||
return this.getImageInternal(extent, resolution, pixelRatio, projection);
|
||||
} else {
|
||||
if (this.reprojectedImage_) {
|
||||
if (
|
||||
this.reprojectedRevision_ == this.getRevision() &&
|
||||
equivalent(this.reprojectedImage_.getProjection(), projection) &&
|
||||
this.reprojectedImage_.getResolution() == resolution &&
|
||||
equals(this.reprojectedImage_.getExtent(), extent)
|
||||
) {
|
||||
return this.reprojectedImage_;
|
||||
}
|
||||
this.reprojectedImage_.dispose();
|
||||
this.reprojectedImage_ = null;
|
||||
}
|
||||
|
||||
this.reprojectedImage_ = new ReprojImage(
|
||||
sourceProjection,
|
||||
projection,
|
||||
extent,
|
||||
resolution,
|
||||
pixelRatio,
|
||||
function (extent, resolution, pixelRatio) {
|
||||
return this.getImageInternal(
|
||||
extent,
|
||||
resolution,
|
||||
pixelRatio,
|
||||
sourceProjection
|
||||
);
|
||||
}.bind(this),
|
||||
this.getInterpolate()
|
||||
);
|
||||
this.reprojectedRevision_ = this.getRevision();
|
||||
|
||||
return this.reprojectedImage_;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../ImageBase.js").default} Single image.
|
||||
* @protected
|
||||
*/
|
||||
getImageInternal(extent, resolution, pixelRatio, projection) {
|
||||
return abstract();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle image change events.
|
||||
* @param {import("../events/Event.js").default} event Event.
|
||||
* @protected
|
||||
*/
|
||||
handleImageChange(event) {
|
||||
const image = /** @type {import("../Image.js").default} */ (event.target);
|
||||
let type;
|
||||
switch (image.getState()) {
|
||||
case ImageState.LOADING:
|
||||
this.loading = true;
|
||||
type = ImageSourceEventType.IMAGELOADSTART;
|
||||
break;
|
||||
case ImageState.LOADED:
|
||||
this.loading = false;
|
||||
type = ImageSourceEventType.IMAGELOADEND;
|
||||
break;
|
||||
case ImageState.ERROR:
|
||||
this.loading = false;
|
||||
type = ImageSourceEventType.IMAGELOADERROR;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (this.hasListener(type)) {
|
||||
this.dispatchEvent(new ImageSourceEvent(type, image));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default image load function for image sources that use import("../Image.js").Image image
|
||||
* instances.
|
||||
* @param {import("../Image.js").default} image Image.
|
||||
* @param {string} src Source.
|
||||
*/
|
||||
export function defaultImageLoadFunction(image, src) {
|
||||
/** @type {HTMLImageElement|HTMLVideoElement} */ (image.getImage()).src = src;
|
||||
}
|
||||
|
||||
export default ImageSource;
|
||||
320
node_modules/ol/src/source/ImageArcGISRest.js
generated
vendored
Normal file
320
node_modules/ol/src/source/ImageArcGISRest.js
generated
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
/**
|
||||
* @module ol/source/ImageArcGISRest
|
||||
*/
|
||||
|
||||
import EventType from '../events/EventType.js';
|
||||
import ImageSource, {defaultImageLoadFunction} from './Image.js';
|
||||
import ImageWrapper from '../Image.js';
|
||||
import {appendParams} from '../uri.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {containsExtent, getHeight, getWidth} from '../extent.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [hidpi=true] Use the `ol/Map#pixelRatio` value when requesting the image from
|
||||
* the remote server.
|
||||
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given
|
||||
* a URL.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {Object<string,*>} [params] ArcGIS Rest parameters. This field is optional. Service
|
||||
* defaults will be used for any fields not specified. `FORMAT` is `PNG32` by default. `F` is
|
||||
* `IMAGE` by default. `TRANSPARENT` is `true` by default. `BBOX`, `SIZE`, `BBOXSR`, and `IMAGESR`
|
||||
* will be set dynamically. Set `LAYERS` to override the default service layer visibility. See
|
||||
* https://developers.arcgis.com/rest/services-reference/export-map.htm
|
||||
* for further reference.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* The projection code must contain a numeric end portion separated by :
|
||||
* or the entire code must form a valid ArcGIS SpatialReference definition.
|
||||
* @property {number} [ratio=1.5] Ratio. `1` means image requests are the size of the map viewport,
|
||||
* `2` means twice the size of the map viewport, and so on.
|
||||
* @property {Array<number>} [resolutions] Resolutions. If specified, requests will be made for
|
||||
* these resolutions only.
|
||||
* @property {string} [url] ArcGIS Rest service URL for a Map Service or Image Service. The url
|
||||
* should include /MapServer or /ImageServer.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Source for data from ArcGIS Rest services providing single, untiled images.
|
||||
* Useful when underlying map service has labels.
|
||||
*
|
||||
* If underlying map service is not using labels,
|
||||
* take advantage of ol image caching and use
|
||||
* {@link module:ol/source/TileArcGISRest~TileArcGISRest} data source.
|
||||
*
|
||||
* @fires module:ol/source/Image.ImageSourceEvent
|
||||
* @api
|
||||
*/
|
||||
class ImageArcGISRest extends ImageSource {
|
||||
/**
|
||||
* @param {Options} [opt_options] Image ArcGIS Rest Options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
interpolate: interpolate,
|
||||
projection: options.projection,
|
||||
resolutions: options.resolutions,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?string}
|
||||
*/
|
||||
this.crossOrigin_ =
|
||||
options.crossOrigin !== undefined ? options.crossOrigin : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.url_ = options.url;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../Image.js").LoadFunction}
|
||||
*/
|
||||
this.imageLoadFunction_ =
|
||||
options.imageLoadFunction !== undefined
|
||||
? options.imageLoadFunction
|
||||
: defaultImageLoadFunction;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object}
|
||||
*/
|
||||
this.params_ = options.params || {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../Image.js").default}
|
||||
*/
|
||||
this.image_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../size.js").Size}
|
||||
*/
|
||||
this.imageSize_ = [0, 0];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.renderedRevision_ = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user-provided params, i.e. those passed to the constructor through
|
||||
* the "params" option, and possibly updated using the updateParams method.
|
||||
* @return {Object} Params.
|
||||
* @api
|
||||
*/
|
||||
getParams() {
|
||||
return this.params_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../Image.js").default} Single image.
|
||||
*/
|
||||
getImageInternal(extent, resolution, pixelRatio, projection) {
|
||||
if (this.url_ === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
resolution = this.findNearestResolution(resolution);
|
||||
pixelRatio = this.hidpi_ ? pixelRatio : 1;
|
||||
|
||||
const image = this.image_;
|
||||
if (
|
||||
image &&
|
||||
this.renderedRevision_ == this.getRevision() &&
|
||||
image.getResolution() == resolution &&
|
||||
image.getPixelRatio() == pixelRatio &&
|
||||
containsExtent(image.getExtent(), extent)
|
||||
) {
|
||||
return image;
|
||||
}
|
||||
|
||||
const params = {
|
||||
'F': 'image',
|
||||
'FORMAT': 'PNG32',
|
||||
'TRANSPARENT': true,
|
||||
};
|
||||
assign(params, this.params_);
|
||||
|
||||
extent = extent.slice();
|
||||
const centerX = (extent[0] + extent[2]) / 2;
|
||||
const centerY = (extent[1] + extent[3]) / 2;
|
||||
if (this.ratio_ != 1) {
|
||||
const halfWidth = (this.ratio_ * getWidth(extent)) / 2;
|
||||
const halfHeight = (this.ratio_ * getHeight(extent)) / 2;
|
||||
extent[0] = centerX - halfWidth;
|
||||
extent[1] = centerY - halfHeight;
|
||||
extent[2] = centerX + halfWidth;
|
||||
extent[3] = centerY + halfHeight;
|
||||
}
|
||||
|
||||
const imageResolution = resolution / pixelRatio;
|
||||
|
||||
// Compute an integer width and height.
|
||||
const width = Math.ceil(getWidth(extent) / imageResolution);
|
||||
const height = Math.ceil(getHeight(extent) / imageResolution);
|
||||
|
||||
// Modify the extent to match the integer width and height.
|
||||
extent[0] = centerX - (imageResolution * width) / 2;
|
||||
extent[2] = centerX + (imageResolution * width) / 2;
|
||||
extent[1] = centerY - (imageResolution * height) / 2;
|
||||
extent[3] = centerY + (imageResolution * height) / 2;
|
||||
|
||||
this.imageSize_[0] = width;
|
||||
this.imageSize_[1] = height;
|
||||
|
||||
const url = this.getRequestUrl_(
|
||||
extent,
|
||||
this.imageSize_,
|
||||
pixelRatio,
|
||||
projection,
|
||||
params
|
||||
);
|
||||
|
||||
this.image_ = new ImageWrapper(
|
||||
extent,
|
||||
resolution,
|
||||
pixelRatio,
|
||||
url,
|
||||
this.crossOrigin_,
|
||||
this.imageLoadFunction_
|
||||
);
|
||||
|
||||
this.renderedRevision_ = this.getRevision();
|
||||
|
||||
this.image_.addEventListener(
|
||||
EventType.CHANGE,
|
||||
this.handleImageChange.bind(this)
|
||||
);
|
||||
|
||||
return this.image_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image load function of the source.
|
||||
* @return {import("../Image.js").LoadFunction} The image load function.
|
||||
* @api
|
||||
*/
|
||||
getImageLoadFunction() {
|
||||
return this.imageLoadFunction_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {import("../size.js").Size} size Size.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @param {Object} params Params.
|
||||
* @return {string} Request URL.
|
||||
* @private
|
||||
*/
|
||||
getRequestUrl_(extent, size, pixelRatio, projection, params) {
|
||||
// ArcGIS Server only wants the numeric portion of the projection ID.
|
||||
// (if there is no numeric portion the entire projection code must
|
||||
// form a valid ArcGIS SpatialReference definition).
|
||||
const srid = projection
|
||||
.getCode()
|
||||
.split(/:(?=\d+$)/)
|
||||
.pop();
|
||||
|
||||
params['SIZE'] = size[0] + ',' + size[1];
|
||||
params['BBOX'] = extent.join(',');
|
||||
params['BBOXSR'] = srid;
|
||||
params['IMAGESR'] = srid;
|
||||
params['DPI'] = Math.round(90 * pixelRatio);
|
||||
|
||||
const url = this.url_;
|
||||
|
||||
const modifiedUrl = url
|
||||
.replace(/MapServer\/?$/, 'MapServer/export')
|
||||
.replace(/ImageServer\/?$/, 'ImageServer/exportImage');
|
||||
if (modifiedUrl == url) {
|
||||
assert(false, 50); // `options.featureTypes` should be an Array
|
||||
}
|
||||
return appendParams(modifiedUrl, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL used for this ArcGIS source.
|
||||
* @return {string|undefined} URL.
|
||||
* @api
|
||||
*/
|
||||
getUrl() {
|
||||
return this.url_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the image load function of the source.
|
||||
* @param {import("../Image.js").LoadFunction} imageLoadFunction Image load function.
|
||||
* @api
|
||||
*/
|
||||
setImageLoadFunction(imageLoadFunction) {
|
||||
this.image_ = null;
|
||||
this.imageLoadFunction_ = imageLoadFunction;
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to use for requests.
|
||||
* @param {string|undefined} url URL.
|
||||
* @api
|
||||
*/
|
||||
setUrl(url) {
|
||||
if (url != this.url_) {
|
||||
this.url_ = url;
|
||||
this.image_ = null;
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user-provided params.
|
||||
* @param {Object} params Params.
|
||||
* @api
|
||||
*/
|
||||
updateParams(params) {
|
||||
assign(this.params_, params);
|
||||
this.image_ = null;
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
export default ImageArcGISRest;
|
||||
146
node_modules/ol/src/source/ImageCanvas.js
generated
vendored
Normal file
146
node_modules/ol/src/source/ImageCanvas.js
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* @module ol/source/ImageCanvas
|
||||
*/
|
||||
|
||||
import ImageCanvas from '../ImageCanvas.js';
|
||||
import ImageSource from './Image.js';
|
||||
import {
|
||||
containsExtent,
|
||||
getHeight,
|
||||
getWidth,
|
||||
scaleFromCenter,
|
||||
} from '../extent.js';
|
||||
|
||||
/**
|
||||
* A function returning the canvas element (`{HTMLCanvasElement}`)
|
||||
* used by the source as an image. The arguments passed to the function are:
|
||||
* {@link module:ol/extent~Extent} the image extent, `{number}` the image resolution,
|
||||
* `{number}` the pixel ratio of the map, {@link module:ol/size~Size} the image size,
|
||||
* and {@link module:ol/proj/Projection~Projection} the image projection. The canvas returned by
|
||||
* this function is cached by the source. The this keyword inside the function
|
||||
* references the {@link module:ol/source/ImageCanvas~ImageCanvasSource}.
|
||||
*
|
||||
* @typedef {function(this:import("../ImageCanvas.js").default, import("../extent.js").Extent, number,
|
||||
* number, import("../size.js").Size, import("../proj/Projection.js").default): HTMLCanvasElement} FunctionType
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {FunctionType} [canvasFunction] Canvas function.
|
||||
* The function returning the canvas element used by the source
|
||||
* as an image. The arguments passed to the function are: {@link import("../extent.js").Extent} the
|
||||
* image extent, `{number}` the image resolution, `{number}` the pixel ratio of the map,
|
||||
* {@link import("../size.js").Size} the image size, and {@link import("../proj/Projection.js").default} the image
|
||||
* projection. The canvas returned by this function is cached by the source. If
|
||||
* the value returned by the function is later changed then
|
||||
* `changed` should be called on the source for the source to
|
||||
* invalidate the current cached image. See: {@link module:ol/Observable~Observable#changed}
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {number} [ratio=1.5] Ratio. 1 means canvases are the size of the map viewport, 2 means twice the
|
||||
* width and height of the map viewport, and so on. Must be `1` or higher.
|
||||
* @property {Array<number>} [resolutions] Resolutions.
|
||||
* If specified, new canvases will be created for these resolutions
|
||||
* @property {import("./Source.js").State} [state] Source state.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Base class for image sources where a canvas element is the image.
|
||||
* @api
|
||||
*/
|
||||
class ImageCanvasSource extends ImageSource {
|
||||
/**
|
||||
* @param {Options} [opt_options] ImageCanvas options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
interpolate: interpolate,
|
||||
projection: options.projection,
|
||||
resolutions: options.resolutions,
|
||||
state: options.state,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {FunctionType}
|
||||
*/
|
||||
this.canvasFunction_ = options.canvasFunction;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../ImageCanvas.js").default}
|
||||
*/
|
||||
this.canvas_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.renderedRevision_ = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../ImageCanvas.js").default} Single image.
|
||||
*/
|
||||
getImageInternal(extent, resolution, pixelRatio, projection) {
|
||||
resolution = this.findNearestResolution(resolution);
|
||||
|
||||
let canvas = this.canvas_;
|
||||
if (
|
||||
canvas &&
|
||||
this.renderedRevision_ == this.getRevision() &&
|
||||
canvas.getResolution() == resolution &&
|
||||
canvas.getPixelRatio() == pixelRatio &&
|
||||
containsExtent(canvas.getExtent(), extent)
|
||||
) {
|
||||
return canvas;
|
||||
}
|
||||
|
||||
extent = extent.slice();
|
||||
scaleFromCenter(extent, this.ratio_);
|
||||
const width = getWidth(extent) / resolution;
|
||||
const height = getHeight(extent) / resolution;
|
||||
const size = [width * pixelRatio, height * pixelRatio];
|
||||
|
||||
const canvasElement = this.canvasFunction_.call(
|
||||
this,
|
||||
extent,
|
||||
resolution,
|
||||
pixelRatio,
|
||||
size,
|
||||
projection
|
||||
);
|
||||
if (canvasElement) {
|
||||
canvas = new ImageCanvas(extent, resolution, pixelRatio, canvasElement);
|
||||
}
|
||||
this.canvas_ = canvas;
|
||||
this.renderedRevision_ = this.getRevision();
|
||||
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
|
||||
export default ImageCanvasSource;
|
||||
289
node_modules/ol/src/source/ImageMapGuide.js
generated
vendored
Normal file
289
node_modules/ol/src/source/ImageMapGuide.js
generated
vendored
Normal file
@@ -0,0 +1,289 @@
|
||||
/**
|
||||
* @module ol/source/ImageMapGuide
|
||||
*/
|
||||
|
||||
import EventType from '../events/EventType.js';
|
||||
import ImageSource, {defaultImageLoadFunction} from './Image.js';
|
||||
import ImageWrapper from '../Image.js';
|
||||
import {appendParams} from '../uri.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {
|
||||
containsExtent,
|
||||
getCenter,
|
||||
getHeight,
|
||||
getWidth,
|
||||
scaleFromCenter,
|
||||
} from '../extent.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {string} [url] The mapagent url.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {number} [displayDpi=96] The display resolution.
|
||||
* @property {number} [metersPerUnit=1] The meters-per-unit value.
|
||||
* @property {boolean} [hidpi=true] Use the `ol/Map#pixelRatio` value when requesting
|
||||
* the image from the remote server.
|
||||
* @property {boolean} [useOverlay] If `true`, will use `GETDYNAMICMAPOVERLAYIMAGE`.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {number} [ratio=1] Ratio. `1` means image requests are the size of the map viewport, `2` means
|
||||
* twice the width and height of the map viewport, and so on. Must be `1` or higher.
|
||||
* @property {Array<number>} [resolutions] Resolutions.
|
||||
* If specified, requests will be made for these resolutions only.
|
||||
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given a URL.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {Object} [params] Additional parameters.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Source for images from Mapguide servers
|
||||
*
|
||||
* @fires module:ol/source/Image.ImageSourceEvent
|
||||
* @api
|
||||
*/
|
||||
class ImageMapGuide extends ImageSource {
|
||||
/**
|
||||
* @param {Options} options ImageMapGuide options.
|
||||
*/
|
||||
constructor(options) {
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
interpolate: interpolate,
|
||||
projection: options.projection,
|
||||
resolutions: options.resolutions,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?string}
|
||||
*/
|
||||
this.crossOrigin_ =
|
||||
options.crossOrigin !== undefined ? options.crossOrigin : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.displayDpi_ =
|
||||
options.displayDpi !== undefined ? options.displayDpi : 96;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object}
|
||||
*/
|
||||
this.params_ = options.params || {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.url_ = options.url;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../Image.js").LoadFunction}
|
||||
*/
|
||||
this.imageLoadFunction_ =
|
||||
options.imageLoadFunction !== undefined
|
||||
? options.imageLoadFunction
|
||||
: defaultImageLoadFunction;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.metersPerUnit_ =
|
||||
options.metersPerUnit !== undefined ? options.metersPerUnit : 1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.ratio_ = options.ratio !== undefined ? options.ratio : 1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.useOverlay_ =
|
||||
options.useOverlay !== undefined ? options.useOverlay : false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../Image.js").default}
|
||||
*/
|
||||
this.image_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.renderedRevision_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user-provided params, i.e. those passed to the constructor through
|
||||
* the "params" option, and possibly updated using the updateParams method.
|
||||
* @return {Object} Params.
|
||||
* @api
|
||||
*/
|
||||
getParams() {
|
||||
return this.params_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../Image.js").default} Single image.
|
||||
*/
|
||||
getImageInternal(extent, resolution, pixelRatio, projection) {
|
||||
resolution = this.findNearestResolution(resolution);
|
||||
pixelRatio = this.hidpi_ ? pixelRatio : 1;
|
||||
|
||||
let image = this.image_;
|
||||
if (
|
||||
image &&
|
||||
this.renderedRevision_ == this.getRevision() &&
|
||||
image.getResolution() == resolution &&
|
||||
image.getPixelRatio() == pixelRatio &&
|
||||
containsExtent(image.getExtent(), extent)
|
||||
) {
|
||||
return image;
|
||||
}
|
||||
|
||||
if (this.ratio_ != 1) {
|
||||
extent = extent.slice();
|
||||
scaleFromCenter(extent, this.ratio_);
|
||||
}
|
||||
const width = getWidth(extent) / resolution;
|
||||
const height = getHeight(extent) / resolution;
|
||||
const size = [width * pixelRatio, height * pixelRatio];
|
||||
|
||||
if (this.url_ !== undefined) {
|
||||
const imageUrl = this.getUrl(
|
||||
this.url_,
|
||||
this.params_,
|
||||
extent,
|
||||
size,
|
||||
projection
|
||||
);
|
||||
image = new ImageWrapper(
|
||||
extent,
|
||||
resolution,
|
||||
pixelRatio,
|
||||
imageUrl,
|
||||
this.crossOrigin_,
|
||||
this.imageLoadFunction_
|
||||
);
|
||||
image.addEventListener(
|
||||
EventType.CHANGE,
|
||||
this.handleImageChange.bind(this)
|
||||
);
|
||||
} else {
|
||||
image = null;
|
||||
}
|
||||
this.image_ = image;
|
||||
this.renderedRevision_ = this.getRevision();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image load function of the source.
|
||||
* @return {import("../Image.js").LoadFunction} The image load function.
|
||||
* @api
|
||||
*/
|
||||
getImageLoadFunction() {
|
||||
return this.imageLoadFunction_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user-provided params.
|
||||
* @param {Object} params Params.
|
||||
* @api
|
||||
*/
|
||||
updateParams(params) {
|
||||
assign(this.params_, params);
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} baseUrl The mapagent url.
|
||||
* @param {Object<string, string|number>} params Request parameters.
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {import("../size.js").Size} size Size.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {string} The mapagent map image request URL.
|
||||
*/
|
||||
getUrl(baseUrl, params, extent, size, projection) {
|
||||
const scale = getScale(extent, size, this.metersPerUnit_, this.displayDpi_);
|
||||
const center = getCenter(extent);
|
||||
const baseParams = {
|
||||
'OPERATION': this.useOverlay_
|
||||
? 'GETDYNAMICMAPOVERLAYIMAGE'
|
||||
: 'GETMAPIMAGE',
|
||||
'VERSION': '2.0.0',
|
||||
'LOCALE': 'en',
|
||||
'CLIENTAGENT': 'ol/source/ImageMapGuide source',
|
||||
'CLIP': '1',
|
||||
'SETDISPLAYDPI': this.displayDpi_,
|
||||
'SETDISPLAYWIDTH': Math.round(size[0]),
|
||||
'SETDISPLAYHEIGHT': Math.round(size[1]),
|
||||
'SETVIEWSCALE': scale,
|
||||
'SETVIEWCENTERX': center[0],
|
||||
'SETVIEWCENTERY': center[1],
|
||||
};
|
||||
assign(baseParams, params);
|
||||
return appendParams(baseUrl, baseParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the image load function of the MapGuide source.
|
||||
* @param {import("../Image.js").LoadFunction} imageLoadFunction Image load function.
|
||||
* @api
|
||||
*/
|
||||
setImageLoadFunction(imageLoadFunction) {
|
||||
this.image_ = null;
|
||||
this.imageLoadFunction_ = imageLoadFunction;
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent The map extents.
|
||||
* @param {import("../size.js").Size} size The viewport size.
|
||||
* @param {number} metersPerUnit The meters-per-unit value.
|
||||
* @param {number} dpi The display resolution.
|
||||
* @return {number} The computed map scale.
|
||||
*/
|
||||
function getScale(extent, size, metersPerUnit, dpi) {
|
||||
const mcsW = getWidth(extent);
|
||||
const mcsH = getHeight(extent);
|
||||
const devW = size[0];
|
||||
const devH = size[1];
|
||||
const mpp = 0.0254 / dpi;
|
||||
if (devH * mcsW > devW * mcsH) {
|
||||
return (mcsW * metersPerUnit) / (devW * mpp); // width limited
|
||||
} else {
|
||||
return (mcsH * metersPerUnit) / (devH * mpp); // height limited
|
||||
}
|
||||
}
|
||||
|
||||
export default ImageMapGuide;
|
||||
182
node_modules/ol/src/source/ImageStatic.js
generated
vendored
Normal file
182
node_modules/ol/src/source/ImageStatic.js
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* @module ol/source/ImageStatic
|
||||
*/
|
||||
|
||||
import EventType from '../events/EventType.js';
|
||||
import ImageSource, {defaultImageLoadFunction} from './Image.js';
|
||||
import ImageState from '../ImageState.js';
|
||||
import ImageWrapper from '../Image.js';
|
||||
import {IMAGE_SMOOTHING_DISABLED} from '../renderer/canvas/common.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {createCanvasContext2D} from '../dom.js';
|
||||
import {getHeight, getWidth, intersects} from '../extent.js';
|
||||
import {get as getProjection} from '../proj.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {import("../extent.js").Extent} [imageExtent] Extent of the image in map coordinates.
|
||||
* This is the [left, bottom, right, top] map coordinates of your image.
|
||||
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given a URL.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {import("../size.js").Size} [imageSize] Size of the image in pixels. Usually the image size is auto-detected, so this
|
||||
* only needs to be set if auto-detection fails for some reason.
|
||||
* @property {string} url Image URL.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A layer source for displaying a single, static image.
|
||||
* @api
|
||||
*/
|
||||
class Static extends ImageSource {
|
||||
/**
|
||||
* @param {Options} options ImageStatic options.
|
||||
*/
|
||||
constructor(options) {
|
||||
const crossOrigin =
|
||||
options.crossOrigin !== undefined ? options.crossOrigin : null;
|
||||
|
||||
const /** @type {import("../Image.js").LoadFunction} */ imageLoadFunction =
|
||||
options.imageLoadFunction !== undefined
|
||||
? options.imageLoadFunction
|
||||
: defaultImageLoadFunction;
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
interpolate: interpolate,
|
||||
projection: getProjection(options.projection),
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.url_ = options.url;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../extent.js").Extent}
|
||||
*/
|
||||
this.imageExtent_ = options.imageExtent;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../Image.js").default}
|
||||
*/
|
||||
this.image_ = new ImageWrapper(
|
||||
this.imageExtent_,
|
||||
undefined,
|
||||
1,
|
||||
this.url_,
|
||||
crossOrigin,
|
||||
imageLoadFunction
|
||||
);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../size.js").Size|null}
|
||||
*/
|
||||
this.imageSize_ = options.imageSize ? options.imageSize : null;
|
||||
|
||||
this.image_.addEventListener(
|
||||
EventType.CHANGE,
|
||||
this.handleImageChange.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image extent
|
||||
* @return {import("../extent.js").Extent} image extent.
|
||||
* @api
|
||||
*/
|
||||
getImageExtent() {
|
||||
return this.imageExtent_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../Image.js").default} Single image.
|
||||
*/
|
||||
getImageInternal(extent, resolution, pixelRatio, projection) {
|
||||
if (intersects(extent, this.image_.getExtent())) {
|
||||
return this.image_;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL used for this image source.
|
||||
* @return {string} URL.
|
||||
* @api
|
||||
*/
|
||||
getUrl() {
|
||||
return this.url_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../events/Event.js").default} evt Event.
|
||||
*/
|
||||
handleImageChange(evt) {
|
||||
if (this.image_.getState() == ImageState.LOADED) {
|
||||
const imageExtent = this.image_.getExtent();
|
||||
const image = this.image_.getImage();
|
||||
let imageWidth, imageHeight;
|
||||
if (this.imageSize_) {
|
||||
imageWidth = this.imageSize_[0];
|
||||
imageHeight = this.imageSize_[1];
|
||||
} else {
|
||||
imageWidth = image.width;
|
||||
imageHeight = image.height;
|
||||
}
|
||||
const extentWidth = getWidth(imageExtent);
|
||||
const extentHeight = getHeight(imageExtent);
|
||||
const xResolution = extentWidth / imageWidth;
|
||||
const yResolution = extentHeight / imageHeight;
|
||||
let targetWidth = imageWidth;
|
||||
let targetHeight = imageHeight;
|
||||
if (xResolution > yResolution) {
|
||||
targetWidth = Math.round(extentWidth / yResolution);
|
||||
} else {
|
||||
targetHeight = Math.round(extentHeight / xResolution);
|
||||
}
|
||||
if (targetWidth !== imageWidth || targetHeight !== imageHeight) {
|
||||
const context = createCanvasContext2D(targetWidth, targetHeight);
|
||||
if (!this.getInterpolate()) {
|
||||
assign(context, IMAGE_SMOOTHING_DISABLED);
|
||||
}
|
||||
const canvas = context.canvas;
|
||||
context.drawImage(
|
||||
image,
|
||||
0,
|
||||
0,
|
||||
imageWidth,
|
||||
imageHeight,
|
||||
0,
|
||||
0,
|
||||
canvas.width,
|
||||
canvas.height
|
||||
);
|
||||
this.image_.setImage(canvas);
|
||||
}
|
||||
}
|
||||
super.handleImageChange(evt);
|
||||
}
|
||||
}
|
||||
|
||||
export default Static;
|
||||
498
node_modules/ol/src/source/ImageWMS.js
generated
vendored
Normal file
498
node_modules/ol/src/source/ImageWMS.js
generated
vendored
Normal file
@@ -0,0 +1,498 @@
|
||||
/**
|
||||
* @module ol/source/ImageWMS
|
||||
*/
|
||||
|
||||
import EventType from '../events/EventType.js';
|
||||
import ImageSource, {defaultImageLoadFunction} from './Image.js';
|
||||
import ImageWrapper from '../Image.js';
|
||||
import {DEFAULT_VERSION} from './wms.js';
|
||||
import {appendParams} from '../uri.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {calculateSourceResolution} from '../reproj.js';
|
||||
import {ceil, floor, round} from '../math.js';
|
||||
import {compareVersions} from '../string.js';
|
||||
import {
|
||||
containsExtent,
|
||||
getCenter,
|
||||
getForViewAndSize,
|
||||
getHeight,
|
||||
getWidth,
|
||||
} from '../extent.js';
|
||||
import {get as getProjection, transform} from '../proj.js';
|
||||
|
||||
/**
|
||||
* Number of decimal digits to consider in integer values when rounding.
|
||||
* @type {number}
|
||||
*/
|
||||
const DECIMALS = 4;
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {import("../size.js").Size}
|
||||
*/
|
||||
const GETFEATUREINFO_IMAGE_SIZE = [101, 101];
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [hidpi=true] Use the `ol/Map#pixelRatio` value when requesting
|
||||
* the image from the remote server.
|
||||
* @property {import("./wms.js").ServerType} [serverType] The type of
|
||||
* the remote WMS server: `mapserver`, `geoserver`, `carmentaserver`, or `qgis`.
|
||||
* Only needed if `hidpi` is `true`.
|
||||
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given a URL.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {Object<string,*>} params WMS request parameters.
|
||||
* At least a `LAYERS` param is required. `STYLES` is
|
||||
* `''` by default. `VERSION` is `1.3.0` by default. `WIDTH`, `HEIGHT`, `BBOX`
|
||||
* and `CRS` (`SRS` for WMS version < 1.3.0) will be set dynamically.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {number} [ratio=1.5] Ratio. `1` means image requests are the size of the map viewport, `2` means
|
||||
* twice the width and height of the map viewport, and so on. Must be `1` or
|
||||
* higher.
|
||||
* @property {Array<number>} [resolutions] Resolutions.
|
||||
* If specified, requests will be made for these resolutions only.
|
||||
* @property {string} url WMS service URL.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Source for WMS servers providing single, untiled images.
|
||||
*
|
||||
* @fires module:ol/source/Image.ImageSourceEvent
|
||||
* @api
|
||||
*/
|
||||
class ImageWMS extends ImageSource {
|
||||
/**
|
||||
* @param {Options} [opt_options] ImageWMS options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
interpolate: interpolate,
|
||||
projection: options.projection,
|
||||
resolutions: options.resolutions,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?string}
|
||||
*/
|
||||
this.crossOrigin_ =
|
||||
options.crossOrigin !== undefined ? options.crossOrigin : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.url_ = options.url;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../Image.js").LoadFunction}
|
||||
*/
|
||||
this.imageLoadFunction_ =
|
||||
options.imageLoadFunction !== undefined
|
||||
? options.imageLoadFunction
|
||||
: defaultImageLoadFunction;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object}
|
||||
*/
|
||||
this.params_ = options.params || {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.v13_ = true;
|
||||
this.updateV13_();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./wms.js").ServerType}
|
||||
*/
|
||||
this.serverType_ = options.serverType;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../Image.js").default}
|
||||
*/
|
||||
this.image_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../size.js").Size}
|
||||
*/
|
||||
this.imageSize_ = [0, 0];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.renderedRevision_ = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the GetFeatureInfo URL for the passed coordinate, resolution, and
|
||||
* projection. Return `undefined` if the GetFeatureInfo URL cannot be
|
||||
* constructed.
|
||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {import("../proj.js").ProjectionLike} projection Projection.
|
||||
* @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should
|
||||
* be provided. If `QUERY_LAYERS` is not provided then the layers specified
|
||||
* in the `LAYERS` parameter will be used. `VERSION` should not be
|
||||
* specified here.
|
||||
* @return {string|undefined} GetFeatureInfo URL.
|
||||
* @api
|
||||
*/
|
||||
getFeatureInfoUrl(coordinate, resolution, projection, params) {
|
||||
if (this.url_ === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const projectionObj = getProjection(projection);
|
||||
const sourceProjectionObj = this.getProjection();
|
||||
|
||||
if (sourceProjectionObj && sourceProjectionObj !== projectionObj) {
|
||||
resolution = calculateSourceResolution(
|
||||
sourceProjectionObj,
|
||||
projectionObj,
|
||||
coordinate,
|
||||
resolution
|
||||
);
|
||||
coordinate = transform(coordinate, projectionObj, sourceProjectionObj);
|
||||
}
|
||||
|
||||
const extent = getForViewAndSize(
|
||||
coordinate,
|
||||
resolution,
|
||||
0,
|
||||
GETFEATUREINFO_IMAGE_SIZE
|
||||
);
|
||||
|
||||
const baseParams = {
|
||||
'SERVICE': 'WMS',
|
||||
'VERSION': DEFAULT_VERSION,
|
||||
'REQUEST': 'GetFeatureInfo',
|
||||
'FORMAT': 'image/png',
|
||||
'TRANSPARENT': true,
|
||||
'QUERY_LAYERS': this.params_['LAYERS'],
|
||||
};
|
||||
assign(baseParams, this.params_, params);
|
||||
|
||||
const x = floor((coordinate[0] - extent[0]) / resolution, DECIMALS);
|
||||
const y = floor((extent[3] - coordinate[1]) / resolution, DECIMALS);
|
||||
baseParams[this.v13_ ? 'I' : 'X'] = x;
|
||||
baseParams[this.v13_ ? 'J' : 'Y'] = y;
|
||||
|
||||
return this.getRequestUrl_(
|
||||
extent,
|
||||
GETFEATUREINFO_IMAGE_SIZE,
|
||||
1,
|
||||
sourceProjectionObj || projectionObj,
|
||||
baseParams
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the GetLegendGraphic URL, optionally optimized for the passed
|
||||
* resolution and possibly including any passed specific parameters. Returns
|
||||
* `undefined` if the GetLegendGraphic URL cannot be constructed.
|
||||
*
|
||||
* @param {number} [resolution] Resolution. If set to undefined, `SCALE`
|
||||
* will not be calculated and included in URL.
|
||||
* @param {Object} [params] GetLegendGraphic params. If `LAYER` is set, the
|
||||
* request is generated for this wms layer, else it will try to use the
|
||||
* configured wms layer. Default `FORMAT` is `image/png`.
|
||||
* `VERSION` should not be specified here.
|
||||
* @return {string|undefined} GetLegendGraphic URL.
|
||||
* @api
|
||||
*/
|
||||
getLegendUrl(resolution, params) {
|
||||
if (this.url_ === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const baseParams = {
|
||||
'SERVICE': 'WMS',
|
||||
'VERSION': DEFAULT_VERSION,
|
||||
'REQUEST': 'GetLegendGraphic',
|
||||
'FORMAT': 'image/png',
|
||||
};
|
||||
|
||||
if (params === undefined || params['LAYER'] === undefined) {
|
||||
const layers = this.params_.LAYERS;
|
||||
const isSingleLayer = !Array.isArray(layers) || layers.length === 1;
|
||||
if (!isSingleLayer) {
|
||||
return undefined;
|
||||
}
|
||||
baseParams['LAYER'] = layers;
|
||||
}
|
||||
|
||||
if (resolution !== undefined) {
|
||||
const mpu = this.getProjection()
|
||||
? this.getProjection().getMetersPerUnit()
|
||||
: 1;
|
||||
const pixelSize = 0.00028;
|
||||
baseParams['SCALE'] = (resolution * mpu) / pixelSize;
|
||||
}
|
||||
|
||||
assign(baseParams, params);
|
||||
|
||||
return appendParams(/** @type {string} */ (this.url_), baseParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user-provided params, i.e. those passed to the constructor through
|
||||
* the "params" option, and possibly updated using the updateParams method.
|
||||
* @return {Object} Params.
|
||||
* @api
|
||||
*/
|
||||
getParams() {
|
||||
return this.params_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../Image.js").default} Single image.
|
||||
*/
|
||||
getImageInternal(extent, resolution, pixelRatio, projection) {
|
||||
if (this.url_ === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
resolution = this.findNearestResolution(resolution);
|
||||
|
||||
if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) {
|
||||
pixelRatio = 1;
|
||||
}
|
||||
|
||||
const imageResolution = resolution / pixelRatio;
|
||||
|
||||
const center = getCenter(extent);
|
||||
const viewWidth = ceil(getWidth(extent) / imageResolution, DECIMALS);
|
||||
const viewHeight = ceil(getHeight(extent) / imageResolution, DECIMALS);
|
||||
const viewExtent = getForViewAndSize(center, imageResolution, 0, [
|
||||
viewWidth,
|
||||
viewHeight,
|
||||
]);
|
||||
const requestWidth = ceil(
|
||||
(this.ratio_ * getWidth(extent)) / imageResolution,
|
||||
DECIMALS
|
||||
);
|
||||
const requestHeight = ceil(
|
||||
(this.ratio_ * getHeight(extent)) / imageResolution,
|
||||
DECIMALS
|
||||
);
|
||||
const requestExtent = getForViewAndSize(center, imageResolution, 0, [
|
||||
requestWidth,
|
||||
requestHeight,
|
||||
]);
|
||||
|
||||
const image = this.image_;
|
||||
if (
|
||||
image &&
|
||||
this.renderedRevision_ == this.getRevision() &&
|
||||
image.getResolution() == resolution &&
|
||||
image.getPixelRatio() == pixelRatio &&
|
||||
containsExtent(image.getExtent(), viewExtent)
|
||||
) {
|
||||
return image;
|
||||
}
|
||||
|
||||
const params = {
|
||||
'SERVICE': 'WMS',
|
||||
'VERSION': DEFAULT_VERSION,
|
||||
'REQUEST': 'GetMap',
|
||||
'FORMAT': 'image/png',
|
||||
'TRANSPARENT': true,
|
||||
};
|
||||
assign(params, this.params_);
|
||||
|
||||
this.imageSize_[0] = round(
|
||||
getWidth(requestExtent) / imageResolution,
|
||||
DECIMALS
|
||||
);
|
||||
this.imageSize_[1] = round(
|
||||
getHeight(requestExtent) / imageResolution,
|
||||
DECIMALS
|
||||
);
|
||||
|
||||
const url = this.getRequestUrl_(
|
||||
requestExtent,
|
||||
this.imageSize_,
|
||||
pixelRatio,
|
||||
projection,
|
||||
params
|
||||
);
|
||||
|
||||
this.image_ = new ImageWrapper(
|
||||
requestExtent,
|
||||
resolution,
|
||||
pixelRatio,
|
||||
url,
|
||||
this.crossOrigin_,
|
||||
this.imageLoadFunction_
|
||||
);
|
||||
|
||||
this.renderedRevision_ = this.getRevision();
|
||||
|
||||
this.image_.addEventListener(
|
||||
EventType.CHANGE,
|
||||
this.handleImageChange.bind(this)
|
||||
);
|
||||
|
||||
return this.image_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image load function of the source.
|
||||
* @return {import("../Image.js").LoadFunction} The image load function.
|
||||
* @api
|
||||
*/
|
||||
getImageLoadFunction() {
|
||||
return this.imageLoadFunction_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {import("../size.js").Size} size Size.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @param {Object} params Params.
|
||||
* @return {string} Request URL.
|
||||
* @private
|
||||
*/
|
||||
getRequestUrl_(extent, size, pixelRatio, projection, params) {
|
||||
assert(this.url_ !== undefined, 9); // `url` must be configured or set using `#setUrl()`
|
||||
|
||||
params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode();
|
||||
|
||||
if (!('STYLES' in this.params_)) {
|
||||
params['STYLES'] = '';
|
||||
}
|
||||
|
||||
if (pixelRatio != 1) {
|
||||
switch (this.serverType_) {
|
||||
case 'geoserver':
|
||||
const dpi = (90 * pixelRatio + 0.5) | 0;
|
||||
if ('FORMAT_OPTIONS' in params) {
|
||||
params['FORMAT_OPTIONS'] += ';dpi:' + dpi;
|
||||
} else {
|
||||
params['FORMAT_OPTIONS'] = 'dpi:' + dpi;
|
||||
}
|
||||
break;
|
||||
case 'mapserver':
|
||||
params['MAP_RESOLUTION'] = 90 * pixelRatio;
|
||||
break;
|
||||
case 'carmentaserver':
|
||||
case 'qgis':
|
||||
params['DPI'] = 90 * pixelRatio;
|
||||
break;
|
||||
default: // Unknown `serverType` configured
|
||||
assert(false, 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
params['WIDTH'] = size[0];
|
||||
params['HEIGHT'] = size[1];
|
||||
|
||||
const axisOrientation = projection.getAxisOrientation();
|
||||
let bbox;
|
||||
if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') {
|
||||
bbox = [extent[1], extent[0], extent[3], extent[2]];
|
||||
} else {
|
||||
bbox = extent;
|
||||
}
|
||||
params['BBOX'] = bbox.join(',');
|
||||
|
||||
return appendParams(/** @type {string} */ (this.url_), params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL used for this WMS source.
|
||||
* @return {string|undefined} URL.
|
||||
* @api
|
||||
*/
|
||||
getUrl() {
|
||||
return this.url_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the image load function of the source.
|
||||
* @param {import("../Image.js").LoadFunction} imageLoadFunction Image load function.
|
||||
* @api
|
||||
*/
|
||||
setImageLoadFunction(imageLoadFunction) {
|
||||
this.image_ = null;
|
||||
this.imageLoadFunction_ = imageLoadFunction;
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to use for requests.
|
||||
* @param {string|undefined} url URL.
|
||||
* @api
|
||||
*/
|
||||
setUrl(url) {
|
||||
if (url != this.url_) {
|
||||
this.url_ = url;
|
||||
this.image_ = null;
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user-provided params.
|
||||
* @param {Object} params Params.
|
||||
* @api
|
||||
*/
|
||||
updateParams(params) {
|
||||
assign(this.params_, params);
|
||||
this.updateV13_();
|
||||
this.image_ = null;
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateV13_() {
|
||||
const version = this.params_['VERSION'] || DEFAULT_VERSION;
|
||||
this.v13_ = compareVersions(version, '1.3') >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
export default ImageWMS;
|
||||
100
node_modules/ol/src/source/OGCMapTile.js
generated
vendored
Normal file
100
node_modules/ol/src/source/OGCMapTile.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @module ol/source/OGCMapTile
|
||||
*/
|
||||
import TileImage from './TileImage.js';
|
||||
import {getTileSetInfo} from './ogcTileUtil.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {string} url URL to the OGC Map Tileset endpoint.
|
||||
* @property {Object} [context] A lookup of values to use in the tile URL template. The `{tileMatrix}`
|
||||
* (zoom level), `{tileRow}`, and `{tileCol}` variables in the URL will always be provided by the source.
|
||||
* @property {string} [mediaType] The content type for the tiles (e.g. "image/png"). If not provided,
|
||||
* the source will try to find a link with rel="item" that uses a supported image type.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. By default, the projection
|
||||
* will be derived from the `crs` of the `tileMatrixSet`. You can override this by supplying
|
||||
* a projection to the constructor.
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {number} [cacheSize] Tile cache size. The default depends on the screen size. Will be ignored if too small.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is
|
||||
* ```js
|
||||
* function(tile, src) {
|
||||
* tile.getImage().src = src;
|
||||
* };
|
||||
* ```
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* @property {number} [transition] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for map tiles from an [OGC API - Tiles](https://ogcapi.ogc.org/tiles/) service that provides "map" type tiles.
|
||||
* The service must conform to at least the core (http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/core)
|
||||
* and tileset (http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tileset) conformance classes.
|
||||
*/
|
||||
class OGCMapTile extends TileImage {
|
||||
/**
|
||||
* @param {Options} options OGC map tile options.
|
||||
*/
|
||||
constructor(options) {
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: options.crossOrigin,
|
||||
interpolate: interpolate,
|
||||
projection: options.projection,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
state: 'loading',
|
||||
tileLoadFunction: options.tileLoadFunction,
|
||||
wrapX: options.wrapX !== undefined ? options.wrapX : true,
|
||||
transition: options.transition,
|
||||
});
|
||||
|
||||
const sourceInfo = {
|
||||
url: options.url,
|
||||
projection: this.getProjection(),
|
||||
mediaType: options.mediaType,
|
||||
context: options.context || null,
|
||||
};
|
||||
|
||||
getTileSetInfo(sourceInfo)
|
||||
.then(this.handleTileSetInfo_.bind(this))
|
||||
.catch(this.handleError_.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./ogcTileUtil.js").TileSetInfo} tileSetInfo Tile set info.
|
||||
* @private
|
||||
*/
|
||||
handleTileSetInfo_(tileSetInfo) {
|
||||
this.tileGrid = tileSetInfo.grid;
|
||||
this.setTileUrlFunction(tileSetInfo.urlFunction, tileSetInfo.urlTemplate);
|
||||
this.setState('ready');
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Error} error The error.
|
||||
*/
|
||||
handleError_(error) {
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
this.setState('error');
|
||||
}
|
||||
}
|
||||
|
||||
export default OGCMapTile;
|
||||
99
node_modules/ol/src/source/OGCVectorTile.js
generated
vendored
Normal file
99
node_modules/ol/src/source/OGCVectorTile.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @module ol/source/OGCVectorTile
|
||||
*/
|
||||
|
||||
import VectorTile from './VectorTile.js';
|
||||
import {getTileSetInfo} from './ogcTileUtil.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {string} url URL to the OGC Vector Tileset endpoint.
|
||||
* @property {Object} [context] A lookup of values to use in the tile URL template. The `{tileMatrix}`
|
||||
* (zoom level), `{tileRow}`, and `{tileCol}` variables in the URL will always be provided by the source.
|
||||
* @property {import("../format/Feature.js").default} format Feature parser for tiles.
|
||||
* @property {string} [mediaType] The content type for the tiles (e.g. "application/vnd.mapbox-vector-tile"). If not provided,
|
||||
* the source will try to find a link with rel="item" that uses a vector type supported by the configured format.
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least twice the number of tiles in the viewport.
|
||||
* @property {boolean} [overlaps=true] This source may have overlapping geometries. Setting this
|
||||
* to `false` (e.g. for sources with polygons that represent administrative
|
||||
* boundaries or TopoJSON sources) allows the renderer to optimise fill and
|
||||
* stroke operations.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Projection of the tile grid.
|
||||
* @property {typeof import("../VectorTile.js").default} [tileClass] Class used to instantiate image tiles.
|
||||
* Default is {@link module:ol/VectorTile~VectorTile}.
|
||||
* @property {number} [transition] A duration for tile opacity
|
||||
* transitions in milliseconds. A duration of 0 disables the opacity transition.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* When set to `false`, only one world
|
||||
* will be rendered. When set to `true`, tiles will be wrapped horizontally to
|
||||
* render multiple worlds.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=1]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for map tiles from an [OGC API - Tiles](https://ogcapi.ogc.org/tiles/) service that provides "vector" type tiles.
|
||||
* The service must conform to at least the core (http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/core)
|
||||
* and tileset (http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tileset) conformance classes.
|
||||
*
|
||||
* Vector tile sets may come in a variety of formats (e.g. GeoJSON, MVT). The `format` option is used to determine
|
||||
* which of the advertised media types is used. If you need to force the use of a particular media type, you can
|
||||
* provide the `mediaType` option.
|
||||
*/
|
||||
class OGCVectorTile extends VectorTile {
|
||||
/**
|
||||
* @param {Options} options OGC vector tile options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
attributionsCollapsible: options.attributionsCollapsible,
|
||||
cacheSize: options.cacheSize,
|
||||
format: options.format,
|
||||
overlaps: options.overlaps,
|
||||
projection: options.projection,
|
||||
tileClass: options.tileClass,
|
||||
transition: options.transition,
|
||||
wrapX: options.wrapX,
|
||||
zDirection: options.zDirection,
|
||||
state: 'loading',
|
||||
});
|
||||
|
||||
const sourceInfo = {
|
||||
url: options.url,
|
||||
projection: this.getProjection(),
|
||||
mediaType: options.mediaType,
|
||||
supportedMediaTypes: options.format.supportedMediaTypes,
|
||||
context: options.context || null,
|
||||
};
|
||||
|
||||
getTileSetInfo(sourceInfo)
|
||||
.then(this.handleTileSetInfo_.bind(this))
|
||||
.catch(this.handleError_.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./ogcTileUtil.js").TileSetInfo} tileSetInfo Tile set info.
|
||||
* @private
|
||||
*/
|
||||
handleTileSetInfo_(tileSetInfo) {
|
||||
this.tileGrid = tileSetInfo.grid;
|
||||
this.setTileUrlFunction(tileSetInfo.urlFunction, tileSetInfo.urlTemplate);
|
||||
this.setState('ready');
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Error} error The error.
|
||||
*/
|
||||
handleError_(error) {
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
this.setState('error');
|
||||
}
|
||||
}
|
||||
|
||||
export default OGCVectorTile;
|
||||
100
node_modules/ol/src/source/OSM.js
generated
vendored
Normal file
100
node_modules/ol/src/source/OSM.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @module ol/source/OSM
|
||||
*/
|
||||
|
||||
import XYZ from './XYZ.js';
|
||||
|
||||
/**
|
||||
* The attribution containing a link to the OpenStreetMap Copyright and License
|
||||
* page.
|
||||
* @const
|
||||
* @type {string}
|
||||
* @api
|
||||
*/
|
||||
export const ATTRIBUTION =
|
||||
'© ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> ' +
|
||||
'contributors.';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {null|string} [crossOrigin='anonymous'] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {number} [maxZoom=19] Max zoom.
|
||||
* @property {boolean} [opaque=true] Whether the layer is opaque.
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is
|
||||
* ```js
|
||||
* function(imageTile, src) {
|
||||
* imageTile.getImage().src = src;
|
||||
* };
|
||||
* ```
|
||||
* @property {number} [transition=250] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {string} [url='https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'] URL template.
|
||||
* Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for the OpenStreetMap tile server.
|
||||
* @api
|
||||
*/
|
||||
class OSM extends XYZ {
|
||||
/**
|
||||
* @param {Options} [opt_options] Open Street Map options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
const options = opt_options || {};
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
let attributions;
|
||||
if (options.attributions !== undefined) {
|
||||
attributions = options.attributions;
|
||||
} else {
|
||||
attributions = [ATTRIBUTION];
|
||||
}
|
||||
|
||||
const crossOrigin =
|
||||
options.crossOrigin !== undefined ? options.crossOrigin : 'anonymous';
|
||||
|
||||
const url =
|
||||
options.url !== undefined
|
||||
? options.url
|
||||
: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png';
|
||||
|
||||
super({
|
||||
attributions: attributions,
|
||||
attributionsCollapsible: false,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: crossOrigin,
|
||||
interpolate: interpolate,
|
||||
maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19,
|
||||
opaque: options.opaque !== undefined ? options.opaque : true,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
tileLoadFunction: options.tileLoadFunction,
|
||||
transition: options.transition,
|
||||
url: url,
|
||||
wrapX: options.wrapX,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default OSM;
|
||||
993
node_modules/ol/src/source/Raster.js
generated
vendored
Normal file
993
node_modules/ol/src/source/Raster.js
generated
vendored
Normal file
@@ -0,0 +1,993 @@
|
||||
/**
|
||||
* @module ol/source/Raster
|
||||
*/
|
||||
import Disposable from '../Disposable.js';
|
||||
import Event from '../events/Event.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import ImageCanvas from '../ImageCanvas.js';
|
||||
import ImageLayer from '../layer/Image.js';
|
||||
import ImageSource from './Image.js';
|
||||
import Source from './Source.js';
|
||||
import TileLayer from '../layer/Tile.js';
|
||||
import TileQueue from '../TileQueue.js';
|
||||
import TileSource from './Tile.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {createCanvasContext2D} from '../dom.js';
|
||||
import {create as createTransform} from '../transform.js';
|
||||
import {equals, getCenter, getHeight, getWidth} from '../extent.js';
|
||||
import {getUid} from '../util.js';
|
||||
|
||||
let hasImageData = true;
|
||||
try {
|
||||
new ImageData(10, 10);
|
||||
} catch (_) {
|
||||
hasImageData = false;
|
||||
}
|
||||
|
||||
/** @type {CanvasRenderingContext2D} */
|
||||
let context;
|
||||
|
||||
/**
|
||||
* @param {Uint8ClampedArray} data Image data.
|
||||
* @param {number} width Number of columns.
|
||||
* @param {number} height Number of rows.
|
||||
* @return {ImageData} Image data.
|
||||
*/
|
||||
export function newImageData(data, width, height) {
|
||||
if (hasImageData) {
|
||||
return new ImageData(data, width, height);
|
||||
}
|
||||
|
||||
if (!context) {
|
||||
context = document.createElement('canvas').getContext('2d');
|
||||
}
|
||||
const imageData = context.createImageData(width, height);
|
||||
imageData.data.set(data);
|
||||
return imageData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} MinionData
|
||||
* @property {Array<ArrayBuffer>} buffers Array of buffers.
|
||||
* @property {Object} meta Operation metadata.
|
||||
* @property {boolean} imageOps The operation is an image operation.
|
||||
* @property {number} width The width of the image.
|
||||
* @property {number} height The height of the image.
|
||||
*/
|
||||
|
||||
/* istanbul ignore next */
|
||||
/**
|
||||
* Create a function for running operations. This function is serialized for
|
||||
* use in a worker.
|
||||
* @param {function(Array, Object):*} operation The operation.
|
||||
* @return {function(MinionData):ArrayBuffer} A function that takes an object with
|
||||
* buffers, meta, imageOps, width, and height properties and returns an array
|
||||
* buffer.
|
||||
*/
|
||||
function createMinion(operation) {
|
||||
let workerHasImageData = true;
|
||||
try {
|
||||
new ImageData(10, 10);
|
||||
} catch (_) {
|
||||
workerHasImageData = false;
|
||||
}
|
||||
|
||||
function newWorkerImageData(data, width, height) {
|
||||
if (workerHasImageData) {
|
||||
return new ImageData(data, width, height);
|
||||
} else {
|
||||
return {data: data, width: width, height: height};
|
||||
}
|
||||
}
|
||||
|
||||
return function (data) {
|
||||
// bracket notation for minification support
|
||||
const buffers = data['buffers'];
|
||||
const meta = data['meta'];
|
||||
const imageOps = data['imageOps'];
|
||||
const width = data['width'];
|
||||
const height = data['height'];
|
||||
|
||||
const numBuffers = buffers.length;
|
||||
const numBytes = buffers[0].byteLength;
|
||||
|
||||
if (imageOps) {
|
||||
const images = new Array(numBuffers);
|
||||
for (let b = 0; b < numBuffers; ++b) {
|
||||
images[b] = newWorkerImageData(
|
||||
new Uint8ClampedArray(buffers[b]),
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
const output = operation(images, meta).data;
|
||||
return output.buffer;
|
||||
}
|
||||
|
||||
const output = new Uint8ClampedArray(numBytes);
|
||||
const arrays = new Array(numBuffers);
|
||||
const pixels = new Array(numBuffers);
|
||||
for (let b = 0; b < numBuffers; ++b) {
|
||||
arrays[b] = new Uint8ClampedArray(buffers[b]);
|
||||
pixels[b] = [0, 0, 0, 0];
|
||||
}
|
||||
for (let i = 0; i < numBytes; i += 4) {
|
||||
for (let j = 0; j < numBuffers; ++j) {
|
||||
const array = arrays[j];
|
||||
pixels[j][0] = array[i];
|
||||
pixels[j][1] = array[i + 1];
|
||||
pixels[j][2] = array[i + 2];
|
||||
pixels[j][3] = array[i + 3];
|
||||
}
|
||||
const pixel = operation(pixels, meta);
|
||||
output[i] = pixel[0];
|
||||
output[i + 1] = pixel[1];
|
||||
output[i + 2] = pixel[2];
|
||||
output[i + 3] = pixel[3];
|
||||
}
|
||||
return output.buffer;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a worker for running operations.
|
||||
* @param {ProcessorOptions} config Processor options.
|
||||
* @param {function(MessageEvent): void} onMessage Called with a message event.
|
||||
* @return {Worker} The worker.
|
||||
*/
|
||||
function createWorker(config, onMessage) {
|
||||
const lib = Object.keys(config.lib || {}).map(function (name) {
|
||||
return 'var ' + name + ' = ' + config.lib[name].toString() + ';';
|
||||
});
|
||||
|
||||
const lines = lib.concat([
|
||||
'var __minion__ = (' + createMinion.toString() + ')(',
|
||||
config.operation.toString(),
|
||||
');',
|
||||
'self.addEventListener("message", function(event) {',
|
||||
' var buffer = __minion__(event.data);',
|
||||
' self.postMessage({buffer: buffer, meta: event.data.meta}, [buffer]);',
|
||||
'});',
|
||||
]);
|
||||
|
||||
const worker = new Worker(
|
||||
typeof Blob === 'undefined'
|
||||
? 'data:text/javascript;base64,' +
|
||||
Buffer.from(lines.join('\n'), 'binary').toString('base64')
|
||||
: URL.createObjectURL(new Blob(lines, {type: 'text/javascript'}))
|
||||
);
|
||||
worker.addEventListener('message', onMessage);
|
||||
return worker;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} FauxMessageEvent
|
||||
* @property {Object} data Message data.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a faux worker for running operations.
|
||||
* @param {ProcessorOptions} config Configuration.
|
||||
* @param {function(FauxMessageEvent): void} onMessage Called with a message event.
|
||||
* @return {Object} The faux worker.
|
||||
*/
|
||||
function createFauxWorker(config, onMessage) {
|
||||
const minion = createMinion(config.operation);
|
||||
let terminated = false;
|
||||
return {
|
||||
postMessage: function (data) {
|
||||
setTimeout(function () {
|
||||
if (terminated) {
|
||||
return;
|
||||
}
|
||||
onMessage({data: {buffer: minion(data), meta: data['meta']}});
|
||||
}, 0);
|
||||
},
|
||||
terminate: function () {
|
||||
terminated = true;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {function(Error, ImageData, (Object|Array<Object>)): void} JobCallback
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Job
|
||||
* @property {Object} meta Job metadata.
|
||||
* @property {Array<ImageData>} inputs Array of input data.
|
||||
* @property {JobCallback} callback Called when the job is complete.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ProcessorOptions
|
||||
* @property {number} threads Number of workers to spawn.
|
||||
* @property {Operation} operation The operation.
|
||||
* @property {Object<string, Function>} [lib] Functions that will be made available to operations run in a worker.
|
||||
* @property {number} queue The number of queued jobs to allow.
|
||||
* @property {boolean} [imageOps=false] Pass all the image data to the operation instead of a single pixel.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A processor runs pixel or image operations in workers.
|
||||
*/
|
||||
export class Processor extends Disposable {
|
||||
/**
|
||||
* @param {ProcessorOptions} config Configuration.
|
||||
*/
|
||||
constructor(config) {
|
||||
super();
|
||||
|
||||
this._imageOps = !!config.imageOps;
|
||||
let threads;
|
||||
if (config.threads === 0) {
|
||||
threads = 0;
|
||||
} else if (this._imageOps) {
|
||||
threads = 1;
|
||||
} else {
|
||||
threads = config.threads || 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Array<Worker>}
|
||||
*/
|
||||
const workers = new Array(threads);
|
||||
if (threads) {
|
||||
for (let i = 0; i < threads; ++i) {
|
||||
workers[i] = createWorker(config, this._onWorkerMessage.bind(this, i));
|
||||
}
|
||||
} else {
|
||||
workers[0] = createFauxWorker(
|
||||
config,
|
||||
this._onWorkerMessage.bind(this, 0)
|
||||
);
|
||||
}
|
||||
this._workers = workers;
|
||||
|
||||
/**
|
||||
* @type {Array<Job>}
|
||||
* @private
|
||||
*/
|
||||
this._queue = [];
|
||||
|
||||
this._maxQueueLength = config.queue || Infinity;
|
||||
this._running = 0;
|
||||
|
||||
/**
|
||||
* @type {Object<number, any>}
|
||||
* @private
|
||||
*/
|
||||
this._dataLookup = {};
|
||||
|
||||
/**
|
||||
* @type {Job}
|
||||
* @private
|
||||
*/
|
||||
this._job = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run operation on input data.
|
||||
* @param {Array<ImageData>} inputs Array of image data.
|
||||
* @param {Object} meta A user data object. This is passed to all operations
|
||||
* and must be serializable.
|
||||
* @param {function(Error, ImageData, Object): void} callback Called when work
|
||||
* completes. The first argument is any error. The second is the ImageData
|
||||
* generated by operations. The third is the user data object.
|
||||
*/
|
||||
process(inputs, meta, callback) {
|
||||
this._enqueue({
|
||||
inputs: inputs,
|
||||
meta: meta,
|
||||
callback: callback,
|
||||
});
|
||||
this._dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a job to the queue.
|
||||
* @param {Job} job The job.
|
||||
*/
|
||||
_enqueue(job) {
|
||||
this._queue.push(job);
|
||||
while (this._queue.length > this._maxQueueLength) {
|
||||
this._queue.shift().callback(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a job.
|
||||
*/
|
||||
_dispatch() {
|
||||
if (this._running || this._queue.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const job = this._queue.shift();
|
||||
this._job = job;
|
||||
const width = job.inputs[0].width;
|
||||
const height = job.inputs[0].height;
|
||||
const buffers = job.inputs.map(function (input) {
|
||||
return input.data.buffer;
|
||||
});
|
||||
const threads = this._workers.length;
|
||||
this._running = threads;
|
||||
if (threads === 1) {
|
||||
this._workers[0].postMessage(
|
||||
{
|
||||
buffers: buffers,
|
||||
meta: job.meta,
|
||||
imageOps: this._imageOps,
|
||||
width: width,
|
||||
height: height,
|
||||
},
|
||||
buffers
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const length = job.inputs[0].data.length;
|
||||
const segmentLength = 4 * Math.ceil(length / 4 / threads);
|
||||
for (let i = 0; i < threads; ++i) {
|
||||
const offset = i * segmentLength;
|
||||
const slices = [];
|
||||
for (let j = 0, jj = buffers.length; j < jj; ++j) {
|
||||
slices.push(buffers[j].slice(offset, offset + segmentLength));
|
||||
}
|
||||
this._workers[i].postMessage(
|
||||
{
|
||||
buffers: slices,
|
||||
meta: job.meta,
|
||||
imageOps: this._imageOps,
|
||||
width: width,
|
||||
height: height,
|
||||
},
|
||||
slices
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle messages from the worker.
|
||||
* @param {number} index The worker index.
|
||||
* @param {MessageEvent} event The message event.
|
||||
*/
|
||||
_onWorkerMessage(index, event) {
|
||||
if (this.disposed) {
|
||||
return;
|
||||
}
|
||||
this._dataLookup[index] = event.data;
|
||||
--this._running;
|
||||
if (this._running === 0) {
|
||||
this._resolveJob();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a job. If there are no more worker threads, the processor callback
|
||||
* will be called.
|
||||
*/
|
||||
_resolveJob() {
|
||||
const job = this._job;
|
||||
const threads = this._workers.length;
|
||||
let data, meta;
|
||||
if (threads === 1) {
|
||||
data = new Uint8ClampedArray(this._dataLookup[0]['buffer']);
|
||||
meta = this._dataLookup[0]['meta'];
|
||||
} else {
|
||||
const length = job.inputs[0].data.length;
|
||||
data = new Uint8ClampedArray(length);
|
||||
meta = new Array(threads);
|
||||
const segmentLength = 4 * Math.ceil(length / 4 / threads);
|
||||
for (let i = 0; i < threads; ++i) {
|
||||
const buffer = this._dataLookup[i]['buffer'];
|
||||
const offset = i * segmentLength;
|
||||
data.set(new Uint8ClampedArray(buffer), offset);
|
||||
meta[i] = this._dataLookup[i]['meta'];
|
||||
}
|
||||
}
|
||||
this._job = null;
|
||||
this._dataLookup = {};
|
||||
job.callback(
|
||||
null,
|
||||
newImageData(data, job.inputs[0].width, job.inputs[0].height),
|
||||
meta
|
||||
);
|
||||
this._dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate all workers associated with the processor.
|
||||
*/
|
||||
disposeInternal() {
|
||||
for (let i = 0; i < this._workers.length; ++i) {
|
||||
this._workers[i].terminate();
|
||||
}
|
||||
this._workers.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that takes an array of input data, performs some operation, and
|
||||
* returns an array of output data.
|
||||
* For `pixel` type operations, the function will be called with an array of
|
||||
* pixels, where each pixel is an array of four numbers (`[r, g, b, a]`) in the
|
||||
* range of 0 - 255. It should return a single pixel array.
|
||||
* For `'image'` type operations, functions will be called with an array of
|
||||
* [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData)
|
||||
* and should return a single
|
||||
* [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData).
|
||||
* The operations
|
||||
* are called with a second "data" argument, which can be used for storage. The
|
||||
* data object is accessible from raster events, where it can be initialized in
|
||||
* "beforeoperations" and accessed again in "afteroperations".
|
||||
*
|
||||
* @typedef {function((Array<Array<number>>|Array<ImageData>), Object):
|
||||
* (Array<number>|ImageData)} Operation
|
||||
*/
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
const RasterEventType = {
|
||||
/**
|
||||
* Triggered before operations are run. Listeners will receive an event object with
|
||||
* a `data` property that can be used to make data available to operations.
|
||||
* @event module:ol/source/Raster.RasterSourceEvent#beforeoperations
|
||||
* @api
|
||||
*/
|
||||
BEFOREOPERATIONS: 'beforeoperations',
|
||||
|
||||
/**
|
||||
* Triggered after operations are run. Listeners will receive an event object with
|
||||
* a `data` property. If more than one thread is used, `data` will be an array of
|
||||
* objects. If a single thread is used, `data` will be a single object.
|
||||
* @event module:ol/source/Raster.RasterSourceEvent#afteroperations
|
||||
* @api
|
||||
*/
|
||||
AFTEROPERATIONS: 'afteroperations',
|
||||
};
|
||||
|
||||
/**
|
||||
* Raster operation type. Supported values are `'pixel'` and `'image'`.
|
||||
* @enum {string}
|
||||
*/
|
||||
const RasterOperationType = {
|
||||
PIXEL: 'pixel',
|
||||
IMAGE: 'image',
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {import("./Image.js").ImageSourceEventTypes|'beforeoperations'|'afteroperations'} RasterSourceEventTypes
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Events emitted by {@link module:ol/source/Raster~RasterSource} instances are instances of this
|
||||
* type.
|
||||
*/
|
||||
export class RasterSourceEvent extends Event {
|
||||
/**
|
||||
* @param {string} type Type.
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState The frame state.
|
||||
* @param {Object|Array<Object>} data An object made available to operations. For "afteroperations" evenets
|
||||
* this will be an array of objects if more than one thread is used.
|
||||
*/
|
||||
constructor(type, frameState, data) {
|
||||
super(type);
|
||||
|
||||
/**
|
||||
* The raster extent.
|
||||
* @type {import("../extent.js").Extent}
|
||||
* @api
|
||||
*/
|
||||
this.extent = frameState.extent;
|
||||
|
||||
/**
|
||||
* The pixel resolution (map units per pixel).
|
||||
* @type {number}
|
||||
* @api
|
||||
*/
|
||||
this.resolution = frameState.viewState.resolution / frameState.pixelRatio;
|
||||
|
||||
/**
|
||||
* An object made available to all operations. This can be used by operations
|
||||
* as a storage object (e.g. for calculating statistics).
|
||||
* @type {Object}
|
||||
* @api
|
||||
*/
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {Array<import("./Source.js").default|import("../layer/Layer.js").default>} sources Input
|
||||
* sources or layers. For vector data, use an VectorImage layer.
|
||||
* @property {Operation} [operation] Raster operation.
|
||||
* The operation will be called with data from input sources
|
||||
* and the output will be assigned to the raster source.
|
||||
* @property {Object} [lib] Functions that will be made available to operations run in a worker.
|
||||
* @property {number} [threads] By default, operations will be run in a single worker thread.
|
||||
* To avoid using workers altogether, set `threads: 0`. For pixel operations, operations can
|
||||
* be run in multiple worker threads. Note that there is additional overhead in
|
||||
* transferring data to multiple workers, and that depending on the user's
|
||||
* system, it may not be possible to parallelize the work.
|
||||
* @property {RasterOperationType} [operationType='pixel'] Operation type.
|
||||
* Supported values are `'pixel'` and `'image'`. By default,
|
||||
* `'pixel'` operations are assumed, and operations will be called with an
|
||||
* array of pixels from input sources. If set to `'image'`, operations will
|
||||
* be called with an array of ImageData objects from input sources.
|
||||
*/
|
||||
|
||||
/***
|
||||
* @template Return
|
||||
* @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> &
|
||||
* import("../Observable").OnSignature<import("../ObjectEventType").Types, import("../Object").ObjectEvent, Return> &
|
||||
* import("../Observable").OnSignature<import("./Image.js").ImageSourceEventTypes, import("./Image.js").ImageSourceEvent, Return> &
|
||||
* import("../Observable").OnSignature<RasterSourceEventTypes, RasterSourceEvent, Return> &
|
||||
* import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("../ObjectEventType").Types
|
||||
* |RasterSourceEventTypes, Return>} RasterSourceOnSignature
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A source that transforms data from any number of input sources using an
|
||||
* {@link module:ol/source/Raster~Operation} function to transform input pixel values into
|
||||
* output pixel values.
|
||||
*
|
||||
* @fires module:ol/source/Raster.RasterSourceEvent
|
||||
* @api
|
||||
*/
|
||||
class RasterSource extends ImageSource {
|
||||
/**
|
||||
* @param {Options} options Options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super({
|
||||
projection: null,
|
||||
});
|
||||
|
||||
/***
|
||||
* @type {RasterSourceOnSignature<import("../events").EventsKey>}
|
||||
*/
|
||||
this.on;
|
||||
|
||||
/***
|
||||
* @type {RasterSourceOnSignature<import("../events").EventsKey>}
|
||||
*/
|
||||
this.once;
|
||||
|
||||
/***
|
||||
* @type {RasterSourceOnSignature<void>}
|
||||
*/
|
||||
this.un;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Processor}
|
||||
*/
|
||||
this.processor_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {RasterOperationType}
|
||||
*/
|
||||
this.operationType_ =
|
||||
options.operationType !== undefined
|
||||
? options.operationType
|
||||
: RasterOperationType.PIXEL;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.threads_ = options.threads !== undefined ? options.threads : 1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<import("../layer/Layer.js").default>}
|
||||
*/
|
||||
this.layers_ = createLayers(options.sources);
|
||||
|
||||
const changed = this.changed.bind(this);
|
||||
for (let i = 0, ii = this.layers_.length; i < ii; ++i) {
|
||||
this.layers_[i].addEventListener(EventType.CHANGE, changed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../TileQueue.js").default}
|
||||
*/
|
||||
this.tileQueue_ = new TileQueue(function () {
|
||||
return 1;
|
||||
}, this.changed.bind(this));
|
||||
|
||||
/**
|
||||
* The most recently requested frame state.
|
||||
* @type {import("../PluggableMap.js").FrameState}
|
||||
* @private
|
||||
*/
|
||||
this.requestedFrameState_;
|
||||
|
||||
/**
|
||||
* The most recently rendered image canvas.
|
||||
* @type {import("../ImageCanvas.js").default}
|
||||
* @private
|
||||
*/
|
||||
this.renderedImageCanvas_ = null;
|
||||
|
||||
/**
|
||||
* The most recently rendered revision.
|
||||
* @type {number}
|
||||
*/
|
||||
this.renderedRevision_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../PluggableMap.js").FrameState}
|
||||
*/
|
||||
this.frameState_ = {
|
||||
animate: false,
|
||||
coordinateToPixelTransform: createTransform(),
|
||||
declutterTree: null,
|
||||
extent: null,
|
||||
index: 0,
|
||||
layerIndex: 0,
|
||||
layerStatesArray: getLayerStatesArray(this.layers_),
|
||||
pixelRatio: 1,
|
||||
pixelToCoordinateTransform: createTransform(),
|
||||
postRenderFunctions: [],
|
||||
size: [0, 0],
|
||||
tileQueue: this.tileQueue_,
|
||||
time: Date.now(),
|
||||
usedTiles: {},
|
||||
viewState: /** @type {import("../View.js").State} */ ({
|
||||
rotation: 0,
|
||||
}),
|
||||
viewHints: [],
|
||||
wantedTiles: {},
|
||||
mapId: getUid(this),
|
||||
renderTargets: {},
|
||||
};
|
||||
|
||||
this.setAttributions(function (frameState) {
|
||||
const attributions = [];
|
||||
for (
|
||||
let index = 0, iMax = options.sources.length;
|
||||
index < iMax;
|
||||
++index
|
||||
) {
|
||||
const sourceOrLayer = options.sources[index];
|
||||
const source =
|
||||
sourceOrLayer instanceof Source
|
||||
? sourceOrLayer
|
||||
: sourceOrLayer.getSource();
|
||||
const attributionGetter = source.getAttributions();
|
||||
if (typeof attributionGetter === 'function') {
|
||||
const sourceAttribution = attributionGetter(frameState);
|
||||
attributions.push.apply(attributions, sourceAttribution);
|
||||
}
|
||||
}
|
||||
return attributions.length !== 0 ? attributions : null;
|
||||
});
|
||||
|
||||
if (options.operation !== undefined) {
|
||||
this.setOperation(options.operation, options.lib);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the operation.
|
||||
* @param {Operation} operation New operation.
|
||||
* @param {Object} [opt_lib] Functions that will be available to operations run
|
||||
* in a worker.
|
||||
* @api
|
||||
*/
|
||||
setOperation(operation, opt_lib) {
|
||||
if (this.processor_) {
|
||||
this.processor_.dispose();
|
||||
}
|
||||
|
||||
this.processor_ = new Processor({
|
||||
operation: operation,
|
||||
imageOps: this.operationType_ === RasterOperationType.IMAGE,
|
||||
queue: 1,
|
||||
lib: opt_lib,
|
||||
threads: this.threads_,
|
||||
});
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the stored frame state.
|
||||
* @param {import("../extent.js").Extent} extent The view extent (in map units).
|
||||
* @param {number} resolution The view resolution.
|
||||
* @param {import("../proj/Projection.js").default} projection The view projection.
|
||||
* @return {import("../PluggableMap.js").FrameState} The updated frame state.
|
||||
* @private
|
||||
*/
|
||||
updateFrameState_(extent, resolution, projection) {
|
||||
const frameState = /** @type {import("../PluggableMap.js").FrameState} */ (
|
||||
assign({}, this.frameState_)
|
||||
);
|
||||
|
||||
frameState.viewState = /** @type {import("../View.js").State} */ (
|
||||
assign({}, frameState.viewState)
|
||||
);
|
||||
|
||||
const center = getCenter(extent);
|
||||
|
||||
frameState.extent = extent.slice();
|
||||
frameState.size[0] = Math.round(getWidth(extent) / resolution);
|
||||
frameState.size[1] = Math.round(getHeight(extent) / resolution);
|
||||
frameState.time = Date.now();
|
||||
|
||||
const viewState = frameState.viewState;
|
||||
viewState.center = center;
|
||||
viewState.projection = projection;
|
||||
viewState.resolution = resolution;
|
||||
return frameState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if all sources are ready.
|
||||
* @return {boolean} All sources are ready.
|
||||
* @private
|
||||
*/
|
||||
allSourcesReady_() {
|
||||
let ready = true;
|
||||
let source;
|
||||
for (let i = 0, ii = this.layers_.length; i < ii; ++i) {
|
||||
source = this.layers_[i].getSource();
|
||||
if (source.getState() !== 'ready') {
|
||||
ready = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../ImageCanvas.js").default} Single image.
|
||||
*/
|
||||
getImage(extent, resolution, pixelRatio, projection) {
|
||||
if (!this.allSourcesReady_()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const frameState = this.updateFrameState_(extent, resolution, projection);
|
||||
this.requestedFrameState_ = frameState;
|
||||
|
||||
// check if we can't reuse the existing ol/ImageCanvas
|
||||
if (this.renderedImageCanvas_) {
|
||||
const renderedResolution = this.renderedImageCanvas_.getResolution();
|
||||
const renderedExtent = this.renderedImageCanvas_.getExtent();
|
||||
if (
|
||||
resolution !== renderedResolution ||
|
||||
!equals(extent, renderedExtent)
|
||||
) {
|
||||
this.renderedImageCanvas_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!this.renderedImageCanvas_ ||
|
||||
this.getRevision() !== this.renderedRevision_
|
||||
) {
|
||||
this.processSources_();
|
||||
}
|
||||
|
||||
frameState.tileQueue.loadMoreTiles(16, 16);
|
||||
|
||||
if (frameState.animate) {
|
||||
requestAnimationFrame(this.changed.bind(this));
|
||||
}
|
||||
|
||||
return this.renderedImageCanvas_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start processing source data.
|
||||
* @private
|
||||
*/
|
||||
processSources_() {
|
||||
const frameState = this.requestedFrameState_;
|
||||
const len = this.layers_.length;
|
||||
const imageDatas = new Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
frameState.layerIndex = i;
|
||||
const imageData = getImageData(this.layers_[i], frameState);
|
||||
if (imageData) {
|
||||
imageDatas[i] = imageData;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const data = {};
|
||||
this.dispatchEvent(
|
||||
new RasterSourceEvent(RasterEventType.BEFOREOPERATIONS, frameState, data)
|
||||
);
|
||||
this.processor_.process(
|
||||
imageDatas,
|
||||
data,
|
||||
this.onWorkerComplete_.bind(this, frameState)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when pixel processing is complete.
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState The frame state.
|
||||
* @param {Error} err Any error during processing.
|
||||
* @param {ImageData} output The output image data.
|
||||
* @param {Object|Array<Object>} data The user data (or an array if more than one thread).
|
||||
* @private
|
||||
*/
|
||||
onWorkerComplete_(frameState, err, output, data) {
|
||||
if (err || !output) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do nothing if extent or resolution changed
|
||||
const extent = frameState.extent;
|
||||
const resolution = frameState.viewState.resolution;
|
||||
if (
|
||||
resolution !== this.requestedFrameState_.viewState.resolution ||
|
||||
!equals(extent, this.requestedFrameState_.extent)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let context;
|
||||
if (this.renderedImageCanvas_) {
|
||||
context = this.renderedImageCanvas_.getImage().getContext('2d');
|
||||
} else {
|
||||
const width = Math.round(getWidth(extent) / resolution);
|
||||
const height = Math.round(getHeight(extent) / resolution);
|
||||
context = createCanvasContext2D(width, height);
|
||||
this.renderedImageCanvas_ = new ImageCanvas(
|
||||
extent,
|
||||
resolution,
|
||||
1,
|
||||
context.canvas
|
||||
);
|
||||
}
|
||||
context.putImageData(output, 0, 0);
|
||||
|
||||
this.changed();
|
||||
this.renderedRevision_ = this.getRevision();
|
||||
|
||||
this.dispatchEvent(
|
||||
new RasterSourceEvent(RasterEventType.AFTEROPERATIONS, frameState, data)
|
||||
);
|
||||
if (frameState.animate) {
|
||||
requestAnimationFrame(this.changed.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
disposeInternal() {
|
||||
if (this.processor_) {
|
||||
this.processor_.dispose();
|
||||
}
|
||||
super.disposeInternal();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up and unregister the worker.
|
||||
* @function
|
||||
* @api
|
||||
*/
|
||||
RasterSource.prototype.dispose;
|
||||
|
||||
/**
|
||||
* A reusable canvas context.
|
||||
* @type {CanvasRenderingContext2D}
|
||||
* @private
|
||||
*/
|
||||
let sharedContext = null;
|
||||
|
||||
/**
|
||||
* Get image data from a layer.
|
||||
* @param {import("../layer/Layer.js").default} layer Layer to render.
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState The frame state.
|
||||
* @return {ImageData} The image data.
|
||||
*/
|
||||
function getImageData(layer, frameState) {
|
||||
const renderer = layer.getRenderer();
|
||||
if (!renderer) {
|
||||
throw new Error('Unsupported layer type: ' + layer);
|
||||
}
|
||||
|
||||
if (!renderer.prepareFrame(frameState)) {
|
||||
return null;
|
||||
}
|
||||
const width = frameState.size[0];
|
||||
const height = frameState.size[1];
|
||||
if (width === 0 || height === 0) {
|
||||
return null;
|
||||
}
|
||||
const container = renderer.renderFrame(frameState, null);
|
||||
let element;
|
||||
if (container instanceof HTMLCanvasElement) {
|
||||
element = container;
|
||||
} else {
|
||||
if (container) {
|
||||
element = container.firstElementChild;
|
||||
}
|
||||
if (!(element instanceof HTMLCanvasElement)) {
|
||||
throw new Error('Unsupported rendered element: ' + element);
|
||||
}
|
||||
if (element.width === width && element.height === height) {
|
||||
const context = element.getContext('2d');
|
||||
return context.getImageData(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sharedContext) {
|
||||
sharedContext = createCanvasContext2D(width, height);
|
||||
} else {
|
||||
const canvas = sharedContext.canvas;
|
||||
if (canvas.width !== width || canvas.height !== height) {
|
||||
sharedContext = createCanvasContext2D(width, height);
|
||||
} else {
|
||||
sharedContext.clearRect(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
sharedContext.drawImage(element, 0, 0, width, height);
|
||||
return sharedContext.getImageData(0, 0, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of layer states from a list of layers.
|
||||
* @param {Array<import("../layer/Layer.js").default>} layers Layers.
|
||||
* @return {Array<import("../layer/Layer.js").State>} The layer states.
|
||||
*/
|
||||
function getLayerStatesArray(layers) {
|
||||
return layers.map(function (layer) {
|
||||
return layer.getLayerState();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create layers for all sources.
|
||||
* @param {Array<import("./Source.js").default|import("../layer/Layer.js").default>} sources The sources.
|
||||
* @return {Array<import("../layer/Layer.js").default>} Array of layers.
|
||||
*/
|
||||
function createLayers(sources) {
|
||||
const len = sources.length;
|
||||
const layers = new Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
layers[i] = createLayer(sources[i]);
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a layer for the provided source.
|
||||
* @param {import("./Source.js").default|import("../layer/Layer.js").default} layerOrSource The layer or source.
|
||||
* @return {import("../layer/Layer.js").default} The layer.
|
||||
*/
|
||||
function createLayer(layerOrSource) {
|
||||
// @type {import("../layer/Layer.js").default}
|
||||
let layer;
|
||||
if (layerOrSource instanceof Source) {
|
||||
if (layerOrSource instanceof TileSource) {
|
||||
layer = new TileLayer({source: layerOrSource});
|
||||
} else if (layerOrSource instanceof ImageSource) {
|
||||
layer = new ImageLayer({source: layerOrSource});
|
||||
}
|
||||
} else {
|
||||
layer = layerOrSource;
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
|
||||
export default RasterSource;
|
||||
246
node_modules/ol/src/source/Source.js
generated
vendored
Normal file
246
node_modules/ol/src/source/Source.js
generated
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
/**
|
||||
* @module ol/source/Source
|
||||
*/
|
||||
import BaseObject from '../Object.js';
|
||||
import {abstract} from '../util.js';
|
||||
import {get as getProjection} from '../proj.js';
|
||||
|
||||
/**
|
||||
* @typedef {'undefined' | 'loading' | 'ready' | 'error'} State
|
||||
* State of the source, one of 'undefined', 'loading', 'ready' or 'error'.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that takes a {@link module:ol/PluggableMap~FrameState} and returns a string or
|
||||
* an array of strings representing source attributions.
|
||||
*
|
||||
* @typedef {function(import("../PluggableMap.js").FrameState): (string|Array<string>)} Attribution
|
||||
*/
|
||||
|
||||
/**
|
||||
* A type that can be used to provide attribution information for data sources.
|
||||
*
|
||||
* It represents either
|
||||
* * a simple string (e.g. `'© Acme Inc.'`)
|
||||
* * an array of simple strings (e.g. `['© Acme Inc.', '© Bacme Inc.']`)
|
||||
* * a function that returns a string or array of strings ({@link module:ol/source/Source~Attribution})
|
||||
*
|
||||
* @typedef {string|Array<string>|Attribution} AttributionLike
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {import("./Source.js").State} [state='ready'] State.
|
||||
* @property {boolean} [wrapX=false] WrapX.
|
||||
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||
* the nearest neighbor is used when resampling.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Abstract base class; normally only used for creating subclasses and not
|
||||
* instantiated in apps.
|
||||
* Base class for {@link module:ol/layer/Layer~Layer} sources.
|
||||
*
|
||||
* A generic `change` event is triggered when the state of the source changes.
|
||||
* @abstract
|
||||
* @api
|
||||
*/
|
||||
class Source extends BaseObject {
|
||||
/**
|
||||
* @param {Options} options Source options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {import("../proj/Projection.js").default|null}
|
||||
*/
|
||||
this.projection = getProjection(options.projection);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?Attribution}
|
||||
*/
|
||||
this.attributions_ = adaptAttributions(options.attributions);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.attributionsCollapsible_ =
|
||||
options.attributionsCollapsible !== undefined
|
||||
? options.attributionsCollapsible
|
||||
: true;
|
||||
|
||||
/**
|
||||
* This source is currently loading data. Sources that defer loading to the
|
||||
* map's tile queue never set this to `true`.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.loading = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./Source.js").State}
|
||||
*/
|
||||
this.state_ = options.state !== undefined ? options.state : 'ready';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.wrapX_ = options.wrapX !== undefined ? options.wrapX : false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.interpolate_ = !!options.interpolate;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {function(import("../View.js").ViewOptions):void}
|
||||
*/
|
||||
this.viewResolver = null;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {function(Error):void}
|
||||
*/
|
||||
this.viewRejector = null;
|
||||
|
||||
const self = this;
|
||||
/**
|
||||
* @private
|
||||
* @type {Promise<import("../View.js").ViewOptions>}
|
||||
*/
|
||||
this.viewPromise_ = new Promise(function (resolve, reject) {
|
||||
self.viewResolver = resolve;
|
||||
self.viewRejector = reject;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attribution function for the source.
|
||||
* @return {?Attribution} Attribution function.
|
||||
* @api
|
||||
*/
|
||||
getAttributions() {
|
||||
return this.attributions_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} Attributions are collapsible.
|
||||
* @api
|
||||
*/
|
||||
getAttributionsCollapsible() {
|
||||
return this.attributionsCollapsible_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the projection of the source.
|
||||
* @return {import("../proj/Projection.js").default|null} Projection.
|
||||
* @api
|
||||
*/
|
||||
getProjection() {
|
||||
return this.projection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @return {Array<number>|null} Resolutions.
|
||||
*/
|
||||
getResolutions() {
|
||||
return abstract();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Promise<import("../View.js").ViewOptions>} A promise for view-related properties.
|
||||
*/
|
||||
getView() {
|
||||
return this.viewPromise_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of the source, see {@link import("./Source.js").State} for possible states.
|
||||
* @return {import("./Source.js").State} State.
|
||||
* @api
|
||||
*/
|
||||
getState() {
|
||||
return this.state_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean|undefined} Wrap X.
|
||||
*/
|
||||
getWrapX() {
|
||||
return this.wrapX_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} Use linear interpolation when resampling.
|
||||
*/
|
||||
getInterpolate() {
|
||||
return this.interpolate_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the source. The source will be cleared, and data from the server will be reloaded.
|
||||
* @api
|
||||
*/
|
||||
refresh() {
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the attributions of the source.
|
||||
* @param {AttributionLike|undefined} attributions Attributions.
|
||||
* Can be passed as `string`, `Array<string>`, {@link module:ol/source/Source~Attribution},
|
||||
* or `undefined`.
|
||||
* @api
|
||||
*/
|
||||
setAttributions(attributions) {
|
||||
this.attributions_ = adaptAttributions(attributions);
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of the source.
|
||||
* @param {import("./Source.js").State} state State.
|
||||
*/
|
||||
setState(state) {
|
||||
this.state_ = state;
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the attributions option into an attributions function.
|
||||
* @param {AttributionLike|undefined} attributionLike The attribution option.
|
||||
* @return {Attribution|null} An attribution function (or null).
|
||||
*/
|
||||
function adaptAttributions(attributionLike) {
|
||||
if (!attributionLike) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(attributionLike)) {
|
||||
return function (frameState) {
|
||||
return attributionLike;
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof attributionLike === 'function') {
|
||||
return attributionLike;
|
||||
}
|
||||
|
||||
return function (frameState) {
|
||||
return [attributionLike];
|
||||
};
|
||||
}
|
||||
|
||||
export default Source;
|
||||
164
node_modules/ol/src/source/Stamen.js
generated
vendored
Normal file
164
node_modules/ol/src/source/Stamen.js
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @module ol/source/Stamen
|
||||
*/
|
||||
|
||||
import XYZ from './XYZ.js';
|
||||
import {ATTRIBUTION as OSM_ATTRIBUTION} from './OSM.js';
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
const ATTRIBUTIONS = [
|
||||
'Map tiles by <a href="https://stamen.com/" target="_blank">Stamen Design</a>, ' +
|
||||
'under <a href="https://creativecommons.org/licenses/by/3.0/" target="_blank">CC BY' +
|
||||
' 3.0</a>.',
|
||||
OSM_ATTRIBUTION,
|
||||
];
|
||||
|
||||
/**
|
||||
* @type {Object<string, {extension: string, opaque: boolean}>}
|
||||
*/
|
||||
const LayerConfig = {
|
||||
'terrain': {
|
||||
extension: 'jpg',
|
||||
opaque: true,
|
||||
},
|
||||
'terrain-background': {
|
||||
extension: 'jpg',
|
||||
opaque: true,
|
||||
},
|
||||
'terrain-labels': {
|
||||
extension: 'png',
|
||||
opaque: false,
|
||||
},
|
||||
'terrain-lines': {
|
||||
extension: 'png',
|
||||
opaque: false,
|
||||
},
|
||||
'toner-background': {
|
||||
extension: 'png',
|
||||
opaque: true,
|
||||
},
|
||||
'toner': {
|
||||
extension: 'png',
|
||||
opaque: true,
|
||||
},
|
||||
'toner-hybrid': {
|
||||
extension: 'png',
|
||||
opaque: false,
|
||||
},
|
||||
'toner-labels': {
|
||||
extension: 'png',
|
||||
opaque: false,
|
||||
},
|
||||
'toner-lines': {
|
||||
extension: 'png',
|
||||
opaque: false,
|
||||
},
|
||||
'toner-lite': {
|
||||
extension: 'png',
|
||||
opaque: true,
|
||||
},
|
||||
'watercolor': {
|
||||
extension: 'jpg',
|
||||
opaque: true,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {Object<string, {minZoom: number, maxZoom: number}>}
|
||||
*/
|
||||
const ProviderConfig = {
|
||||
'terrain': {
|
||||
minZoom: 0,
|
||||
maxZoom: 18,
|
||||
},
|
||||
'toner': {
|
||||
minZoom: 0,
|
||||
maxZoom: 20,
|
||||
},
|
||||
'watercolor': {
|
||||
minZoom: 0,
|
||||
maxZoom: 18,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {string} layer Layer name.
|
||||
* @property {number} [minZoom] Minimum zoom.
|
||||
* @property {number} [maxZoom] Maximum zoom.
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction]
|
||||
* Optional function to load a tile given a URL. The default is
|
||||
* ```js
|
||||
* function(imageTile, src) {
|
||||
* imageTile.getImage().src = src;
|
||||
* };
|
||||
* ```
|
||||
* @property {number} [transition=250] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for the Stamen tile server.
|
||||
* @api
|
||||
*/
|
||||
class Stamen extends XYZ {
|
||||
/**
|
||||
* @param {Options} options Stamen options.
|
||||
*/
|
||||
constructor(options) {
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
const i = options.layer.indexOf('-');
|
||||
const provider = i == -1 ? options.layer : options.layer.slice(0, i);
|
||||
const providerConfig = ProviderConfig[provider];
|
||||
|
||||
const layerConfig = LayerConfig[options.layer];
|
||||
|
||||
const url =
|
||||
options.url !== undefined
|
||||
? options.url
|
||||
: 'https://stamen-tiles-{a-d}.a.ssl.fastly.net/' +
|
||||
options.layer +
|
||||
'/{z}/{x}/{y}.' +
|
||||
layerConfig.extension;
|
||||
|
||||
super({
|
||||
attributions: ATTRIBUTIONS,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: 'anonymous',
|
||||
interpolate: interpolate,
|
||||
maxZoom:
|
||||
options.maxZoom != undefined ? options.maxZoom : providerConfig.maxZoom,
|
||||
minZoom:
|
||||
options.minZoom != undefined ? options.minZoom : providerConfig.minZoom,
|
||||
opaque: layerConfig.opaque,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
tileLoadFunction: options.tileLoadFunction,
|
||||
transition: options.transition,
|
||||
url: url,
|
||||
wrapX: options.wrapX,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default Stamen;
|
||||
397
node_modules/ol/src/source/Tile.js
generated
vendored
Normal file
397
node_modules/ol/src/source/Tile.js
generated
vendored
Normal file
@@ -0,0 +1,397 @@
|
||||
/**
|
||||
* @module ol/source/Tile
|
||||
*/
|
||||
import Event from '../events/Event.js';
|
||||
import Source from './Source.js';
|
||||
import TileCache from '../TileCache.js';
|
||||
import TileState from '../TileState.js';
|
||||
import {abstract} from '../util.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {equivalent} from '../proj.js';
|
||||
import {getKeyZXY, withinExtentAndZ} from '../tilecoord.js';
|
||||
import {
|
||||
getForProjection as getTileGridForProjection,
|
||||
wrapX,
|
||||
} from '../tilegrid.js';
|
||||
import {scale as scaleSize, toSize} from '../size.js';
|
||||
|
||||
/***
|
||||
* @template Return
|
||||
* @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> &
|
||||
* import("../Observable").OnSignature<import("../ObjectEventType").Types, import("../Object").ObjectEvent, Return> &
|
||||
* import("../Observable").OnSignature<import("./TileEventType").TileSourceEventTypes, TileSourceEvent, Return> &
|
||||
* import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("../ObjectEventType").Types|
|
||||
* import("./TileEventType").TileSourceEventTypes, Return>} TileSourceOnSignature
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {number} [cacheSize] CacheSize.
|
||||
* @property {boolean} [opaque=false] Whether the layer is opaque.
|
||||
* @property {number} [tilePixelRatio] TilePixelRatio.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection.
|
||||
* @property {import("./Source.js").State} [state] State.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] TileGrid.
|
||||
* @property {boolean} [wrapX=false] WrapX.
|
||||
* @property {number} [transition] Transition.
|
||||
* @property {string} [key] Key.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] ZDirection.
|
||||
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||
* the nearest neighbor is used when resampling.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Abstract base class; normally only used for creating subclasses and not
|
||||
* instantiated in apps.
|
||||
* Base class for sources providing images divided into a tile grid.
|
||||
* @abstract
|
||||
* @api
|
||||
*/
|
||||
class TileSource extends Source {
|
||||
/**
|
||||
* @param {Options} options SourceTile source options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
attributionsCollapsible: options.attributionsCollapsible,
|
||||
projection: options.projection,
|
||||
state: options.state,
|
||||
wrapX: options.wrapX,
|
||||
interpolate: options.interpolate,
|
||||
});
|
||||
|
||||
/***
|
||||
* @type {TileSourceOnSignature<import("../events").EventsKey>}
|
||||
*/
|
||||
this.on;
|
||||
|
||||
/***
|
||||
* @type {TileSourceOnSignature<import("../events").EventsKey>}
|
||||
*/
|
||||
this.once;
|
||||
|
||||
/***
|
||||
* @type {TileSourceOnSignature<void>}
|
||||
*/
|
||||
this.un;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.opaque_ = options.opaque !== undefined ? options.opaque : false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.tilePixelRatio_ =
|
||||
options.tilePixelRatio !== undefined ? options.tilePixelRatio : 1;
|
||||
|
||||
/**
|
||||
* @type {import("../tilegrid/TileGrid.js").default|null}
|
||||
*/
|
||||
this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : null;
|
||||
|
||||
const tileSize = [256, 256];
|
||||
if (this.tileGrid) {
|
||||
toSize(this.tileGrid.getTileSize(this.tileGrid.getMinZoom()), tileSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {import("../TileCache.js").default}
|
||||
*/
|
||||
this.tileCache = new TileCache(options.cacheSize || 0);
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {import("../size.js").Size}
|
||||
*/
|
||||
this.tmpSize = [0, 0];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.key_ = options.key || '';
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {import("../Tile.js").Options}
|
||||
*/
|
||||
this.tileOptions = {
|
||||
transition: options.transition,
|
||||
interpolate: options.interpolate,
|
||||
};
|
||||
|
||||
/**
|
||||
* zDirection hint, read by the renderer. Indicates which resolution should be used
|
||||
* by a renderer if the views resolution does not match any resolution of the tile source.
|
||||
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
|
||||
* will be used. If -1, the nearest higher resolution will be used.
|
||||
* @type {number|import("../array.js").NearestDirectionFunction}
|
||||
*/
|
||||
this.zDirection = options.zDirection ? options.zDirection : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} Can expire cache.
|
||||
*/
|
||||
canExpireCache() {
|
||||
return this.tileCache.canExpireCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @param {!Object<string, boolean>} usedTiles Used tiles.
|
||||
*/
|
||||
expireCache(projection, usedTiles) {
|
||||
const tileCache = this.getTileCacheForProjection(projection);
|
||||
if (tileCache) {
|
||||
tileCache.expireCache(usedTiles);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @param {number} z Zoom level.
|
||||
* @param {import("../TileRange.js").default} tileRange Tile range.
|
||||
* @param {function(import("../Tile.js").default):(boolean|void)} callback Called with each
|
||||
* loaded tile. If the callback returns `false`, the tile will not be
|
||||
* considered loaded.
|
||||
* @return {boolean} The tile range is fully covered with loaded tiles.
|
||||
*/
|
||||
forEachLoadedTile(projection, z, tileRange, callback) {
|
||||
const tileCache = this.getTileCacheForProjection(projection);
|
||||
if (!tileCache) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let covered = true;
|
||||
let tile, tileCoordKey, loaded;
|
||||
for (let x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (let y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
tileCoordKey = getKeyZXY(z, x, y);
|
||||
loaded = false;
|
||||
if (tileCache.containsKey(tileCoordKey)) {
|
||||
tile = /** @type {!import("../Tile.js").default} */ (
|
||||
tileCache.get(tileCoordKey)
|
||||
);
|
||||
loaded = tile.getState() === TileState.LOADED;
|
||||
if (loaded) {
|
||||
loaded = callback(tile) !== false;
|
||||
}
|
||||
}
|
||||
if (!loaded) {
|
||||
covered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return covered;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {number} Gutter.
|
||||
*/
|
||||
getGutterForProjection(projection) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key to be used for all tiles in the source.
|
||||
* @return {string} The key for all tiles.
|
||||
*/
|
||||
getKey() {
|
||||
return this.key_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value to be used as the key for all tiles in the source.
|
||||
* @param {string} key The key for tiles.
|
||||
* @protected
|
||||
*/
|
||||
setKey(key) {
|
||||
if (this.key_ !== key) {
|
||||
this.key_ = key;
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {boolean} Opaque.
|
||||
*/
|
||||
getOpaque(projection) {
|
||||
return this.opaque_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array<number>|null} Resolutions.
|
||||
*/
|
||||
getResolutions() {
|
||||
if (!this.tileGrid) {
|
||||
return null;
|
||||
}
|
||||
return this.tileGrid.getResolutions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {!import("../Tile.js").default} Tile.
|
||||
*/
|
||||
getTile(z, x, y, pixelRatio, projection) {
|
||||
return abstract();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tile grid of the tile source.
|
||||
* @return {import("../tilegrid/TileGrid.js").default|null} Tile grid.
|
||||
* @api
|
||||
*/
|
||||
getTileGrid() {
|
||||
return this.tileGrid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {!import("../tilegrid/TileGrid.js").default} Tile grid.
|
||||
*/
|
||||
getTileGridForProjection(projection) {
|
||||
if (!this.tileGrid) {
|
||||
return getTileGridForProjection(projection);
|
||||
} else {
|
||||
return this.tileGrid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../TileCache.js").default} Tile cache.
|
||||
* @protected
|
||||
*/
|
||||
getTileCacheForProjection(projection) {
|
||||
const sourceProjection = this.getProjection();
|
||||
assert(
|
||||
sourceProjection === null || equivalent(sourceProjection, projection),
|
||||
68 // A VectorTile source can only be rendered if it has a projection compatible with the view projection.
|
||||
);
|
||||
return this.tileCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tile pixel ratio for this source. Subclasses may override this
|
||||
* method, which is meant to return a supported pixel ratio that matches the
|
||||
* provided `pixelRatio` as close as possible.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @return {number} Tile pixel ratio.
|
||||
*/
|
||||
getTilePixelRatio(pixelRatio) {
|
||||
return this.tilePixelRatio_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} z Z.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../size.js").Size} Tile size.
|
||||
*/
|
||||
getTilePixelSize(z, pixelRatio, projection) {
|
||||
const tileGrid = this.getTileGridForProjection(projection);
|
||||
const tilePixelRatio = this.getTilePixelRatio(pixelRatio);
|
||||
const tileSize = toSize(tileGrid.getTileSize(z), this.tmpSize);
|
||||
if (tilePixelRatio == 1) {
|
||||
return tileSize;
|
||||
} else {
|
||||
return scaleSize(tileSize, tilePixelRatio, this.tmpSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a tile coordinate wrapped around the x-axis. When the tile coordinate
|
||||
* is outside the resolution and extent range of the tile grid, `null` will be
|
||||
* returned.
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {import("../proj/Projection.js").default} [opt_projection] Projection.
|
||||
* @return {import("../tilecoord.js").TileCoord} Tile coordinate to be passed to the tileUrlFunction or
|
||||
* null if no tile URL should be created for the passed `tileCoord`.
|
||||
*/
|
||||
getTileCoordForTileUrlFunction(tileCoord, opt_projection) {
|
||||
const projection =
|
||||
opt_projection !== undefined ? opt_projection : this.getProjection();
|
||||
const tileGrid = this.getTileGridForProjection(projection);
|
||||
if (this.getWrapX() && projection.isGlobal()) {
|
||||
tileCoord = wrapX(tileGrid, tileCoord, projection);
|
||||
}
|
||||
return withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all cached tiles from the source. The next render cycle will fetch new tiles.
|
||||
* @api
|
||||
*/
|
||||
clear() {
|
||||
this.tileCache.clear();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.clear();
|
||||
super.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the cache size if needed
|
||||
* @param {number} tileCount Minimum number of tiles needed.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
*/
|
||||
updateCacheSize(tileCount, projection) {
|
||||
const tileCache = this.getTileCacheForProjection(projection);
|
||||
if (tileCount > tileCache.highWaterMark) {
|
||||
tileCache.highWaterMark = tileCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a tile coord as being used, without triggering a load.
|
||||
* @abstract
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
*/
|
||||
useTile(z, x, y, projection) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Events emitted by {@link module:ol/source/Tile~TileSource} instances are instances of this
|
||||
* type.
|
||||
*/
|
||||
export class TileSourceEvent extends Event {
|
||||
/**
|
||||
* @param {string} type Type.
|
||||
* @param {import("../Tile.js").default} tile The tile.
|
||||
*/
|
||||
constructor(type, tile) {
|
||||
super(type);
|
||||
|
||||
/**
|
||||
* The tile related to the event.
|
||||
* @type {import("../Tile.js").default}
|
||||
* @api
|
||||
*/
|
||||
this.tile = tile;
|
||||
}
|
||||
}
|
||||
|
||||
export default TileSource;
|
||||
262
node_modules/ol/src/source/TileArcGISRest.js
generated
vendored
Normal file
262
node_modules/ol/src/source/TileArcGISRest.js
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
/**
|
||||
* @module ol/source/TileArcGISRest
|
||||
*/
|
||||
|
||||
import TileImage from './TileImage.js';
|
||||
import {appendParams} from '../uri.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {createEmpty} from '../extent.js';
|
||||
import {modulo} from '../math.js';
|
||||
import {scale as scaleSize, toSize} from '../size.js';
|
||||
import {hash as tileCoordHash} from '../tilecoord.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {Object<string,*>} [params] ArcGIS Rest parameters. This field is optional. Service defaults will be
|
||||
* used for any fields not specified. `FORMAT` is `PNG32` by default. `F` is `IMAGE` by
|
||||
* default. `TRANSPARENT` is `true` by default. `BBOX`, `SIZE`, `BBOXSR`,
|
||||
* and `IMAGESR` will be set dynamically. Set `LAYERS` to
|
||||
* override the default service layer visibility. See
|
||||
* https://developers.arcgis.com/rest/services-reference/export-map.htm
|
||||
* for further reference.
|
||||
* @property {boolean} [hidpi=true] Use the `ol/Map#pixelRatio` value when requesting
|
||||
* the image from the remote server.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid. Base this on the resolutions,
|
||||
* tilesize and extent supported by the server.
|
||||
* If this is not defined, a default grid will be used: if there is a projection
|
||||
* extent, the grid will be based on that; if not, a grid based on a global
|
||||
* extent with origin at 0,0 will be used.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* The projection code must contain a numeric end portion separated by :
|
||||
* or the entire code must form a valid ArcGIS SpatialReference definition.
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL.
|
||||
* The default is
|
||||
* ```js
|
||||
* function(imageTile, src) {
|
||||
* imageTile.getImage().src = src;
|
||||
* };
|
||||
* ```
|
||||
* @property {string} [url] ArcGIS Rest service URL for a Map Service or Image Service. The
|
||||
* url should include /MapServer or /ImageServer.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* @property {number} [transition] Duration of the opacity transition for rendering. To disable the opacity
|
||||
* transition, pass `transition: 0`.
|
||||
* @property {Array<string>} [urls] ArcGIS Rest service urls. Use this instead of `url` when the ArcGIS
|
||||
* Service supports multiple urls for export requests.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for tile data from ArcGIS Rest services. Map and Image
|
||||
* Services are supported.
|
||||
*
|
||||
* For cached ArcGIS services, better performance is available using the
|
||||
* {@link module:ol/source/XYZ~XYZ} data source.
|
||||
* @api
|
||||
*/
|
||||
class TileArcGISRest extends TileImage {
|
||||
/**
|
||||
* @param {Options} [opt_options] Tile ArcGIS Rest options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: options.crossOrigin,
|
||||
interpolate: interpolate,
|
||||
projection: options.projection,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
tileGrid: options.tileGrid,
|
||||
tileLoadFunction: options.tileLoadFunction,
|
||||
url: options.url,
|
||||
urls: options.urls,
|
||||
wrapX: options.wrapX !== undefined ? options.wrapX : true,
|
||||
transition: options.transition,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object}
|
||||
*/
|
||||
this.params_ = options.params || {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../extent.js").Extent}
|
||||
*/
|
||||
this.tmpExtent_ = createEmpty();
|
||||
|
||||
this.setKey(this.getKeyForParams_());
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {string} The key for the current params.
|
||||
*/
|
||||
getKeyForParams_() {
|
||||
let i = 0;
|
||||
const res = [];
|
||||
for (const key in this.params_) {
|
||||
res[i++] = key + '-' + this.params_[key];
|
||||
}
|
||||
return res.join('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user-provided params, i.e. those passed to the constructor through
|
||||
* the "params" option, and possibly updated using the updateParams method.
|
||||
* @return {Object} Params.
|
||||
* @api
|
||||
*/
|
||||
getParams() {
|
||||
return this.params_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {import("../size.js").Size} tileSize Tile size.
|
||||
* @param {import("../extent.js").Extent} tileExtent Tile extent.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @param {Object} params Params.
|
||||
* @return {string|undefined} Request URL.
|
||||
* @private
|
||||
*/
|
||||
getRequestUrl_(
|
||||
tileCoord,
|
||||
tileSize,
|
||||
tileExtent,
|
||||
pixelRatio,
|
||||
projection,
|
||||
params
|
||||
) {
|
||||
const urls = this.urls;
|
||||
if (!urls) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// ArcGIS Server only wants the numeric portion of the projection ID.
|
||||
// (if there is no numeric portion the entire projection code must
|
||||
// form a valid ArcGIS SpatialReference definition).
|
||||
const srid = projection
|
||||
.getCode()
|
||||
.split(/:(?=\d+$)/)
|
||||
.pop();
|
||||
|
||||
params['SIZE'] = tileSize[0] + ',' + tileSize[1];
|
||||
params['BBOX'] = tileExtent.join(',');
|
||||
params['BBOXSR'] = srid;
|
||||
params['IMAGESR'] = srid;
|
||||
params['DPI'] = Math.round(
|
||||
params['DPI'] ? params['DPI'] * pixelRatio : 90 * pixelRatio
|
||||
);
|
||||
|
||||
let url;
|
||||
if (urls.length == 1) {
|
||||
url = urls[0];
|
||||
} else {
|
||||
const index = modulo(tileCoordHash(tileCoord), urls.length);
|
||||
url = urls[index];
|
||||
}
|
||||
|
||||
const modifiedUrl = url
|
||||
.replace(/MapServer\/?$/, 'MapServer/export')
|
||||
.replace(/ImageServer\/?$/, 'ImageServer/exportImage');
|
||||
return appendParams(modifiedUrl, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tile pixel ratio for this source.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @return {number} Tile pixel ratio.
|
||||
*/
|
||||
getTilePixelRatio(pixelRatio) {
|
||||
return this.hidpi_ ? pixelRatio : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user-provided params.
|
||||
* @param {Object} params Params.
|
||||
* @api
|
||||
*/
|
||||
updateParams(params) {
|
||||
assign(this.params_, params);
|
||||
this.setKey(this.getKeyForParams_());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord The tile coordinate
|
||||
* @param {number} pixelRatio The pixel ratio
|
||||
* @param {import("../proj/Projection.js").default} projection The projection
|
||||
* @return {string|undefined} The tile URL
|
||||
* @override
|
||||
*/
|
||||
tileUrlFunction(tileCoord, pixelRatio, projection) {
|
||||
let tileGrid = this.getTileGrid();
|
||||
if (!tileGrid) {
|
||||
tileGrid = this.getTileGridForProjection(projection);
|
||||
}
|
||||
|
||||
if (tileGrid.getResolutions().length <= tileCoord[0]) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (pixelRatio != 1 && !this.hidpi_) {
|
||||
pixelRatio = 1;
|
||||
}
|
||||
|
||||
const tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
|
||||
let tileSize = toSize(tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
|
||||
|
||||
if (pixelRatio != 1) {
|
||||
tileSize = scaleSize(tileSize, pixelRatio, this.tmpSize);
|
||||
}
|
||||
|
||||
// Apply default params and override with user specified values.
|
||||
const baseParams = {
|
||||
'F': 'image',
|
||||
'FORMAT': 'PNG32',
|
||||
'TRANSPARENT': true,
|
||||
};
|
||||
assign(baseParams, this.params_);
|
||||
|
||||
return this.getRequestUrl_(
|
||||
tileCoord,
|
||||
tileSize,
|
||||
tileExtent,
|
||||
pixelRatio,
|
||||
projection,
|
||||
baseParams
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TileArcGISRest;
|
||||
71
node_modules/ol/src/source/TileDebug.js
generated
vendored
Normal file
71
node_modules/ol/src/source/TileDebug.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @module ol/source/TileDebug
|
||||
*/
|
||||
|
||||
import XYZ from './XYZ.js';
|
||||
import {createCanvasContext2D} from '../dom.js';
|
||||
import {toSize} from '../size.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Optional projection.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Set to `1` when debugging `VectorTile` sources with a default configuration.
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
* @property {string} [template='z:{z} x:{x} y:{y}'] Template for labeling the tiles.
|
||||
* Should include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A pseudo tile source, which does not fetch tiles from a server, but renders
|
||||
* a grid outline for the tile grid/projection along with the coordinates for
|
||||
* each tile. See examples/canvas-tiles for an example.
|
||||
* @api
|
||||
*/
|
||||
class TileDebug extends XYZ {
|
||||
/**
|
||||
* @param {Options} [opt_options] Debug tile options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
/**
|
||||
* @type {Options}
|
||||
*/
|
||||
const options = opt_options || {};
|
||||
|
||||
super({
|
||||
opaque: false,
|
||||
projection: options.projection,
|
||||
tileGrid: options.tileGrid,
|
||||
wrapX: options.wrapX !== undefined ? options.wrapX : true,
|
||||
zDirection: options.zDirection,
|
||||
url: options.template || 'z:{z} x:{x} y:{y}',
|
||||
tileLoadFunction: (tile, text) => {
|
||||
const z = tile.getTileCoord()[0];
|
||||
const tileSize = toSize(this.tileGrid.getTileSize(z));
|
||||
const context = createCanvasContext2D(tileSize[0], tileSize[1]);
|
||||
|
||||
context.strokeStyle = 'grey';
|
||||
context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5);
|
||||
|
||||
context.fillStyle = 'grey';
|
||||
context.strokeStyle = 'white';
|
||||
context.textAlign = 'center';
|
||||
context.textBaseline = 'middle';
|
||||
context.font = '24px sans-serif';
|
||||
context.lineWidth = 4;
|
||||
context.strokeText(text, tileSize[0] / 2, tileSize[1] / 2, tileSize[0]);
|
||||
context.fillText(text, tileSize[0] / 2, tileSize[1] / 2, tileSize[0]);
|
||||
|
||||
/** @type {import("../ImageTile.js").default} */ (tile).setImage(
|
||||
context.canvas
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default TileDebug;
|
||||
34
node_modules/ol/src/source/TileEventType.js
generated
vendored
Normal file
34
node_modules/ol/src/source/TileEventType.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @module ol/source/TileEventType
|
||||
*/
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
export default {
|
||||
/**
|
||||
* Triggered when a tile starts loading.
|
||||
* @event module:ol/source/Tile.TileSourceEvent#tileloadstart
|
||||
* @api
|
||||
*/
|
||||
TILELOADSTART: 'tileloadstart',
|
||||
|
||||
/**
|
||||
* Triggered when a tile finishes loading, either when its data is loaded,
|
||||
* or when loading was aborted because the tile is no longer needed.
|
||||
* @event module:ol/source/Tile.TileSourceEvent#tileloadend
|
||||
* @api
|
||||
*/
|
||||
TILELOADEND: 'tileloadend',
|
||||
|
||||
/**
|
||||
* Triggered if tile loading results in an error.
|
||||
* @event module:ol/source/Tile.TileSourceEvent#tileloaderror
|
||||
* @api
|
||||
*/
|
||||
TILELOADERROR: 'tileloaderror',
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {'tileloadstart'|'tileloadend'|'tileloaderror'} TileSourceEventTypes
|
||||
*/
|
||||
471
node_modules/ol/src/source/TileImage.js
generated
vendored
Normal file
471
node_modules/ol/src/source/TileImage.js
generated
vendored
Normal file
@@ -0,0 +1,471 @@
|
||||
/**
|
||||
* @module ol/source/TileImage
|
||||
*/
|
||||
import EventType from '../events/EventType.js';
|
||||
import ImageTile from '../ImageTile.js';
|
||||
import ReprojTile from '../reproj/Tile.js';
|
||||
import TileCache from '../TileCache.js';
|
||||
import TileState from '../TileState.js';
|
||||
import UrlTile from './UrlTile.js';
|
||||
import {ENABLE_RASTER_REPROJECTION} from '../reproj/common.js';
|
||||
import {equivalent, get as getProjection} from '../proj.js';
|
||||
import {getKey, getKeyZXY} from '../tilecoord.js';
|
||||
import {getForProjection as getTileGridForProjection} from '../tilegrid.js';
|
||||
import {getUid} from '../util.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {boolean} [opaque=false] Whether the layer is opaque.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {import("./Source.js").State} [state] Source state.
|
||||
* @property {typeof import("../ImageTile.js").default} [tileClass] Class used to instantiate image tiles.
|
||||
* Default is {@link module:ol/ImageTile~ImageTile}.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is
|
||||
* ```js
|
||||
* function(imageTile, src) {
|
||||
* imageTile.getImage().src = src;
|
||||
* };
|
||||
* ```
|
||||
* @property {number} [tilePixelRatio=1] The pixel ratio used by the tile service. For example, if the tile
|
||||
* service advertizes 256px by 256px tiles but actually sends 512px
|
||||
* by 512px images (for retina/hidpi devices) then `tilePixelRatio`
|
||||
* should be set to `2`.
|
||||
* @property {import("../Tile.js").UrlFunction} [tileUrlFunction] Optional function to get tile URL given a tile coordinate and the projection.
|
||||
* @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
|
||||
* A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be
|
||||
* used instead of defining each one separately in the `urls` option.
|
||||
* @property {Array<string>} [urls] An array of URL templates.
|
||||
* @property {boolean} [wrapX] Whether to wrap the world horizontally. The default, is to
|
||||
* request out-of-bounds tiles from the server. When set to `false`, only one
|
||||
* world will be rendered. When set to `true`, tiles will be requested for one
|
||||
* world only, but they will be wrapped horizontally to render multiple worlds.
|
||||
* @property {number} [transition] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {string} [key] Optional tile key for proper cache fetching
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Base class for sources providing images divided into a tile grid.
|
||||
*
|
||||
* @fires import("./Tile.js").TileSourceEvent
|
||||
* @api
|
||||
*/
|
||||
class TileImage extends UrlTile {
|
||||
/**
|
||||
* @param {!Options} options Image tile options.
|
||||
*/
|
||||
constructor(options) {
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
cacheSize: options.cacheSize,
|
||||
opaque: options.opaque,
|
||||
projection: options.projection,
|
||||
state: options.state,
|
||||
tileGrid: options.tileGrid,
|
||||
tileLoadFunction: options.tileLoadFunction
|
||||
? options.tileLoadFunction
|
||||
: defaultTileLoadFunction,
|
||||
tilePixelRatio: options.tilePixelRatio,
|
||||
tileUrlFunction: options.tileUrlFunction,
|
||||
url: options.url,
|
||||
urls: options.urls,
|
||||
wrapX: options.wrapX,
|
||||
transition: options.transition,
|
||||
interpolate: interpolate,
|
||||
key: options.key,
|
||||
attributionsCollapsible: options.attributionsCollapsible,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {?string}
|
||||
*/
|
||||
this.crossOrigin =
|
||||
options.crossOrigin !== undefined ? options.crossOrigin : null;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {typeof ImageTile}
|
||||
*/
|
||||
this.tileClass =
|
||||
options.tileClass !== undefined ? options.tileClass : ImageTile;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {!Object<string, TileCache>}
|
||||
*/
|
||||
this.tileCacheForProjection = {};
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {!Object<string, import("../tilegrid/TileGrid.js").default>}
|
||||
*/
|
||||
this.tileGridForProjection = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.reprojectionErrorThreshold_ = options.reprojectionErrorThreshold;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderReprojectionEdges_ = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} Can expire cache.
|
||||
*/
|
||||
canExpireCache() {
|
||||
if (!ENABLE_RASTER_REPROJECTION) {
|
||||
return super.canExpireCache();
|
||||
}
|
||||
if (this.tileCache.canExpireCache()) {
|
||||
return true;
|
||||
} else {
|
||||
for (const key in this.tileCacheForProjection) {
|
||||
if (this.tileCacheForProjection[key].canExpireCache()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @param {!Object<string, boolean>} usedTiles Used tiles.
|
||||
*/
|
||||
expireCache(projection, usedTiles) {
|
||||
if (!ENABLE_RASTER_REPROJECTION) {
|
||||
super.expireCache(projection, usedTiles);
|
||||
return;
|
||||
}
|
||||
const usedTileCache = this.getTileCacheForProjection(projection);
|
||||
|
||||
this.tileCache.expireCache(
|
||||
this.tileCache == usedTileCache ? usedTiles : {}
|
||||
);
|
||||
for (const id in this.tileCacheForProjection) {
|
||||
const tileCache = this.tileCacheForProjection[id];
|
||||
tileCache.expireCache(tileCache == usedTileCache ? usedTiles : {});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {number} Gutter.
|
||||
*/
|
||||
getGutterForProjection(projection) {
|
||||
if (
|
||||
ENABLE_RASTER_REPROJECTION &&
|
||||
this.getProjection() &&
|
||||
projection &&
|
||||
!equivalent(this.getProjection(), projection)
|
||||
) {
|
||||
return 0;
|
||||
} else {
|
||||
return this.getGutter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number} Gutter.
|
||||
*/
|
||||
getGutter() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key to be used for all tiles in the source.
|
||||
* @return {string} The key for all tiles.
|
||||
*/
|
||||
getKey() {
|
||||
let key = super.getKey();
|
||||
if (!this.getInterpolate()) {
|
||||
key += ':disable-interpolation';
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {boolean} Opaque.
|
||||
*/
|
||||
getOpaque(projection) {
|
||||
if (
|
||||
ENABLE_RASTER_REPROJECTION &&
|
||||
this.getProjection() &&
|
||||
projection &&
|
||||
!equivalent(this.getProjection(), projection)
|
||||
) {
|
||||
return false;
|
||||
} else {
|
||||
return super.getOpaque(projection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {!import("../tilegrid/TileGrid.js").default} Tile grid.
|
||||
*/
|
||||
getTileGridForProjection(projection) {
|
||||
if (!ENABLE_RASTER_REPROJECTION) {
|
||||
return super.getTileGridForProjection(projection);
|
||||
}
|
||||
const thisProj = this.getProjection();
|
||||
if (this.tileGrid && (!thisProj || equivalent(thisProj, projection))) {
|
||||
return this.tileGrid;
|
||||
} else {
|
||||
const projKey = getUid(projection);
|
||||
if (!(projKey in this.tileGridForProjection)) {
|
||||
this.tileGridForProjection[projKey] =
|
||||
getTileGridForProjection(projection);
|
||||
}
|
||||
return this.tileGridForProjection[projKey];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../TileCache.js").default} Tile cache.
|
||||
*/
|
||||
getTileCacheForProjection(projection) {
|
||||
if (!ENABLE_RASTER_REPROJECTION) {
|
||||
return super.getTileCacheForProjection(projection);
|
||||
}
|
||||
const thisProj = this.getProjection();
|
||||
if (!thisProj || equivalent(thisProj, projection)) {
|
||||
return this.tileCache;
|
||||
} else {
|
||||
const projKey = getUid(projection);
|
||||
if (!(projKey in this.tileCacheForProjection)) {
|
||||
this.tileCacheForProjection[projKey] = new TileCache(
|
||||
this.tileCache.highWaterMark
|
||||
);
|
||||
}
|
||||
return this.tileCacheForProjection[projKey];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @param {string} key The key set on the tile.
|
||||
* @return {!ImageTile} Tile.
|
||||
* @private
|
||||
*/
|
||||
createTile_(z, x, y, pixelRatio, projection, key) {
|
||||
const tileCoord = [z, x, y];
|
||||
const urlTileCoord = this.getTileCoordForTileUrlFunction(
|
||||
tileCoord,
|
||||
projection
|
||||
);
|
||||
const tileUrl = urlTileCoord
|
||||
? this.tileUrlFunction(urlTileCoord, pixelRatio, projection)
|
||||
: undefined;
|
||||
const tile = new this.tileClass(
|
||||
tileCoord,
|
||||
tileUrl !== undefined ? TileState.IDLE : TileState.EMPTY,
|
||||
tileUrl !== undefined ? tileUrl : '',
|
||||
this.crossOrigin,
|
||||
this.tileLoadFunction,
|
||||
this.tileOptions
|
||||
);
|
||||
tile.key = key;
|
||||
tile.addEventListener(EventType.CHANGE, this.handleTileChange.bind(this));
|
||||
return tile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {!(ImageTile|ReprojTile)} Tile.
|
||||
*/
|
||||
getTile(z, x, y, pixelRatio, projection) {
|
||||
const sourceProjection = this.getProjection();
|
||||
if (
|
||||
!ENABLE_RASTER_REPROJECTION ||
|
||||
!sourceProjection ||
|
||||
!projection ||
|
||||
equivalent(sourceProjection, projection)
|
||||
) {
|
||||
return this.getTileInternal(
|
||||
z,
|
||||
x,
|
||||
y,
|
||||
pixelRatio,
|
||||
sourceProjection || projection
|
||||
);
|
||||
} else {
|
||||
const cache = this.getTileCacheForProjection(projection);
|
||||
const tileCoord = [z, x, y];
|
||||
let tile;
|
||||
const tileCoordKey = getKey(tileCoord);
|
||||
if (cache.containsKey(tileCoordKey)) {
|
||||
tile = cache.get(tileCoordKey);
|
||||
}
|
||||
const key = this.getKey();
|
||||
if (tile && tile.key == key) {
|
||||
return tile;
|
||||
} else {
|
||||
const sourceTileGrid = this.getTileGridForProjection(sourceProjection);
|
||||
const targetTileGrid = this.getTileGridForProjection(projection);
|
||||
const wrappedTileCoord = this.getTileCoordForTileUrlFunction(
|
||||
tileCoord,
|
||||
projection
|
||||
);
|
||||
const newTile = new ReprojTile(
|
||||
sourceProjection,
|
||||
sourceTileGrid,
|
||||
projection,
|
||||
targetTileGrid,
|
||||
tileCoord,
|
||||
wrappedTileCoord,
|
||||
this.getTilePixelRatio(pixelRatio),
|
||||
this.getGutter(),
|
||||
function (z, x, y, pixelRatio) {
|
||||
return this.getTileInternal(z, x, y, pixelRatio, sourceProjection);
|
||||
}.bind(this),
|
||||
this.reprojectionErrorThreshold_,
|
||||
this.renderReprojectionEdges_,
|
||||
this.getInterpolate()
|
||||
);
|
||||
newTile.key = key;
|
||||
|
||||
if (tile) {
|
||||
newTile.interimTile = tile;
|
||||
newTile.refreshInterimChain();
|
||||
cache.replace(tileCoordKey, newTile);
|
||||
} else {
|
||||
cache.set(tileCoordKey, newTile);
|
||||
}
|
||||
return newTile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {!import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {!(ImageTile|ReprojTile)} Tile.
|
||||
* @protected
|
||||
*/
|
||||
getTileInternal(z, x, y, pixelRatio, projection) {
|
||||
let tile = null;
|
||||
const tileCoordKey = getKeyZXY(z, x, y);
|
||||
const key = this.getKey();
|
||||
if (!this.tileCache.containsKey(tileCoordKey)) {
|
||||
tile = this.createTile_(z, x, y, pixelRatio, projection, key);
|
||||
this.tileCache.set(tileCoordKey, tile);
|
||||
} else {
|
||||
tile = this.tileCache.get(tileCoordKey);
|
||||
if (tile.key != key) {
|
||||
// The source's params changed. If the tile has an interim tile and if we
|
||||
// can use it then we use it. Otherwise we create a new tile. In both
|
||||
// cases we attempt to assign an interim tile to the new tile.
|
||||
const interimTile = tile;
|
||||
tile = this.createTile_(z, x, y, pixelRatio, projection, key);
|
||||
|
||||
//make the new tile the head of the list,
|
||||
if (interimTile.getState() == TileState.IDLE) {
|
||||
//the old tile hasn't begun loading yet, and is now outdated, so we can simply discard it
|
||||
tile.interimTile = interimTile.interimTile;
|
||||
} else {
|
||||
tile.interimTile = interimTile;
|
||||
}
|
||||
tile.refreshInterimChain();
|
||||
this.tileCache.replace(tileCoordKey, tile);
|
||||
}
|
||||
}
|
||||
return tile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to render reprojection edges or not (usually for debugging).
|
||||
* @param {boolean} render Render the edges.
|
||||
* @api
|
||||
*/
|
||||
setRenderReprojectionEdges(render) {
|
||||
if (
|
||||
!ENABLE_RASTER_REPROJECTION ||
|
||||
this.renderReprojectionEdges_ == render
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.renderReprojectionEdges_ = render;
|
||||
for (const id in this.tileCacheForProjection) {
|
||||
this.tileCacheForProjection[id].clear();
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tile grid to use when reprojecting the tiles to the given
|
||||
* projection instead of the default tile grid for the projection.
|
||||
*
|
||||
* This can be useful when the default tile grid cannot be created
|
||||
* (e.g. projection has no extent defined) or
|
||||
* for optimization reasons (custom tile size, resolutions, ...).
|
||||
*
|
||||
* @param {import("../proj.js").ProjectionLike} projection Projection.
|
||||
* @param {import("../tilegrid/TileGrid.js").default} tilegrid Tile grid to use for the projection.
|
||||
* @api
|
||||
*/
|
||||
setTileGridForProjection(projection, tilegrid) {
|
||||
if (ENABLE_RASTER_REPROJECTION) {
|
||||
const proj = getProjection(projection);
|
||||
if (proj) {
|
||||
const projKey = getUid(proj);
|
||||
if (!(projKey in this.tileGridForProjection)) {
|
||||
this.tileGridForProjection[projKey] = tilegrid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ImageTile} imageTile Image tile.
|
||||
* @param {string} src Source.
|
||||
*/
|
||||
function defaultTileLoadFunction(imageTile, src) {
|
||||
/** @type {HTMLImageElement|HTMLVideoElement} */ (imageTile.getImage()).src =
|
||||
src;
|
||||
}
|
||||
|
||||
export default TileImage;
|
||||
219
node_modules/ol/src/source/TileJSON.js
generated
vendored
Normal file
219
node_modules/ol/src/source/TileJSON.js
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* @module ol/source/TileJSON
|
||||
*/
|
||||
// FIXME check order of async callbacks
|
||||
|
||||
/**
|
||||
* See https://mapbox.com/developers/api/.
|
||||
*/
|
||||
|
||||
import TileImage from './TileImage.js';
|
||||
import {applyTransform, intersects} from '../extent.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {createFromTemplates} from '../tileurlfunction.js';
|
||||
import {createXYZ, extentFromProjection} from '../tilegrid.js';
|
||||
import {get as getProjection, getTransformFromProjections} from '../proj.js';
|
||||
import {jsonp as requestJSONP} from '../net.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Config
|
||||
* @property {string} [name] The name.
|
||||
* @property {string} [description] The description.
|
||||
* @property {string} [version] The version.
|
||||
* @property {string} [attribution] The attribution.
|
||||
* @property {string} [template] The template.
|
||||
* @property {string} [legend] The legend.
|
||||
* @property {string} [scheme] The scheme.
|
||||
* @property {Array<string>} tiles The tile URL templates.
|
||||
* @property {Array<string>} [grids] Optional grids.
|
||||
* @property {number} [minzoom] Minimum zoom level.
|
||||
* @property {number} [maxzoom] Maximum zoom level.
|
||||
* @property {Array<number>} [bounds] Optional bounds.
|
||||
* @property {Array<number>} [center] Optional center.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {boolean} [jsonp=false] Use JSONP with callback to load the TileJSON.
|
||||
* Useful when the server does not support CORS..
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {Config} [tileJSON] TileJSON configuration for this source.
|
||||
* If not provided, `url` must be configured.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is
|
||||
* ```js
|
||||
* function(imageTile, src) {
|
||||
* imageTile.getImage().src = src;
|
||||
* };
|
||||
* ```
|
||||
* @property {number|import("../size.js").Size} [tileSize=[256, 256]] The tile size used by the tile service.
|
||||
* Note: `tileSize` and other non-standard TileJSON properties are currently ignored.
|
||||
* @property {string} [url] URL to the TileJSON file. If not provided, `tileJSON` must be configured.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* @property {number} [transition] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for tile data in TileJSON format.
|
||||
* @api
|
||||
*/
|
||||
class TileJSON extends TileImage {
|
||||
/**
|
||||
* @param {Options} options TileJSON options.
|
||||
*/
|
||||
constructor(options) {
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: options.crossOrigin,
|
||||
interpolate: interpolate,
|
||||
projection: getProjection('EPSG:3857'),
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
state: 'loading',
|
||||
tileLoadFunction: options.tileLoadFunction,
|
||||
wrapX: options.wrapX !== undefined ? options.wrapX : true,
|
||||
transition: options.transition,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {Config}
|
||||
* @private
|
||||
*/
|
||||
this.tileJSON_ = null;
|
||||
|
||||
/**
|
||||
* @type {number|import("../size.js").Size}
|
||||
* @private
|
||||
*/
|
||||
this.tileSize_ = options.tileSize;
|
||||
|
||||
if (options.url) {
|
||||
if (options.jsonp) {
|
||||
requestJSONP(
|
||||
options.url,
|
||||
this.handleTileJSONResponse.bind(this),
|
||||
this.handleTileJSONError.bind(this)
|
||||
);
|
||||
} else {
|
||||
const client = new XMLHttpRequest();
|
||||
client.addEventListener('load', this.onXHRLoad_.bind(this));
|
||||
client.addEventListener('error', this.onXHRError_.bind(this));
|
||||
client.open('GET', options.url);
|
||||
client.send();
|
||||
}
|
||||
} else if (options.tileJSON) {
|
||||
this.handleTileJSONResponse(options.tileJSON);
|
||||
} else {
|
||||
assert(false, 51); // Either `url` or `tileJSON` options must be provided
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event The load event.
|
||||
*/
|
||||
onXHRLoad_(event) {
|
||||
const client = /** @type {XMLHttpRequest} */ (event.target);
|
||||
// status will be 0 for file:// urls
|
||||
if (!client.status || (client.status >= 200 && client.status < 300)) {
|
||||
let response;
|
||||
try {
|
||||
response = /** @type {Config} */ (JSON.parse(client.responseText));
|
||||
} catch (err) {
|
||||
this.handleTileJSONError();
|
||||
return;
|
||||
}
|
||||
this.handleTileJSONResponse(response);
|
||||
} else {
|
||||
this.handleTileJSONError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event The error event.
|
||||
*/
|
||||
onXHRError_(event) {
|
||||
this.handleTileJSONError();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Config} The tilejson object.
|
||||
* @api
|
||||
*/
|
||||
getTileJSON() {
|
||||
return this.tileJSON_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @param {Config} tileJSON Tile JSON.
|
||||
*/
|
||||
handleTileJSONResponse(tileJSON) {
|
||||
const epsg4326Projection = getProjection('EPSG:4326');
|
||||
|
||||
const sourceProjection = this.getProjection();
|
||||
let extent;
|
||||
if (tileJSON['bounds'] !== undefined) {
|
||||
const transform = getTransformFromProjections(
|
||||
epsg4326Projection,
|
||||
sourceProjection
|
||||
);
|
||||
extent = applyTransform(tileJSON['bounds'], transform);
|
||||
}
|
||||
|
||||
const gridExtent = extentFromProjection(sourceProjection);
|
||||
const minZoom = tileJSON['minzoom'] || 0;
|
||||
const maxZoom = tileJSON['maxzoom'] || 22;
|
||||
const tileGrid = createXYZ({
|
||||
extent: gridExtent,
|
||||
maxZoom: maxZoom,
|
||||
minZoom: minZoom,
|
||||
tileSize: this.tileSize_,
|
||||
});
|
||||
this.tileGrid = tileGrid;
|
||||
|
||||
this.tileUrlFunction = createFromTemplates(tileJSON['tiles'], tileGrid);
|
||||
|
||||
if (tileJSON['attribution'] !== undefined && !this.getAttributions()) {
|
||||
const attributionExtent = extent !== undefined ? extent : gridExtent;
|
||||
this.setAttributions(function (frameState) {
|
||||
if (intersects(attributionExtent, frameState.extent)) {
|
||||
return [tileJSON['attribution']];
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
this.tileJSON_ = tileJSON;
|
||||
this.setState('ready');
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handleTileJSONError() {
|
||||
this.setState('error');
|
||||
}
|
||||
}
|
||||
|
||||
export default TileJSON;
|
||||
478
node_modules/ol/src/source/TileWMS.js
generated
vendored
Normal file
478
node_modules/ol/src/source/TileWMS.js
generated
vendored
Normal file
@@ -0,0 +1,478 @@
|
||||
/**
|
||||
* @module ol/source/TileWMS
|
||||
*/
|
||||
|
||||
import TileImage from './TileImage.js';
|
||||
import {DEFAULT_VERSION} from './wms.js';
|
||||
import {appendParams} from '../uri.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {buffer, createEmpty} from '../extent.js';
|
||||
import {buffer as bufferSize, scale as scaleSize, toSize} from '../size.js';
|
||||
import {calculateSourceResolution} from '../reproj.js';
|
||||
import {compareVersions} from '../string.js';
|
||||
import {get as getProjection, transform, transformExtent} from '../proj.js';
|
||||
import {modulo} from '../math.js';
|
||||
import {hash as tileCoordHash} from '../tilecoord.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {Object<string,*>} params WMS request parameters.
|
||||
* At least a `LAYERS` param is required. `STYLES` is
|
||||
* `''` by default. `VERSION` is `1.3.0` by default. `WIDTH`, `HEIGHT`, `BBOX`
|
||||
* and `CRS` (`SRS` for WMS version < 1.3.0) will be set dynamically.
|
||||
* @property {number} [gutter=0]
|
||||
* The size in pixels of the gutter around image tiles to ignore. By setting
|
||||
* this property to a non-zero value, images will be requested that are wider
|
||||
* and taller than the tile size by a value of `2 x gutter`.
|
||||
* Using a non-zero value allows artifacts of rendering at tile edges to be
|
||||
* ignored. If you control the WMS service it is recommended to address
|
||||
* "artifacts at tile edges" issues by properly configuring the WMS service. For
|
||||
* example, MapServer has a `tile_map_edge_buffer` configuration parameter for
|
||||
* this. See https://mapserver.org/output/tile_mode.html.
|
||||
* @property {boolean} [hidpi=true] Use the `ol/Map#pixelRatio` value when requesting
|
||||
* the image from the remote server.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {typeof import("../ImageTile.js").default} [tileClass] Class used to instantiate image tiles.
|
||||
* Default is {@link module:ol/ImageTile~ImageTile}.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid. Base this on the resolutions,
|
||||
* tilesize and extent supported by the server.
|
||||
* If this is not defined, a default grid will be used: if there is a projection
|
||||
* extent, the grid will be based on that; if not, a grid based on a global
|
||||
* extent with origin at 0,0 will be used.
|
||||
* @property {import("./wms.js").ServerType} [serverType] The type of
|
||||
* the remote WMS server: `mapserver`, `geoserver`, `carmentaserver`, or `qgis`.
|
||||
* Only needed if `hidpi` is `true`.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is
|
||||
* ```js
|
||||
* function(imageTile, src) {
|
||||
* imageTile.getImage().src = src;
|
||||
* };
|
||||
* ```
|
||||
* @property {string} [url] WMS service URL.
|
||||
* @property {Array<string>} [urls] WMS service urls.
|
||||
* Use this instead of `url` when the WMS supports multiple urls for GetMap requests.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* When set to `false`, only one world
|
||||
* will be rendered. When `true`, tiles will be requested for one world only,
|
||||
* but they will be wrapped horizontally to render multiple worlds.
|
||||
* @property {number} [transition] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for tile data from WMS servers.
|
||||
* @api
|
||||
*/
|
||||
class TileWMS extends TileImage {
|
||||
/**
|
||||
* @param {Options} [opt_options] Tile WMS options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
const options = opt_options ? opt_options : /** @type {Options} */ ({});
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
const params = options.params || {};
|
||||
|
||||
const transparent = 'TRANSPARENT' in params ? params['TRANSPARENT'] : true;
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
attributionsCollapsible: options.attributionsCollapsible,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: options.crossOrigin,
|
||||
interpolate: interpolate,
|
||||
opaque: !transparent,
|
||||
projection: options.projection,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
tileClass: options.tileClass,
|
||||
tileGrid: options.tileGrid,
|
||||
tileLoadFunction: options.tileLoadFunction,
|
||||
url: options.url,
|
||||
urls: options.urls,
|
||||
wrapX: options.wrapX !== undefined ? options.wrapX : true,
|
||||
transition: options.transition,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.gutter_ = options.gutter !== undefined ? options.gutter : 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object}
|
||||
*/
|
||||
this.params_ = params;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.v13_ = true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./wms.js").ServerType}
|
||||
*/
|
||||
this.serverType_ = options.serverType;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../extent.js").Extent}
|
||||
*/
|
||||
this.tmpExtent_ = createEmpty();
|
||||
|
||||
this.updateV13_();
|
||||
this.setKey(this.getKeyForParams_());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the GetFeatureInfo URL for the passed coordinate, resolution, and
|
||||
* projection. Return `undefined` if the GetFeatureInfo URL cannot be
|
||||
* constructed.
|
||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {import("../proj.js").ProjectionLike} projection Projection.
|
||||
* @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should
|
||||
* be provided. If `QUERY_LAYERS` is not provided then the layers specified
|
||||
* in the `LAYERS` parameter will be used. `VERSION` should not be
|
||||
* specified here.
|
||||
* @return {string|undefined} GetFeatureInfo URL.
|
||||
* @api
|
||||
*/
|
||||
getFeatureInfoUrl(coordinate, resolution, projection, params) {
|
||||
const projectionObj = getProjection(projection);
|
||||
const sourceProjectionObj = this.getProjection();
|
||||
|
||||
let tileGrid = this.getTileGrid();
|
||||
if (!tileGrid) {
|
||||
tileGrid = this.getTileGridForProjection(projectionObj);
|
||||
}
|
||||
|
||||
const z = tileGrid.getZForResolution(resolution, this.zDirection);
|
||||
const tileCoord = tileGrid.getTileCoordForCoordAndZ(coordinate, z);
|
||||
|
||||
if (tileGrid.getResolutions().length <= tileCoord[0]) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let tileResolution = tileGrid.getResolution(tileCoord[0]);
|
||||
let tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
|
||||
let tileSize = toSize(tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
|
||||
|
||||
const gutter = this.gutter_;
|
||||
if (gutter !== 0) {
|
||||
tileSize = bufferSize(tileSize, gutter, this.tmpSize);
|
||||
tileExtent = buffer(tileExtent, tileResolution * gutter, tileExtent);
|
||||
}
|
||||
|
||||
if (sourceProjectionObj && sourceProjectionObj !== projectionObj) {
|
||||
tileResolution = calculateSourceResolution(
|
||||
sourceProjectionObj,
|
||||
projectionObj,
|
||||
coordinate,
|
||||
tileResolution
|
||||
);
|
||||
tileExtent = transformExtent(
|
||||
tileExtent,
|
||||
projectionObj,
|
||||
sourceProjectionObj
|
||||
);
|
||||
coordinate = transform(coordinate, projectionObj, sourceProjectionObj);
|
||||
}
|
||||
|
||||
const baseParams = {
|
||||
'SERVICE': 'WMS',
|
||||
'VERSION': DEFAULT_VERSION,
|
||||
'REQUEST': 'GetFeatureInfo',
|
||||
'FORMAT': 'image/png',
|
||||
'TRANSPARENT': true,
|
||||
'QUERY_LAYERS': this.params_['LAYERS'],
|
||||
};
|
||||
assign(baseParams, this.params_, params);
|
||||
|
||||
const x = Math.floor((coordinate[0] - tileExtent[0]) / tileResolution);
|
||||
const y = Math.floor((tileExtent[3] - coordinate[1]) / tileResolution);
|
||||
|
||||
baseParams[this.v13_ ? 'I' : 'X'] = x;
|
||||
baseParams[this.v13_ ? 'J' : 'Y'] = y;
|
||||
|
||||
return this.getRequestUrl_(
|
||||
tileCoord,
|
||||
tileSize,
|
||||
tileExtent,
|
||||
1,
|
||||
sourceProjectionObj || projectionObj,
|
||||
baseParams
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the GetLegendGraphic URL, optionally optimized for the passed
|
||||
* resolution and possibly including any passed specific parameters. Returns
|
||||
* `undefined` if the GetLegendGraphic URL cannot be constructed.
|
||||
*
|
||||
* @param {number} [resolution] Resolution. If set to undefined, `SCALE`
|
||||
* will not be calculated and included in URL.
|
||||
* @param {Object} [params] GetLegendGraphic params. If `LAYER` is set, the
|
||||
* request is generated for this wms layer, else it will try to use the
|
||||
* configured wms layer. Default `FORMAT` is `image/png`.
|
||||
* `VERSION` should not be specified here.
|
||||
* @return {string|undefined} GetLegendGraphic URL.
|
||||
* @api
|
||||
*/
|
||||
getLegendUrl(resolution, params) {
|
||||
if (this.urls[0] === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const baseParams = {
|
||||
'SERVICE': 'WMS',
|
||||
'VERSION': DEFAULT_VERSION,
|
||||
'REQUEST': 'GetLegendGraphic',
|
||||
'FORMAT': 'image/png',
|
||||
};
|
||||
|
||||
if (params === undefined || params['LAYER'] === undefined) {
|
||||
const layers = this.params_.LAYERS;
|
||||
const isSingleLayer = !Array.isArray(layers) || layers.length === 1;
|
||||
if (!isSingleLayer) {
|
||||
return undefined;
|
||||
}
|
||||
baseParams['LAYER'] = layers;
|
||||
}
|
||||
|
||||
if (resolution !== undefined) {
|
||||
const mpu = this.getProjection()
|
||||
? this.getProjection().getMetersPerUnit()
|
||||
: 1;
|
||||
const pixelSize = 0.00028;
|
||||
baseParams['SCALE'] = (resolution * mpu) / pixelSize;
|
||||
}
|
||||
|
||||
assign(baseParams, params);
|
||||
|
||||
return appendParams(/** @type {string} */ (this.urls[0]), baseParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number} Gutter.
|
||||
*/
|
||||
getGutter() {
|
||||
return this.gutter_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user-provided params, i.e. those passed to the constructor through
|
||||
* the "params" option, and possibly updated using the updateParams method.
|
||||
* @return {Object} Params.
|
||||
* @api
|
||||
*/
|
||||
getParams() {
|
||||
return this.params_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {import("../size.js").Size} tileSize Tile size.
|
||||
* @param {import("../extent.js").Extent} tileExtent Tile extent.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @param {Object} params Params.
|
||||
* @return {string|undefined} Request URL.
|
||||
* @private
|
||||
*/
|
||||
getRequestUrl_(
|
||||
tileCoord,
|
||||
tileSize,
|
||||
tileExtent,
|
||||
pixelRatio,
|
||||
projection,
|
||||
params
|
||||
) {
|
||||
const urls = this.urls;
|
||||
if (!urls) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
params['WIDTH'] = tileSize[0];
|
||||
params['HEIGHT'] = tileSize[1];
|
||||
|
||||
params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode();
|
||||
|
||||
if (!('STYLES' in this.params_)) {
|
||||
params['STYLES'] = '';
|
||||
}
|
||||
|
||||
if (pixelRatio != 1) {
|
||||
switch (this.serverType_) {
|
||||
case 'geoserver':
|
||||
const dpi = (90 * pixelRatio + 0.5) | 0;
|
||||
if ('FORMAT_OPTIONS' in params) {
|
||||
params['FORMAT_OPTIONS'] += ';dpi:' + dpi;
|
||||
} else {
|
||||
params['FORMAT_OPTIONS'] = 'dpi:' + dpi;
|
||||
}
|
||||
break;
|
||||
case 'mapserver':
|
||||
params['MAP_RESOLUTION'] = 90 * pixelRatio;
|
||||
break;
|
||||
case 'carmentaserver':
|
||||
case 'qgis':
|
||||
params['DPI'] = 90 * pixelRatio;
|
||||
break;
|
||||
default: // Unknown `serverType` configured
|
||||
assert(false, 52);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const axisOrientation = projection.getAxisOrientation();
|
||||
const bbox = tileExtent;
|
||||
if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') {
|
||||
let tmp;
|
||||
tmp = tileExtent[0];
|
||||
bbox[0] = tileExtent[1];
|
||||
bbox[1] = tmp;
|
||||
tmp = tileExtent[2];
|
||||
bbox[2] = tileExtent[3];
|
||||
bbox[3] = tmp;
|
||||
}
|
||||
params['BBOX'] = bbox.join(',');
|
||||
|
||||
let url;
|
||||
if (urls.length == 1) {
|
||||
url = urls[0];
|
||||
} else {
|
||||
const index = modulo(tileCoordHash(tileCoord), urls.length);
|
||||
url = urls[index];
|
||||
}
|
||||
return appendParams(url, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tile pixel ratio for this source.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @return {number} Tile pixel ratio.
|
||||
*/
|
||||
getTilePixelRatio(pixelRatio) {
|
||||
return !this.hidpi_ || this.serverType_ === undefined ? 1 : pixelRatio;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {string} The key for the current params.
|
||||
*/
|
||||
getKeyForParams_() {
|
||||
let i = 0;
|
||||
const res = [];
|
||||
for (const key in this.params_) {
|
||||
res[i++] = key + '-' + this.params_[key];
|
||||
}
|
||||
return res.join('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user-provided params.
|
||||
* @param {Object} params Params.
|
||||
* @api
|
||||
*/
|
||||
updateParams(params) {
|
||||
assign(this.params_, params);
|
||||
this.updateV13_();
|
||||
this.setKey(this.getKeyForParams_());
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateV13_() {
|
||||
const version = this.params_['VERSION'] || DEFAULT_VERSION;
|
||||
this.v13_ = compareVersions(version, '1.3') >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord The tile coordinate
|
||||
* @param {number} pixelRatio The pixel ratio
|
||||
* @param {import("../proj/Projection.js").default} projection The projection
|
||||
* @return {string|undefined} The tile URL
|
||||
* @override
|
||||
*/
|
||||
tileUrlFunction(tileCoord, pixelRatio, projection) {
|
||||
let tileGrid = this.getTileGrid();
|
||||
if (!tileGrid) {
|
||||
tileGrid = this.getTileGridForProjection(projection);
|
||||
}
|
||||
|
||||
if (tileGrid.getResolutions().length <= tileCoord[0]) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) {
|
||||
pixelRatio = 1;
|
||||
}
|
||||
|
||||
const tileResolution = tileGrid.getResolution(tileCoord[0]);
|
||||
let tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
|
||||
let tileSize = toSize(tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
|
||||
|
||||
const gutter = this.gutter_;
|
||||
if (gutter !== 0) {
|
||||
tileSize = bufferSize(tileSize, gutter, this.tmpSize);
|
||||
tileExtent = buffer(tileExtent, tileResolution * gutter, tileExtent);
|
||||
}
|
||||
|
||||
if (pixelRatio != 1) {
|
||||
tileSize = scaleSize(tileSize, pixelRatio, this.tmpSize);
|
||||
}
|
||||
|
||||
const baseParams = {
|
||||
'SERVICE': 'WMS',
|
||||
'VERSION': DEFAULT_VERSION,
|
||||
'REQUEST': 'GetMap',
|
||||
'FORMAT': 'image/png',
|
||||
'TRANSPARENT': true,
|
||||
};
|
||||
assign(baseParams, this.params_);
|
||||
|
||||
return this.getRequestUrl_(
|
||||
tileCoord,
|
||||
tileSize,
|
||||
tileExtent,
|
||||
pixelRatio,
|
||||
projection,
|
||||
baseParams
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TileWMS;
|
||||
526
node_modules/ol/src/source/UTFGrid.js
generated
vendored
Normal file
526
node_modules/ol/src/source/UTFGrid.js
generated
vendored
Normal file
@@ -0,0 +1,526 @@
|
||||
/**
|
||||
* @module ol/source/UTFGrid
|
||||
*/
|
||||
|
||||
import EventType from '../events/EventType.js';
|
||||
import Tile from '../Tile.js';
|
||||
import TileSource from './Tile.js';
|
||||
import TileState from '../TileState.js';
|
||||
import {applyTransform, intersects} from '../extent.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {createFromTemplates, nullTileUrlFunction} from '../tileurlfunction.js';
|
||||
import {createXYZ, extentFromProjection} from '../tilegrid.js';
|
||||
import {getKeyZXY} from '../tilecoord.js';
|
||||
import {get as getProjection, getTransformFromProjections} from '../proj.js';
|
||||
import {listenOnce} from '../events.js';
|
||||
import {jsonp as requestJSONP} from '../net.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} UTFGridJSON
|
||||
* @property {Array<string>} grid The grid.
|
||||
* @property {Array<string>} keys The keys.
|
||||
* @property {Object<string, Object>} [data] Optional data.
|
||||
*/
|
||||
|
||||
export class CustomTile extends Tile {
|
||||
/**
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {import("../TileState.js").default} state State.
|
||||
* @param {string} src Image source URI.
|
||||
* @param {import("../extent.js").Extent} extent Extent of the tile.
|
||||
* @param {boolean} preemptive Load the tile when visible (before it's needed).
|
||||
* @param {boolean} jsonp Load the tile as a script.
|
||||
*/
|
||||
constructor(tileCoord, state, src, extent, preemptive, jsonp) {
|
||||
super(tileCoord, state);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.src_ = src;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../extent.js").Extent}
|
||||
*/
|
||||
this.extent_ = extent;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.preemptive_ = preemptive;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
this.grid_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
this.keys_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object<string, Object>|undefined}
|
||||
*/
|
||||
this.data_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.jsonp_ = jsonp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the image element for this tile.
|
||||
* @return {HTMLImageElement} Image.
|
||||
*/
|
||||
getImage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously returns data at given coordinate (if available).
|
||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||
* @return {*} The data.
|
||||
*/
|
||||
getData(coordinate) {
|
||||
if (!this.grid_ || !this.keys_) {
|
||||
return null;
|
||||
}
|
||||
const xRelative =
|
||||
(coordinate[0] - this.extent_[0]) / (this.extent_[2] - this.extent_[0]);
|
||||
const yRelative =
|
||||
(coordinate[1] - this.extent_[1]) / (this.extent_[3] - this.extent_[1]);
|
||||
|
||||
const row = this.grid_[Math.floor((1 - yRelative) * this.grid_.length)];
|
||||
|
||||
if (typeof row !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
let code = row.charCodeAt(Math.floor(xRelative * row.length));
|
||||
if (code >= 93) {
|
||||
code--;
|
||||
}
|
||||
if (code >= 35) {
|
||||
code--;
|
||||
}
|
||||
code -= 32;
|
||||
|
||||
let data = null;
|
||||
if (code in this.keys_) {
|
||||
const id = this.keys_[code];
|
||||
if (this.data_ && id in this.data_) {
|
||||
data = this.data_[id];
|
||||
} else {
|
||||
data = id;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the callback (synchronously by default) with the available data
|
||||
* for given coordinate (or `null` if not yet loaded).
|
||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||
* @param {function(*): void} callback Callback.
|
||||
* @param {boolean} [opt_request] If `true` the callback is always async.
|
||||
* The tile data is requested if not yet loaded.
|
||||
*/
|
||||
forDataAtCoordinate(coordinate, callback, opt_request) {
|
||||
if (this.state == TileState.EMPTY && opt_request === true) {
|
||||
this.state = TileState.IDLE;
|
||||
listenOnce(
|
||||
this,
|
||||
EventType.CHANGE,
|
||||
function (e) {
|
||||
callback(this.getData(coordinate));
|
||||
},
|
||||
this
|
||||
);
|
||||
this.loadInternal_();
|
||||
} else {
|
||||
if (opt_request === true) {
|
||||
setTimeout(
|
||||
function () {
|
||||
callback(this.getData(coordinate));
|
||||
}.bind(this),
|
||||
0
|
||||
);
|
||||
} else {
|
||||
callback(this.getData(coordinate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key to be used for all tiles in the source.
|
||||
* @return {string} The key for all tiles.
|
||||
*/
|
||||
getKey() {
|
||||
return this.src_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleError_() {
|
||||
this.state = TileState.ERROR;
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!UTFGridJSON} json UTFGrid data.
|
||||
* @private
|
||||
*/
|
||||
handleLoad_(json) {
|
||||
this.grid_ = json['grid'];
|
||||
this.keys_ = json['keys'];
|
||||
this.data_ = json['data'];
|
||||
|
||||
this.state = TileState.LOADED;
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
loadInternal_() {
|
||||
if (this.state == TileState.IDLE) {
|
||||
this.state = TileState.LOADING;
|
||||
if (this.jsonp_) {
|
||||
requestJSONP(
|
||||
this.src_,
|
||||
this.handleLoad_.bind(this),
|
||||
this.handleError_.bind(this)
|
||||
);
|
||||
} else {
|
||||
const client = new XMLHttpRequest();
|
||||
client.addEventListener('load', this.onXHRLoad_.bind(this));
|
||||
client.addEventListener('error', this.onXHRError_.bind(this));
|
||||
client.open('GET', this.src_);
|
||||
client.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event The load event.
|
||||
*/
|
||||
onXHRLoad_(event) {
|
||||
const client = /** @type {XMLHttpRequest} */ (event.target);
|
||||
// status will be 0 for file:// urls
|
||||
if (!client.status || (client.status >= 200 && client.status < 300)) {
|
||||
let response;
|
||||
try {
|
||||
response = /** @type {!UTFGridJSON} */ (
|
||||
JSON.parse(client.responseText)
|
||||
);
|
||||
} catch (err) {
|
||||
this.handleError_();
|
||||
return;
|
||||
}
|
||||
this.handleLoad_(response);
|
||||
} else {
|
||||
this.handleError_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event The error event.
|
||||
*/
|
||||
onXHRError_(event) {
|
||||
this.handleError_();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
load() {
|
||||
if (this.preemptive_) {
|
||||
this.loadInternal_();
|
||||
} else {
|
||||
this.setState(TileState.EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {boolean} [preemptive=true]
|
||||
* If `true` the UTFGrid source loads the tiles based on their "visibility".
|
||||
* This improves the speed of response, but increases traffic.
|
||||
* Note that if set to `false` (lazy loading), you need to pass `true` as
|
||||
* `opt_request` to the `forDataAtCoordinateAndResolution` method otherwise no
|
||||
* data will ever be loaded.
|
||||
* @property {boolean} [jsonp=false] Use JSONP with callback to load the TileJSON.
|
||||
* Useful when the server does not support CORS..
|
||||
* @property {import("./TileJSON.js").Config} [tileJSON] TileJSON configuration for this source.
|
||||
* If not provided, `url` must be configured.
|
||||
* @property {string} [url] TileJSON endpoint that provides the configuration for this source.
|
||||
* Request will be made through JSONP. If not provided, `tileJSON` must be configured.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for UTFGrid interaction data loaded from TileJSON format.
|
||||
* @api
|
||||
*/
|
||||
class UTFGrid extends TileSource {
|
||||
/**
|
||||
* @param {Options} options Source options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super({
|
||||
projection: getProjection('EPSG:3857'),
|
||||
state: 'loading',
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.preemptive_ =
|
||||
options.preemptive !== undefined ? options.preemptive : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!import("../Tile.js").UrlFunction}
|
||||
*/
|
||||
this.tileUrlFunction_ = nullTileUrlFunction;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.template_ = undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.jsonp_ = options.jsonp || false;
|
||||
|
||||
if (options.url) {
|
||||
if (this.jsonp_) {
|
||||
requestJSONP(
|
||||
options.url,
|
||||
this.handleTileJSONResponse.bind(this),
|
||||
this.handleTileJSONError.bind(this)
|
||||
);
|
||||
} else {
|
||||
const client = new XMLHttpRequest();
|
||||
client.addEventListener('load', this.onXHRLoad_.bind(this));
|
||||
client.addEventListener('error', this.onXHRError_.bind(this));
|
||||
client.open('GET', options.url);
|
||||
client.send();
|
||||
}
|
||||
} else if (options.tileJSON) {
|
||||
this.handleTileJSONResponse(options.tileJSON);
|
||||
} else {
|
||||
assert(false, 51); // Either `url` or `tileJSON` options must be provided
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event The load event.
|
||||
*/
|
||||
onXHRLoad_(event) {
|
||||
const client = /** @type {XMLHttpRequest} */ (event.target);
|
||||
// status will be 0 for file:// urls
|
||||
if (!client.status || (client.status >= 200 && client.status < 300)) {
|
||||
let response;
|
||||
try {
|
||||
response = /** @type {import("./TileJSON.js").Config} */ (
|
||||
JSON.parse(client.responseText)
|
||||
);
|
||||
} catch (err) {
|
||||
this.handleTileJSONError();
|
||||
return;
|
||||
}
|
||||
this.handleTileJSONResponse(response);
|
||||
} else {
|
||||
this.handleTileJSONError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event The error event.
|
||||
*/
|
||||
onXHRError_(event) {
|
||||
this.handleTileJSONError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the template from TileJSON.
|
||||
* @return {string|undefined} The template from TileJSON.
|
||||
* @api
|
||||
*/
|
||||
getTemplate() {
|
||||
return this.template_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the callback (synchronously by default) with the available data
|
||||
* for given coordinate and resolution (or `null` if not yet loaded or
|
||||
* in case of an error).
|
||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {function(*): void} callback Callback.
|
||||
* @param {boolean} [opt_request] If `true` the callback is always async.
|
||||
* The tile data is requested if not yet loaded.
|
||||
* @api
|
||||
*/
|
||||
forDataAtCoordinateAndResolution(
|
||||
coordinate,
|
||||
resolution,
|
||||
callback,
|
||||
opt_request
|
||||
) {
|
||||
if (this.tileGrid) {
|
||||
const z = this.tileGrid.getZForResolution(resolution, this.zDirection);
|
||||
const tileCoord = this.tileGrid.getTileCoordForCoordAndZ(coordinate, z);
|
||||
const tile = /** @type {!CustomTile} */ (
|
||||
this.getTile(
|
||||
tileCoord[0],
|
||||
tileCoord[1],
|
||||
tileCoord[2],
|
||||
1,
|
||||
this.getProjection()
|
||||
)
|
||||
);
|
||||
tile.forDataAtCoordinate(coordinate, callback, opt_request);
|
||||
} else {
|
||||
if (opt_request === true) {
|
||||
setTimeout(function () {
|
||||
callback(null);
|
||||
}, 0);
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handleTileJSONError() {
|
||||
this.setState('error');
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: very similar to ol/source/TileJSON#handleTileJSONResponse
|
||||
* @protected
|
||||
* @param {import("./TileJSON.js").Config} tileJSON Tile JSON.
|
||||
*/
|
||||
handleTileJSONResponse(tileJSON) {
|
||||
const epsg4326Projection = getProjection('EPSG:4326');
|
||||
|
||||
const sourceProjection = this.getProjection();
|
||||
let extent;
|
||||
if (tileJSON['bounds'] !== undefined) {
|
||||
const transform = getTransformFromProjections(
|
||||
epsg4326Projection,
|
||||
sourceProjection
|
||||
);
|
||||
extent = applyTransform(tileJSON['bounds'], transform);
|
||||
}
|
||||
|
||||
const gridExtent = extentFromProjection(sourceProjection);
|
||||
const minZoom = tileJSON['minzoom'] || 0;
|
||||
const maxZoom = tileJSON['maxzoom'] || 22;
|
||||
const tileGrid = createXYZ({
|
||||
extent: gridExtent,
|
||||
maxZoom: maxZoom,
|
||||
minZoom: minZoom,
|
||||
});
|
||||
this.tileGrid = tileGrid;
|
||||
|
||||
this.template_ = tileJSON['template'];
|
||||
|
||||
const grids = tileJSON['grids'];
|
||||
if (!grids) {
|
||||
this.setState('error');
|
||||
return;
|
||||
}
|
||||
|
||||
this.tileUrlFunction_ = createFromTemplates(grids, tileGrid);
|
||||
|
||||
if (tileJSON['attribution'] !== undefined) {
|
||||
const attributionExtent = extent !== undefined ? extent : gridExtent;
|
||||
this.setAttributions(function (frameState) {
|
||||
if (intersects(attributionExtent, frameState.extent)) {
|
||||
return [tileJSON['attribution']];
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
this.setState('ready');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {!CustomTile} Tile.
|
||||
*/
|
||||
getTile(z, x, y, pixelRatio, projection) {
|
||||
const tileCoordKey = getKeyZXY(z, x, y);
|
||||
if (this.tileCache.containsKey(tileCoordKey)) {
|
||||
return this.tileCache.get(tileCoordKey);
|
||||
} else {
|
||||
const tileCoord = [z, x, y];
|
||||
const urlTileCoord = this.getTileCoordForTileUrlFunction(
|
||||
tileCoord,
|
||||
projection
|
||||
);
|
||||
const tileUrl = this.tileUrlFunction_(
|
||||
urlTileCoord,
|
||||
pixelRatio,
|
||||
projection
|
||||
);
|
||||
const tile = new CustomTile(
|
||||
tileCoord,
|
||||
tileUrl !== undefined ? TileState.IDLE : TileState.EMPTY,
|
||||
tileUrl !== undefined ? tileUrl : '',
|
||||
this.tileGrid.getTileCoordExtent(tileCoord),
|
||||
this.preemptive_,
|
||||
this.jsonp_
|
||||
);
|
||||
this.tileCache.set(tileCoordKey, tile);
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a tile coord as being used, without triggering a load.
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
*/
|
||||
useTile(z, x, y) {
|
||||
const tileCoordKey = getKeyZXY(z, x, y);
|
||||
if (this.tileCache.containsKey(tileCoordKey)) {
|
||||
this.tileCache.get(tileCoordKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default UTFGrid;
|
||||
231
node_modules/ol/src/source/UrlTile.js
generated
vendored
Normal file
231
node_modules/ol/src/source/UrlTile.js
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* @module ol/source/UrlTile
|
||||
*/
|
||||
import TileEventType from './TileEventType.js';
|
||||
import TileSource, {TileSourceEvent} from './Tile.js';
|
||||
import TileState from '../TileState.js';
|
||||
import {createFromTemplates, expandUrl} from '../tileurlfunction.js';
|
||||
import {getKeyZXY} from '../tilecoord.js';
|
||||
import {getUid} from '../util.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {number} [cacheSize] Cache size.
|
||||
* @property {boolean} [opaque=false] Whether the layer is opaque.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection.
|
||||
* @property {import("./Source.js").State} [state] State.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] TileGrid.
|
||||
* @property {import("../Tile.js").LoadFunction} tileLoadFunction TileLoadFunction.
|
||||
* @property {number} [tilePixelRatio] TilePixelRatio.
|
||||
* @property {import("../Tile.js").UrlFunction} [tileUrlFunction] TileUrlFunction.
|
||||
* @property {string} [url] Url.
|
||||
* @property {Array<string>} [urls] Urls.
|
||||
* @property {boolean} [wrapX=true] WrapX.
|
||||
* @property {number} [transition] Transition.
|
||||
* @property {string} [key] Key.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] ZDirection.
|
||||
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||
* the nearest neighbor is used when resampling.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Base class for sources providing tiles divided into a tile grid over http.
|
||||
*
|
||||
* @fires import("./Tile.js").TileSourceEvent
|
||||
*/
|
||||
class UrlTile extends TileSource {
|
||||
/**
|
||||
* @param {Options} options Image tile options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
cacheSize: options.cacheSize,
|
||||
opaque: options.opaque,
|
||||
projection: options.projection,
|
||||
state: options.state,
|
||||
tileGrid: options.tileGrid,
|
||||
tilePixelRatio: options.tilePixelRatio,
|
||||
wrapX: options.wrapX,
|
||||
transition: options.transition,
|
||||
interpolate: options.interpolate,
|
||||
key: options.key,
|
||||
attributionsCollapsible: options.attributionsCollapsible,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.generateTileUrlFunction_ =
|
||||
this.tileUrlFunction === UrlTile.prototype.tileUrlFunction;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {import("../Tile.js").LoadFunction}
|
||||
*/
|
||||
this.tileLoadFunction = options.tileLoadFunction;
|
||||
|
||||
if (options.tileUrlFunction) {
|
||||
this.tileUrlFunction = options.tileUrlFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {!Array<string>|null}
|
||||
*/
|
||||
this.urls = null;
|
||||
|
||||
if (options.urls) {
|
||||
this.setUrls(options.urls);
|
||||
} else if (options.url) {
|
||||
this.setUrl(options.url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object<string, boolean>}
|
||||
*/
|
||||
this.tileLoadingKeys_ = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tile load function of the source.
|
||||
* @return {import("../Tile.js").LoadFunction} TileLoadFunction
|
||||
* @api
|
||||
*/
|
||||
getTileLoadFunction() {
|
||||
return this.tileLoadFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tile URL function of the source.
|
||||
* @return {import("../Tile.js").UrlFunction} TileUrlFunction
|
||||
* @api
|
||||
*/
|
||||
getTileUrlFunction() {
|
||||
return Object.getPrototypeOf(this).tileUrlFunction === this.tileUrlFunction
|
||||
? this.tileUrlFunction.bind(this)
|
||||
: this.tileUrlFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URLs used for this source.
|
||||
* When a tileUrlFunction is used instead of url or urls,
|
||||
* null will be returned.
|
||||
* @return {!Array<string>|null} URLs.
|
||||
* @api
|
||||
*/
|
||||
getUrls() {
|
||||
return this.urls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle tile change events.
|
||||
* @param {import("../events/Event.js").default} event Event.
|
||||
* @protected
|
||||
*/
|
||||
handleTileChange(event) {
|
||||
const tile = /** @type {import("../Tile.js").default} */ (event.target);
|
||||
const uid = getUid(tile);
|
||||
const tileState = tile.getState();
|
||||
let type;
|
||||
if (tileState == TileState.LOADING) {
|
||||
this.tileLoadingKeys_[uid] = true;
|
||||
type = TileEventType.TILELOADSTART;
|
||||
} else if (uid in this.tileLoadingKeys_) {
|
||||
delete this.tileLoadingKeys_[uid];
|
||||
type =
|
||||
tileState == TileState.ERROR
|
||||
? TileEventType.TILELOADERROR
|
||||
: tileState == TileState.LOADED
|
||||
? TileEventType.TILELOADEND
|
||||
: undefined;
|
||||
}
|
||||
if (type != undefined) {
|
||||
this.dispatchEvent(new TileSourceEvent(type, tile));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tile load function of the source.
|
||||
* @param {import("../Tile.js").LoadFunction} tileLoadFunction Tile load function.
|
||||
* @api
|
||||
*/
|
||||
setTileLoadFunction(tileLoadFunction) {
|
||||
this.tileCache.clear();
|
||||
this.tileLoadFunction = tileLoadFunction;
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tile URL function of the source.
|
||||
* @param {import("../Tile.js").UrlFunction} tileUrlFunction Tile URL function.
|
||||
* @param {string} [key] Optional new tile key for the source.
|
||||
* @api
|
||||
*/
|
||||
setTileUrlFunction(tileUrlFunction, key) {
|
||||
this.tileUrlFunction = tileUrlFunction;
|
||||
this.tileCache.pruneExceptNewestZ();
|
||||
if (typeof key !== 'undefined') {
|
||||
this.setKey(key);
|
||||
} else {
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to use for requests.
|
||||
* @param {string} url URL.
|
||||
* @api
|
||||
*/
|
||||
setUrl(url) {
|
||||
const urls = expandUrl(url);
|
||||
this.urls = urls;
|
||||
this.setUrls(urls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URLs to use for requests.
|
||||
* @param {Array<string>} urls URLs.
|
||||
* @api
|
||||
*/
|
||||
setUrls(urls) {
|
||||
this.urls = urls;
|
||||
const key = urls.join('\n');
|
||||
if (this.generateTileUrlFunction_) {
|
||||
this.setTileUrlFunction(createFromTemplates(urls, this.tileGrid), key);
|
||||
} else {
|
||||
this.setKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {string|undefined} Tile URL.
|
||||
*/
|
||||
tileUrlFunction(tileCoord, pixelRatio, projection) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a tile coord as being used, without triggering a load.
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
*/
|
||||
useTile(z, x, y) {
|
||||
const tileCoordKey = getKeyZXY(z, x, y);
|
||||
if (this.tileCache.containsKey(tileCoordKey)) {
|
||||
this.tileCache.get(tileCoordKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default UrlTile;
|
||||
1138
node_modules/ol/src/source/Vector.js
generated
vendored
Normal file
1138
node_modules/ol/src/source/Vector.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
62
node_modules/ol/src/source/VectorEventType.js
generated
vendored
Normal file
62
node_modules/ol/src/source/VectorEventType.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @module ol/source/VectorEventType
|
||||
*/
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
export default {
|
||||
/**
|
||||
* Triggered when a feature is added to the source.
|
||||
* @event module:ol/source/Vector.VectorSourceEvent#addfeature
|
||||
* @api
|
||||
*/
|
||||
ADDFEATURE: 'addfeature',
|
||||
|
||||
/**
|
||||
* Triggered when a feature is updated.
|
||||
* @event module:ol/source/Vector.VectorSourceEvent#changefeature
|
||||
* @api
|
||||
*/
|
||||
CHANGEFEATURE: 'changefeature',
|
||||
|
||||
/**
|
||||
* Triggered when the clear method is called on the source.
|
||||
* @event module:ol/source/Vector.VectorSourceEvent#clear
|
||||
* @api
|
||||
*/
|
||||
CLEAR: 'clear',
|
||||
|
||||
/**
|
||||
* Triggered when a feature is removed from the source.
|
||||
* See {@link module:ol/source/Vector~VectorSource#clear source.clear()} for exceptions.
|
||||
* @event module:ol/source/Vector.VectorSourceEvent#removefeature
|
||||
* @api
|
||||
*/
|
||||
REMOVEFEATURE: 'removefeature',
|
||||
|
||||
/**
|
||||
* Triggered when features starts loading.
|
||||
* @event module:ol/source/Vector.VectorSourceEvent#featuresloadstart
|
||||
* @api
|
||||
*/
|
||||
FEATURESLOADSTART: 'featuresloadstart',
|
||||
|
||||
/**
|
||||
* Triggered when features finishes loading.
|
||||
* @event module:ol/source/Vector.VectorSourceEvent#featuresloadend
|
||||
* @api
|
||||
*/
|
||||
FEATURESLOADEND: 'featuresloadend',
|
||||
|
||||
/**
|
||||
* Triggered if feature loading results in an error.
|
||||
* @event module:ol/source/Vector.VectorSourceEvent#featuresloaderror
|
||||
* @api
|
||||
*/
|
||||
FEATURESLOADERROR: 'featuresloaderror',
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {'addfeature'|'changefeature'|'clear'|'removefeature'|'featuresloadstart'|'featuresloadend'|'featuresloaderror'} VectorSourceEventTypes
|
||||
*/
|
||||
518
node_modules/ol/src/source/VectorTile.js
generated
vendored
Normal file
518
node_modules/ol/src/source/VectorTile.js
generated
vendored
Normal file
@@ -0,0 +1,518 @@
|
||||
/**
|
||||
* @module ol/source/VectorTile
|
||||
*/
|
||||
|
||||
import EventType from '../events/EventType.js';
|
||||
import Tile from '../VectorTile.js';
|
||||
import TileCache from '../TileCache.js';
|
||||
import TileGrid from '../tilegrid/TileGrid.js';
|
||||
import TileState from '../TileState.js';
|
||||
import UrlTile from './UrlTile.js';
|
||||
import VectorRenderTile from '../VectorRenderTile.js';
|
||||
import {DEFAULT_MAX_ZOOM} from '../tilegrid/common.js';
|
||||
import {
|
||||
buffer as bufferExtent,
|
||||
getIntersection,
|
||||
intersects,
|
||||
} from '../extent.js';
|
||||
import {createXYZ, extentFromProjection} from '../tilegrid.js';
|
||||
import {fromKey, getCacheKeyForTileKey, getKeyZXY} from '../tilecoord.js';
|
||||
import {isEmpty} from '../obj.js';
|
||||
import {loadFeaturesXhr} from '../featureloader.js';
|
||||
import {toSize} from '../size.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least twice the number of tiles in the viewport.
|
||||
* @property {import("../extent.js").Extent} [extent] Extent.
|
||||
* @property {import("../format/Feature.js").default} [format] Feature format for tiles. Used and required by the default.
|
||||
* @property {boolean} [overlaps=true] This source may have overlapping geometries. Setting this
|
||||
* to `false` (e.g. for sources with polygons that represent administrative
|
||||
* boundaries or TopoJSON sources) allows the renderer to optimise fill and
|
||||
* stroke operations.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Projection of the tile grid.
|
||||
* @property {import("./Source.js").State} [state] Source state.
|
||||
* @property {typeof import("../VectorTile.js").default} [tileClass] Class used to instantiate image tiles.
|
||||
* Default is {@link module:ol/VectorTile~VectorTile}.
|
||||
* @property {number} [maxZoom=22] Optional max zoom level. Not used if `tileGrid` is provided.
|
||||
* @property {number} [minZoom] Optional min zoom level. Not used if `tileGrid` is provided.
|
||||
* @property {number|import("../size.js").Size} [tileSize=512] Optional tile size. Not used if `tileGrid` is provided.
|
||||
* @property {number} [maxResolution] Optional tile grid resolution at level zero. Not used if `tileGrid` is provided.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction]
|
||||
* Optional function to load a tile given a URL. Could look like this for pbf tiles:
|
||||
* ```js
|
||||
* function(tile, url) {
|
||||
* tile.setLoader(function(extent, resolution, projection) {
|
||||
* fetch(url).then(function(response) {
|
||||
* response.arrayBuffer().then(function(data) {
|
||||
* const format = tile.getFormat() // ol/format/MVT configured as source format
|
||||
* const features = format.readFeatures(data, {
|
||||
* extent: extent,
|
||||
* featureProjection: projection
|
||||
* });
|
||||
* tile.setFeatures(features);
|
||||
* });
|
||||
* });
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
* If you do not need extent, resolution and projection to get the features for a tile (e.g.
|
||||
* for GeoJSON tiles), your `tileLoadFunction` does not need a `setLoader()` call. Only make sure
|
||||
* to call `setFeatures()` on the tile:
|
||||
* ```js
|
||||
* const format = new GeoJSON({featureProjection: map.getView().getProjection()});
|
||||
* async function tileLoadFunction(tile, url) {
|
||||
* const response = await fetch(url);
|
||||
* const data = await response.json();
|
||||
* tile.setFeatures(format.readFeatures(data));
|
||||
* }
|
||||
* ```
|
||||
* @property {import("../Tile.js").UrlFunction} [tileUrlFunction] Optional function to get tile URL given a tile coordinate and the projection.
|
||||
* @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
|
||||
* A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be
|
||||
* used instead of defining each one separately in the `urls` option.
|
||||
* @property {number} [transition] A duration for tile opacity
|
||||
* transitions in milliseconds. A duration of 0 disables the opacity transition.
|
||||
* @property {Array<string>} [urls] An array of URL templates.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* When set to `false`, only one world
|
||||
* will be rendered. When set to `true`, tiles will be wrapped horizontally to
|
||||
* render multiple worlds.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=1]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Class for layer sources providing vector data divided into a tile grid, to be
|
||||
* used with {@link module:ol/layer/VectorTile~VectorTileLayer}. Although this source receives tiles
|
||||
* with vector features from the server, it is not meant for feature editing.
|
||||
* Features are optimized for rendering, their geometries are clipped at or near
|
||||
* tile boundaries and simplified for a view resolution. See
|
||||
* {@link module:ol/source/Vector~VectorSource} for vector sources that are suitable for feature
|
||||
* editing.
|
||||
*
|
||||
* @fires import("./Tile.js").TileSourceEvent
|
||||
* @api
|
||||
*/
|
||||
class VectorTile extends UrlTile {
|
||||
/**
|
||||
* @param {!Options} options Vector tile options.
|
||||
*/
|
||||
constructor(options) {
|
||||
const projection = options.projection || 'EPSG:3857';
|
||||
|
||||
const extent = options.extent || extentFromProjection(projection);
|
||||
|
||||
const tileGrid =
|
||||
options.tileGrid ||
|
||||
createXYZ({
|
||||
extent: extent,
|
||||
maxResolution: options.maxResolution,
|
||||
maxZoom: options.maxZoom !== undefined ? options.maxZoom : 22,
|
||||
minZoom: options.minZoom,
|
||||
tileSize: options.tileSize || 512,
|
||||
});
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
attributionsCollapsible: options.attributionsCollapsible,
|
||||
cacheSize: options.cacheSize,
|
||||
interpolate: true,
|
||||
opaque: false,
|
||||
projection: projection,
|
||||
state: options.state,
|
||||
tileGrid: tileGrid,
|
||||
tileLoadFunction: options.tileLoadFunction
|
||||
? options.tileLoadFunction
|
||||
: defaultLoadFunction,
|
||||
tileUrlFunction: options.tileUrlFunction,
|
||||
url: options.url,
|
||||
urls: options.urls,
|
||||
wrapX: options.wrapX === undefined ? true : options.wrapX,
|
||||
transition: options.transition,
|
||||
zDirection: options.zDirection === undefined ? 1 : options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../format/Feature.js").default|null}
|
||||
*/
|
||||
this.format_ = options.format ? options.format : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {TileCache}
|
||||
*/
|
||||
this.sourceTileCache = new TileCache(this.tileCache.highWaterMark);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.overlaps_ = options.overlaps == undefined ? true : options.overlaps;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {typeof import("../VectorTile.js").default}
|
||||
*/
|
||||
this.tileClass = options.tileClass ? options.tileClass : Tile;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object<string, import("../tilegrid/TileGrid.js").default>}
|
||||
*/
|
||||
this.tileGrids_ = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get features whose bounding box intersects the provided extent. Only features for cached
|
||||
* tiles for the last rendered zoom level are available in the source. So this method is only
|
||||
* suitable for requesting tiles for extents that are currently rendered.
|
||||
*
|
||||
* Features are returned in random tile order and as they are included in the tiles. This means
|
||||
* they can be clipped, duplicated across tiles, and simplified to the render resolution.
|
||||
*
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @return {Array<import("../Feature.js").FeatureLike>} Features.
|
||||
* @api
|
||||
*/
|
||||
getFeaturesInExtent(extent) {
|
||||
const features = [];
|
||||
const tileCache = this.tileCache;
|
||||
if (tileCache.getCount() === 0) {
|
||||
return features;
|
||||
}
|
||||
const z = fromKey(tileCache.peekFirstKey())[0];
|
||||
const tileGrid = this.tileGrid;
|
||||
tileCache.forEach(function (tile) {
|
||||
if (tile.tileCoord[0] !== z || tile.getState() !== TileState.LOADED) {
|
||||
return;
|
||||
}
|
||||
const sourceTiles = tile.getSourceTiles();
|
||||
for (let i = 0, ii = sourceTiles.length; i < ii; ++i) {
|
||||
const sourceTile = sourceTiles[i];
|
||||
const tileCoord = sourceTile.tileCoord;
|
||||
if (intersects(extent, tileGrid.getTileCoordExtent(tileCoord))) {
|
||||
const tileFeatures = sourceTile.getFeatures();
|
||||
if (tileFeatures) {
|
||||
for (let j = 0, jj = tileFeatures.length; j < jj; ++j) {
|
||||
const candidate = tileFeatures[j];
|
||||
const geometry = candidate.getGeometry();
|
||||
if (intersects(extent, geometry.getExtent())) {
|
||||
features.push(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} The source can have overlapping geometries.
|
||||
*/
|
||||
getOverlaps() {
|
||||
return this.overlaps_;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear {@link module:ol/TileCache~TileCache} and delete all source tiles
|
||||
* @api
|
||||
*/
|
||||
clear() {
|
||||
this.tileCache.clear();
|
||||
this.sourceTileCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @param {!Object<string, boolean>} usedTiles Used tiles.
|
||||
*/
|
||||
expireCache(projection, usedTiles) {
|
||||
const tileCache = this.getTileCacheForProjection(projection);
|
||||
const usedSourceTiles = Object.keys(usedTiles).reduce((acc, key) => {
|
||||
const cacheKey = getCacheKeyForTileKey(key);
|
||||
const tile = tileCache.peek(cacheKey);
|
||||
if (tile) {
|
||||
const sourceTiles = tile.sourceTiles;
|
||||
for (let i = 0, ii = sourceTiles.length; i < ii; ++i) {
|
||||
acc[sourceTiles[i].getKey()] = true;
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
super.expireCache(projection, usedTiles);
|
||||
this.sourceTileCache.expireCache(usedSourceTiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection").default} projection Projection.
|
||||
* @param {VectorRenderTile} tile Vector image tile.
|
||||
* @return {Array<import("../VectorTile").default>} Tile keys.
|
||||
*/
|
||||
getSourceTiles(pixelRatio, projection, tile) {
|
||||
if (tile.getState() === TileState.IDLE) {
|
||||
tile.setState(TileState.LOADING);
|
||||
const urlTileCoord = tile.wrappedTileCoord;
|
||||
const tileGrid = this.getTileGridForProjection(projection);
|
||||
const extent = tileGrid.getTileCoordExtent(urlTileCoord);
|
||||
const z = urlTileCoord[0];
|
||||
const resolution = tileGrid.getResolution(z);
|
||||
// make extent 1 pixel smaller so we don't load tiles for < 0.5 pixel render space
|
||||
bufferExtent(extent, -resolution, extent);
|
||||
const sourceTileGrid = this.tileGrid;
|
||||
const sourceExtent = sourceTileGrid.getExtent();
|
||||
if (sourceExtent) {
|
||||
getIntersection(extent, sourceExtent, extent);
|
||||
}
|
||||
const sourceZ = sourceTileGrid.getZForResolution(
|
||||
resolution,
|
||||
this.zDirection
|
||||
);
|
||||
|
||||
sourceTileGrid.forEachTileCoord(extent, sourceZ, (sourceTileCoord) => {
|
||||
const tileUrl = this.tileUrlFunction(
|
||||
sourceTileCoord,
|
||||
pixelRatio,
|
||||
projection
|
||||
);
|
||||
const sourceTile = this.sourceTileCache.containsKey(tileUrl)
|
||||
? this.sourceTileCache.get(tileUrl)
|
||||
: new this.tileClass(
|
||||
sourceTileCoord,
|
||||
tileUrl ? TileState.IDLE : TileState.EMPTY,
|
||||
tileUrl,
|
||||
this.format_,
|
||||
this.tileLoadFunction
|
||||
);
|
||||
tile.sourceTiles.push(sourceTile);
|
||||
const sourceTileState = sourceTile.getState();
|
||||
if (sourceTileState < TileState.LOADED) {
|
||||
const listenChange = (event) => {
|
||||
this.handleTileChange(event);
|
||||
const state = sourceTile.getState();
|
||||
if (state === TileState.LOADED || state === TileState.ERROR) {
|
||||
const sourceTileKey = sourceTile.getKey();
|
||||
if (sourceTileKey in tile.errorTileKeys) {
|
||||
if (sourceTile.getState() === TileState.LOADED) {
|
||||
delete tile.errorTileKeys[sourceTileKey];
|
||||
}
|
||||
} else {
|
||||
tile.loadingSourceTiles--;
|
||||
}
|
||||
if (state === TileState.ERROR) {
|
||||
tile.errorTileKeys[sourceTileKey] = true;
|
||||
} else {
|
||||
sourceTile.removeEventListener(EventType.CHANGE, listenChange);
|
||||
}
|
||||
if (tile.loadingSourceTiles === 0) {
|
||||
tile.setState(
|
||||
isEmpty(tile.errorTileKeys)
|
||||
? TileState.LOADED
|
||||
: TileState.ERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
sourceTile.addEventListener(EventType.CHANGE, listenChange);
|
||||
tile.loadingSourceTiles++;
|
||||
}
|
||||
if (sourceTileState === TileState.IDLE) {
|
||||
sourceTile.extent =
|
||||
sourceTileGrid.getTileCoordExtent(sourceTileCoord);
|
||||
sourceTile.projection = projection;
|
||||
sourceTile.resolution = sourceTileGrid.getResolution(
|
||||
sourceTileCoord[0]
|
||||
);
|
||||
this.sourceTileCache.set(tileUrl, sourceTile);
|
||||
sourceTile.load();
|
||||
}
|
||||
});
|
||||
if (!tile.loadingSourceTiles) {
|
||||
tile.setState(
|
||||
tile.sourceTiles.some(
|
||||
(sourceTile) => sourceTile.getState() === TileState.ERROR
|
||||
)
|
||||
? TileState.ERROR
|
||||
: TileState.LOADED
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return tile.sourceTiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {!VectorRenderTile} Tile.
|
||||
*/
|
||||
getTile(z, x, y, pixelRatio, projection) {
|
||||
const coordKey = getKeyZXY(z, x, y);
|
||||
const key = this.getKey();
|
||||
let tile;
|
||||
if (this.tileCache.containsKey(coordKey)) {
|
||||
tile = this.tileCache.get(coordKey);
|
||||
if (tile.key === key) {
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
const tileCoord = [z, x, y];
|
||||
let urlTileCoord = this.getTileCoordForTileUrlFunction(
|
||||
tileCoord,
|
||||
projection
|
||||
);
|
||||
const sourceExtent = this.getTileGrid().getExtent();
|
||||
const tileGrid = this.getTileGridForProjection(projection);
|
||||
if (urlTileCoord && sourceExtent) {
|
||||
const tileExtent = tileGrid.getTileCoordExtent(urlTileCoord);
|
||||
// make extent 1 pixel smaller so we don't load tiles for < 0.5 pixel render space
|
||||
bufferExtent(tileExtent, -tileGrid.getResolution(z), tileExtent);
|
||||
if (!intersects(sourceExtent, tileExtent)) {
|
||||
urlTileCoord = null;
|
||||
}
|
||||
}
|
||||
let empty = true;
|
||||
if (urlTileCoord !== null) {
|
||||
const sourceTileGrid = this.tileGrid;
|
||||
const resolution = tileGrid.getResolution(z);
|
||||
const sourceZ = sourceTileGrid.getZForResolution(resolution, 1);
|
||||
// make extent 1 pixel smaller so we don't load tiles for < 0.5 pixel render space
|
||||
const extent = tileGrid.getTileCoordExtent(urlTileCoord);
|
||||
bufferExtent(extent, -resolution, extent);
|
||||
sourceTileGrid.forEachTileCoord(
|
||||
extent,
|
||||
sourceZ,
|
||||
function (sourceTileCoord) {
|
||||
empty =
|
||||
empty &&
|
||||
!this.tileUrlFunction(sourceTileCoord, pixelRatio, projection);
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
const newTile = new VectorRenderTile(
|
||||
tileCoord,
|
||||
empty ? TileState.EMPTY : TileState.IDLE,
|
||||
urlTileCoord,
|
||||
this.getSourceTiles.bind(this, pixelRatio, projection)
|
||||
);
|
||||
|
||||
newTile.key = key;
|
||||
if (tile) {
|
||||
newTile.interimTile = tile;
|
||||
newTile.refreshInterimChain();
|
||||
this.tileCache.replace(coordKey, newTile);
|
||||
} else {
|
||||
this.tileCache.set(coordKey, newTile);
|
||||
}
|
||||
return newTile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {!import("../tilegrid/TileGrid.js").default} Tile grid.
|
||||
*/
|
||||
getTileGridForProjection(projection) {
|
||||
const code = projection.getCode();
|
||||
let tileGrid = this.tileGrids_[code];
|
||||
if (!tileGrid) {
|
||||
// A tile grid that matches the tile size of the source tile grid is more
|
||||
// likely to have 1:1 relationships between source tiles and rendered tiles.
|
||||
const sourceTileGrid = this.tileGrid;
|
||||
const resolutions = sourceTileGrid.getResolutions().slice();
|
||||
const origins = resolutions.map(function (resolution, z) {
|
||||
return sourceTileGrid.getOrigin(z);
|
||||
});
|
||||
const tileSizes = resolutions.map(function (resolution, z) {
|
||||
return sourceTileGrid.getTileSize(z);
|
||||
});
|
||||
const length = DEFAULT_MAX_ZOOM + 1;
|
||||
for (let z = resolutions.length; z < length; ++z) {
|
||||
resolutions.push(resolutions[z - 1] / 2);
|
||||
origins.push(origins[z - 1]);
|
||||
tileSizes.push(tileSizes[z - 1]);
|
||||
}
|
||||
tileGrid = new TileGrid({
|
||||
extent: sourceTileGrid.getExtent(),
|
||||
origins: origins,
|
||||
resolutions: resolutions,
|
||||
tileSizes: tileSizes,
|
||||
});
|
||||
this.tileGrids_[code] = tileGrid;
|
||||
}
|
||||
return tileGrid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tile pixel ratio for this source.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @return {number} Tile pixel ratio.
|
||||
*/
|
||||
getTilePixelRatio(pixelRatio) {
|
||||
return pixelRatio;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} z Z.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {import("../size.js").Size} Tile size.
|
||||
*/
|
||||
getTilePixelSize(z, pixelRatio, projection) {
|
||||
const tileGrid = this.getTileGridForProjection(projection);
|
||||
const tileSize = toSize(tileGrid.getTileSize(z), this.tmpSize);
|
||||
return [
|
||||
Math.round(tileSize[0] * pixelRatio),
|
||||
Math.round(tileSize[1] * pixelRatio),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the cache size if needed
|
||||
* @param {number} tileCount Minimum number of tiles needed.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
*/
|
||||
updateCacheSize(tileCount, projection) {
|
||||
super.updateCacheSize(tileCount * 2, projection);
|
||||
this.sourceTileCache.highWaterMark =
|
||||
this.getTileCacheForProjection(projection).highWaterMark;
|
||||
}
|
||||
}
|
||||
|
||||
export default VectorTile;
|
||||
|
||||
/**
|
||||
* Sets the loader for a tile.
|
||||
* @param {import("../VectorTile.js").default} tile Vector tile.
|
||||
* @param {string} url URL.
|
||||
*/
|
||||
export function defaultLoadFunction(tile, url) {
|
||||
tile.setLoader(
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
*/
|
||||
function (extent, resolution, projection) {
|
||||
loadFeaturesXhr(
|
||||
url,
|
||||
tile.getFormat(),
|
||||
extent,
|
||||
resolution,
|
||||
projection,
|
||||
tile.onLoad.bind(tile),
|
||||
tile.onError.bind(tile)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
604
node_modules/ol/src/source/WMTS.js
generated
vendored
Normal file
604
node_modules/ol/src/source/WMTS.js
generated
vendored
Normal file
@@ -0,0 +1,604 @@
|
||||
/**
|
||||
* @module ol/source/WMTS
|
||||
*/
|
||||
|
||||
import TileImage from './TileImage.js';
|
||||
import {appendParams} from '../uri.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {containsExtent} from '../extent.js';
|
||||
import {createFromCapabilitiesMatrixSet} from '../tilegrid/WMTS.js';
|
||||
import {createFromTileUrlFunctions, expandUrl} from '../tileurlfunction.js';
|
||||
import {equivalent, get as getProjection, transformExtent} from '../proj.js';
|
||||
import {find, findIndex, includes} from '../array.js';
|
||||
|
||||
/**
|
||||
* Request encoding. One of 'KVP', 'REST'.
|
||||
* @typedef {'KVP' | 'REST'} RequestEncoding
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {import("../tilegrid/WMTS.js").default} tileGrid Tile grid.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {RequestEncoding} [requestEncoding='KVP'] Request encoding.
|
||||
* @property {string} layer Layer name as advertised in the WMTS capabilities.
|
||||
* @property {string} style Style name as advertised in the WMTS capabilities.
|
||||
* @property {typeof import("../ImageTile.js").default} [tileClass] Class used to instantiate image tiles. Default is {@link module:ol/ImageTile~ImageTile}.
|
||||
* @property {number} [tilePixelRatio=1] The pixel ratio used by the tile service.
|
||||
* For example, if the tile service advertizes 256px by 256px tiles but actually sends 512px
|
||||
* by 512px images (for retina/hidpi devices) then `tilePixelRatio`
|
||||
* should be set to `2`.
|
||||
* @property {string} [format='image/jpeg'] Image format. Only used when `requestEncoding` is `'KVP'`.
|
||||
* @property {string} [version='1.0.0'] WMTS version.
|
||||
* @property {string} matrixSet Matrix set.
|
||||
* @property {!Object} [dimensions] Additional "dimensions" for tile requests.
|
||||
* This is an object with properties named like the advertised WMTS dimensions.
|
||||
* @property {string} [url] A URL for the service.
|
||||
* For the RESTful request encoding, this is a URL
|
||||
* template. For KVP encoding, it is normal URL. A `{?-?}` template pattern,
|
||||
* for example `subdomain{a-f}.domain.com`, may be used instead of defining
|
||||
* each one separately in the `urls` option.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is
|
||||
* ```js
|
||||
* function(imageTile, src) {
|
||||
* imageTile.getImage().src = src;
|
||||
* };
|
||||
* ```
|
||||
* @property {Array<string>} [urls] An array of URLs.
|
||||
* Requests will be distributed among the URLs in this array.
|
||||
* @property {boolean} [wrapX=false] Whether to wrap the world horizontally.
|
||||
* @property {number} [transition] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for tile data from WMTS servers.
|
||||
* @api
|
||||
*/
|
||||
class WMTS extends TileImage {
|
||||
/**
|
||||
* @param {Options} options WMTS options.
|
||||
*/
|
||||
constructor(options) {
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
// TODO: add support for TileMatrixLimits
|
||||
|
||||
const requestEncoding =
|
||||
options.requestEncoding !== undefined ? options.requestEncoding : 'KVP';
|
||||
|
||||
// FIXME: should we create a default tileGrid?
|
||||
// we could issue a getCapabilities xhr to retrieve missing configuration
|
||||
const tileGrid = options.tileGrid;
|
||||
|
||||
let urls = options.urls;
|
||||
if (urls === undefined && options.url !== undefined) {
|
||||
urls = expandUrl(options.url);
|
||||
}
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
attributionsCollapsible: options.attributionsCollapsible,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: options.crossOrigin,
|
||||
interpolate: interpolate,
|
||||
projection: options.projection,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
tileClass: options.tileClass,
|
||||
tileGrid: tileGrid,
|
||||
tileLoadFunction: options.tileLoadFunction,
|
||||
tilePixelRatio: options.tilePixelRatio,
|
||||
urls: urls,
|
||||
wrapX: options.wrapX !== undefined ? options.wrapX : false,
|
||||
transition: options.transition,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.version_ = options.version !== undefined ? options.version : '1.0.0';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.format_ = options.format !== undefined ? options.format : 'image/jpeg';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object}
|
||||
*/
|
||||
this.dimensions_ =
|
||||
options.dimensions !== undefined ? options.dimensions : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.layer_ = options.layer;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.matrixSet_ = options.matrixSet;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.style_ = options.style;
|
||||
|
||||
// FIXME: should we guess this requestEncoding from options.url(s)
|
||||
// structure? that would mean KVP only if a template is not provided.
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {RequestEncoding}
|
||||
*/
|
||||
this.requestEncoding_ = requestEncoding;
|
||||
|
||||
this.setKey(this.getKeyForDimensions_());
|
||||
|
||||
if (urls && urls.length > 0) {
|
||||
this.tileUrlFunction = createFromTileUrlFunctions(
|
||||
urls.map(this.createFromWMTSTemplate.bind(this))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URLs to use for requests.
|
||||
* URLs may contain OGC conform URL Template Variables: {TileMatrix}, {TileRow}, {TileCol}.
|
||||
* @param {Array<string>} urls URLs.
|
||||
*/
|
||||
setUrls(urls) {
|
||||
this.urls = urls;
|
||||
const key = urls.join('\n');
|
||||
this.setTileUrlFunction(
|
||||
createFromTileUrlFunctions(
|
||||
urls.map(this.createFromWMTSTemplate.bind(this))
|
||||
),
|
||||
key
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dimensions, i.e. those passed to the constructor through the
|
||||
* "dimensions" option, and possibly updated using the updateDimensions
|
||||
* method.
|
||||
* @return {!Object} Dimensions.
|
||||
* @api
|
||||
*/
|
||||
getDimensions() {
|
||||
return this.dimensions_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image format of the WMTS source.
|
||||
* @return {string} Format.
|
||||
* @api
|
||||
*/
|
||||
getFormat() {
|
||||
return this.format_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the layer of the WMTS source.
|
||||
* @return {string} Layer.
|
||||
* @api
|
||||
*/
|
||||
getLayer() {
|
||||
return this.layer_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the matrix set of the WMTS source.
|
||||
* @return {string} MatrixSet.
|
||||
* @api
|
||||
*/
|
||||
getMatrixSet() {
|
||||
return this.matrixSet_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the request encoding, either "KVP" or "REST".
|
||||
* @return {RequestEncoding} Request encoding.
|
||||
* @api
|
||||
*/
|
||||
getRequestEncoding() {
|
||||
return this.requestEncoding_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the style of the WMTS source.
|
||||
* @return {string} Style.
|
||||
* @api
|
||||
*/
|
||||
getStyle() {
|
||||
return this.style_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the version of the WMTS source.
|
||||
* @return {string} Version.
|
||||
* @api
|
||||
*/
|
||||
getVersion() {
|
||||
return this.version_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {string} The key for the current dimensions.
|
||||
*/
|
||||
getKeyForDimensions_() {
|
||||
let i = 0;
|
||||
const res = [];
|
||||
for (const key in this.dimensions_) {
|
||||
res[i++] = key + '-' + this.dimensions_[key];
|
||||
}
|
||||
return res.join('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the dimensions.
|
||||
* @param {Object} dimensions Dimensions.
|
||||
* @api
|
||||
*/
|
||||
updateDimensions(dimensions) {
|
||||
assign(this.dimensions_, dimensions);
|
||||
this.setKey(this.getKeyForDimensions_());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} template Template.
|
||||
* @return {import("../Tile.js").UrlFunction} Tile URL function.
|
||||
*/
|
||||
createFromWMTSTemplate(template) {
|
||||
const requestEncoding = this.requestEncoding_;
|
||||
|
||||
// context property names are lower case to allow for a case insensitive
|
||||
// replacement as some services use different naming conventions
|
||||
const context = {
|
||||
'layer': this.layer_,
|
||||
'style': this.style_,
|
||||
'tilematrixset': this.matrixSet_,
|
||||
};
|
||||
|
||||
if (requestEncoding == 'KVP') {
|
||||
assign(context, {
|
||||
'Service': 'WMTS',
|
||||
'Request': 'GetTile',
|
||||
'Version': this.version_,
|
||||
'Format': this.format_,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: we may want to create our own appendParams function so that params
|
||||
// order conforms to wmts spec guidance, and so that we can avoid to escape
|
||||
// special template params
|
||||
|
||||
template =
|
||||
requestEncoding == 'KVP'
|
||||
? appendParams(template, context)
|
||||
: template.replace(/\{(\w+?)\}/g, function (m, p) {
|
||||
return p.toLowerCase() in context ? context[p.toLowerCase()] : m;
|
||||
});
|
||||
|
||||
const tileGrid = /** @type {import("../tilegrid/WMTS.js").default} */ (
|
||||
this.tileGrid
|
||||
);
|
||||
const dimensions = this.dimensions_;
|
||||
|
||||
return (
|
||||
/**
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {string|undefined} Tile URL.
|
||||
*/
|
||||
function (tileCoord, pixelRatio, projection) {
|
||||
if (!tileCoord) {
|
||||
return undefined;
|
||||
} else {
|
||||
const localContext = {
|
||||
'TileMatrix': tileGrid.getMatrixId(tileCoord[0]),
|
||||
'TileCol': tileCoord[1],
|
||||
'TileRow': tileCoord[2],
|
||||
};
|
||||
assign(localContext, dimensions);
|
||||
let url = template;
|
||||
if (requestEncoding == 'KVP') {
|
||||
url = appendParams(url, localContext);
|
||||
} else {
|
||||
url = url.replace(/\{(\w+?)\}/g, function (m, p) {
|
||||
return localContext[p];
|
||||
});
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default WMTS;
|
||||
|
||||
/**
|
||||
* Generate source options from a capabilities object.
|
||||
* @param {Object} wmtsCap An object representing the capabilities document.
|
||||
* @param {!Object} config Configuration properties for the layer. Defaults for
|
||||
* the layer will apply if not provided.
|
||||
*
|
||||
* Required config properties:
|
||||
* - layer - {string} The layer identifier.
|
||||
*
|
||||
* Optional config properties:
|
||||
* - matrixSet - {string} The matrix set identifier, required if there is
|
||||
* more than one matrix set in the layer capabilities.
|
||||
* - projection - {string} The desired CRS when no matrixSet is specified.
|
||||
* eg: "EPSG:3857". If the desired projection is not available,
|
||||
* an error is thrown.
|
||||
* - requestEncoding - {string} url encoding format for the layer. Default is
|
||||
* the first tile url format found in the GetCapabilities response.
|
||||
* - style - {string} The name of the style
|
||||
* - format - {string} Image format for the layer. Default is the first
|
||||
* format returned in the GetCapabilities response.
|
||||
* - crossOrigin - {string|null|undefined} Cross origin. Default is `undefined`.
|
||||
* @return {Options|null} WMTS source options object or `null` if the layer was not found.
|
||||
* @api
|
||||
*/
|
||||
export function optionsFromCapabilities(wmtsCap, config) {
|
||||
const layers = wmtsCap['Contents']['Layer'];
|
||||
const l = find(layers, function (elt, index, array) {
|
||||
return elt['Identifier'] == config['layer'];
|
||||
});
|
||||
if (l === null) {
|
||||
return null;
|
||||
}
|
||||
const tileMatrixSets = wmtsCap['Contents']['TileMatrixSet'];
|
||||
let idx;
|
||||
if (l['TileMatrixSetLink'].length > 1) {
|
||||
if ('projection' in config) {
|
||||
idx = findIndex(l['TileMatrixSetLink'], function (elt, index, array) {
|
||||
const tileMatrixSet = find(tileMatrixSets, function (el) {
|
||||
return el['Identifier'] == elt['TileMatrixSet'];
|
||||
});
|
||||
const supportedCRS = tileMatrixSet['SupportedCRS'];
|
||||
const proj1 = getProjection(supportedCRS);
|
||||
const proj2 = getProjection(config['projection']);
|
||||
if (proj1 && proj2) {
|
||||
return equivalent(proj1, proj2);
|
||||
} else {
|
||||
return supportedCRS == config['projection'];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
idx = findIndex(l['TileMatrixSetLink'], function (elt, index, array) {
|
||||
return elt['TileMatrixSet'] == config['matrixSet'];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
idx = 0;
|
||||
}
|
||||
if (idx < 0) {
|
||||
idx = 0;
|
||||
}
|
||||
const matrixSet =
|
||||
/** @type {string} */
|
||||
(l['TileMatrixSetLink'][idx]['TileMatrixSet']);
|
||||
const matrixLimits =
|
||||
/** @type {Array<Object>} */
|
||||
(l['TileMatrixSetLink'][idx]['TileMatrixSetLimits']);
|
||||
|
||||
let format = /** @type {string} */ (l['Format'][0]);
|
||||
if ('format' in config) {
|
||||
format = config['format'];
|
||||
}
|
||||
idx = findIndex(l['Style'], function (elt, index, array) {
|
||||
if ('style' in config) {
|
||||
return elt['Title'] == config['style'];
|
||||
} else {
|
||||
return elt['isDefault'];
|
||||
}
|
||||
});
|
||||
if (idx < 0) {
|
||||
idx = 0;
|
||||
}
|
||||
const style = /** @type {string} */ (l['Style'][idx]['Identifier']);
|
||||
|
||||
const dimensions = {};
|
||||
if ('Dimension' in l) {
|
||||
l['Dimension'].forEach(function (elt, index, array) {
|
||||
const key = elt['Identifier'];
|
||||
let value = elt['Default'];
|
||||
if (value === undefined) {
|
||||
value = elt['Value'][0];
|
||||
}
|
||||
dimensions[key] = value;
|
||||
});
|
||||
}
|
||||
|
||||
const matrixSets = wmtsCap['Contents']['TileMatrixSet'];
|
||||
const matrixSetObj = find(matrixSets, function (elt, index, array) {
|
||||
return elt['Identifier'] == matrixSet;
|
||||
});
|
||||
|
||||
let projection;
|
||||
const code = matrixSetObj['SupportedCRS'];
|
||||
if (code) {
|
||||
projection = getProjection(code);
|
||||
}
|
||||
if ('projection' in config) {
|
||||
const projConfig = getProjection(config['projection']);
|
||||
if (projConfig) {
|
||||
if (!projection || equivalent(projConfig, projection)) {
|
||||
projection = projConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let wrapX = false;
|
||||
const switchXY = projection.getAxisOrientation().substr(0, 2) == 'ne';
|
||||
|
||||
let matrix = matrixSetObj.TileMatrix[0];
|
||||
|
||||
// create default matrixLimit
|
||||
let selectedMatrixLimit = {
|
||||
MinTileCol: 0,
|
||||
MinTileRow: 0,
|
||||
// subtract one to end up at tile top left
|
||||
MaxTileCol: matrix.MatrixWidth - 1,
|
||||
MaxTileRow: matrix.MatrixHeight - 1,
|
||||
};
|
||||
|
||||
//in case of matrix limits, use matrix limits to calculate extent
|
||||
if (matrixLimits) {
|
||||
selectedMatrixLimit = matrixLimits[matrixLimits.length - 1];
|
||||
const m = find(
|
||||
matrixSetObj.TileMatrix,
|
||||
(tileMatrixValue) =>
|
||||
tileMatrixValue.Identifier === selectedMatrixLimit.TileMatrix ||
|
||||
matrixSetObj.Identifier + ':' + tileMatrixValue.Identifier ===
|
||||
selectedMatrixLimit.TileMatrix
|
||||
);
|
||||
if (m) {
|
||||
matrix = m;
|
||||
}
|
||||
}
|
||||
|
||||
const resolution =
|
||||
(matrix.ScaleDenominator * 0.00028) / projection.getMetersPerUnit(); // WMTS 1.0.0: standardized rendering pixel size
|
||||
const origin = switchXY
|
||||
? [matrix.TopLeftCorner[1], matrix.TopLeftCorner[0]]
|
||||
: matrix.TopLeftCorner;
|
||||
const tileSpanX = matrix.TileWidth * resolution;
|
||||
const tileSpanY = matrix.TileHeight * resolution;
|
||||
let matrixSetExtent = matrixSetObj['BoundingBox'];
|
||||
if (matrixSetExtent && switchXY) {
|
||||
matrixSetExtent = [
|
||||
matrixSetExtent[1],
|
||||
matrixSetExtent[0],
|
||||
matrixSetExtent[3],
|
||||
matrixSetExtent[2],
|
||||
];
|
||||
}
|
||||
let extent = [
|
||||
origin[0] + tileSpanX * selectedMatrixLimit.MinTileCol,
|
||||
// add one to get proper bottom/right coordinate
|
||||
origin[1] - tileSpanY * (1 + selectedMatrixLimit.MaxTileRow),
|
||||
origin[0] + tileSpanX * (1 + selectedMatrixLimit.MaxTileCol),
|
||||
origin[1] - tileSpanY * selectedMatrixLimit.MinTileRow,
|
||||
];
|
||||
|
||||
if (
|
||||
matrixSetExtent !== undefined &&
|
||||
!containsExtent(matrixSetExtent, extent)
|
||||
) {
|
||||
const wgs84BoundingBox = l['WGS84BoundingBox'];
|
||||
const wgs84ProjectionExtent = getProjection('EPSG:4326').getExtent();
|
||||
extent = matrixSetExtent;
|
||||
if (wgs84BoundingBox) {
|
||||
wrapX =
|
||||
wgs84BoundingBox[0] === wgs84ProjectionExtent[0] &&
|
||||
wgs84BoundingBox[2] === wgs84ProjectionExtent[2];
|
||||
} else {
|
||||
const wgs84MatrixSetExtent = transformExtent(
|
||||
matrixSetExtent,
|
||||
matrixSetObj['SupportedCRS'],
|
||||
'EPSG:4326'
|
||||
);
|
||||
// Ignore slight deviation from the correct x limits
|
||||
wrapX =
|
||||
wgs84MatrixSetExtent[0] - 1e-10 <= wgs84ProjectionExtent[0] &&
|
||||
wgs84MatrixSetExtent[2] + 1e-10 >= wgs84ProjectionExtent[2];
|
||||
}
|
||||
}
|
||||
|
||||
const tileGrid = createFromCapabilitiesMatrixSet(
|
||||
matrixSetObj,
|
||||
extent,
|
||||
matrixLimits
|
||||
);
|
||||
|
||||
/** @type {!Array<string>} */
|
||||
const urls = [];
|
||||
let requestEncoding = config['requestEncoding'];
|
||||
requestEncoding = requestEncoding !== undefined ? requestEncoding : '';
|
||||
|
||||
if (
|
||||
'OperationsMetadata' in wmtsCap &&
|
||||
'GetTile' in wmtsCap['OperationsMetadata']
|
||||
) {
|
||||
const gets = wmtsCap['OperationsMetadata']['GetTile']['DCP']['HTTP']['Get'];
|
||||
|
||||
for (let i = 0, ii = gets.length; i < ii; ++i) {
|
||||
if (gets[i]['Constraint']) {
|
||||
const constraint = find(gets[i]['Constraint'], function (element) {
|
||||
return element['name'] == 'GetEncoding';
|
||||
});
|
||||
const encodings = constraint['AllowedValues']['Value'];
|
||||
|
||||
if (requestEncoding === '') {
|
||||
// requestEncoding not provided, use the first encoding from the list
|
||||
requestEncoding = encodings[0];
|
||||
}
|
||||
if (requestEncoding === 'KVP') {
|
||||
if (includes(encodings, 'KVP')) {
|
||||
urls.push(/** @type {string} */ (gets[i]['href']));
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (gets[i]['href']) {
|
||||
requestEncoding = 'KVP';
|
||||
urls.push(/** @type {string} */ (gets[i]['href']));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (urls.length === 0) {
|
||||
requestEncoding = 'REST';
|
||||
l['ResourceURL'].forEach(function (element) {
|
||||
if (element['resourceType'] === 'tile') {
|
||||
format = element['format'];
|
||||
urls.push(/** @type {string} */ (element['template']));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
urls: urls,
|
||||
layer: config['layer'],
|
||||
matrixSet: matrixSet,
|
||||
format: format,
|
||||
projection: projection,
|
||||
requestEncoding: requestEncoding,
|
||||
tileGrid: tileGrid,
|
||||
style: style,
|
||||
dimensions: dimensions,
|
||||
wrapX: wrapX,
|
||||
crossOrigin: config['crossOrigin'],
|
||||
};
|
||||
}
|
||||
136
node_modules/ol/src/source/XYZ.js
generated
vendored
Normal file
136
node_modules/ol/src/source/XYZ.js
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @module ol/source/XYZ
|
||||
*/
|
||||
|
||||
import TileImage from './TileImage.js';
|
||||
import {createXYZ, extentFromProjection} from '../tilegrid.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {boolean} [opaque=false] Whether the layer is opaque.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Projection.
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {number} [maxZoom=42] Optional max zoom level. Not used if `tileGrid` is provided.
|
||||
* @property {number} [minZoom=0] Optional min zoom level. Not used if `tileGrid` is provided.
|
||||
* @property {number} [maxResolution] Optional tile grid resolution at level zero. Not used if `tileGrid` is provided.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is
|
||||
* ```js
|
||||
* function(imageTile, src) {
|
||||
* imageTile.getImage().src = src;
|
||||
* };
|
||||
* ```
|
||||
* @property {number} [tilePixelRatio=1] The pixel ratio used by the tile service.
|
||||
* For example, if the tile service advertizes 256px by 256px tiles but actually sends 512px
|
||||
* by 512px images (for retina/hidpi devices) then `tilePixelRatio`
|
||||
* should be set to `2`.
|
||||
* @property {number|import("../size.js").Size} [tileSize=[256, 256]] The tile size used by the tile service.
|
||||
* Not used if `tileGrid` is provided.
|
||||
* @property {number} [gutter=0] The size in pixels of the gutter around image tiles to ignore.
|
||||
* This allows artifacts of rendering at tile edges to be ignored.
|
||||
* Supported images should be wider and taller than the tile size by a value of `2 x gutter`.
|
||||
* @property {import("../Tile.js").UrlFunction} [tileUrlFunction] Optional function to get
|
||||
* tile URL given a tile coordinate and the projection.
|
||||
* Required if `url` or `urls` are not provided.
|
||||
* @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`,
|
||||
* and `{z}` placeholders. A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`,
|
||||
* may be used instead of defining each one separately in the `urls` option.
|
||||
* @property {Array<string>} [urls] An array of URL templates.
|
||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||
* @property {number} [transition=250] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for tile data with URLs in a set XYZ format that are
|
||||
* defined in a URL template. By default, this follows the widely-used
|
||||
* Google grid where `x` 0 and `y` 0 are in the top left. Grids like
|
||||
* TMS where `x` 0 and `y` 0 are in the bottom left can be used by
|
||||
* using the `{-y}` placeholder in the URL template, so long as the
|
||||
* source does not have a custom tile grid. In this case
|
||||
* a `tileUrlFunction` can be used, such as:
|
||||
* ```js
|
||||
* tileUrlFunction: function(coordinate) {
|
||||
* return 'http://mapserver.com/' + coordinate[0] + '/' +
|
||||
* coordinate[1] + '/' + (-coordinate[2] - 1) + '.png';
|
||||
* }
|
||||
* ```
|
||||
* @api
|
||||
*/
|
||||
class XYZ extends TileImage {
|
||||
/**
|
||||
* @param {Options} [opt_options] XYZ options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
const options = opt_options || {};
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
const projection =
|
||||
options.projection !== undefined ? options.projection : 'EPSG:3857';
|
||||
|
||||
const tileGrid =
|
||||
options.tileGrid !== undefined
|
||||
? options.tileGrid
|
||||
: createXYZ({
|
||||
extent: extentFromProjection(projection),
|
||||
maxResolution: options.maxResolution,
|
||||
maxZoom: options.maxZoom,
|
||||
minZoom: options.minZoom,
|
||||
tileSize: options.tileSize,
|
||||
});
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: options.crossOrigin,
|
||||
interpolate: interpolate,
|
||||
opaque: options.opaque,
|
||||
projection: projection,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
tileGrid: tileGrid,
|
||||
tileLoadFunction: options.tileLoadFunction,
|
||||
tilePixelRatio: options.tilePixelRatio,
|
||||
tileUrlFunction: options.tileUrlFunction,
|
||||
url: options.url,
|
||||
urls: options.urls,
|
||||
wrapX: options.wrapX !== undefined ? options.wrapX : true,
|
||||
transition: options.transition,
|
||||
attributionsCollapsible: options.attributionsCollapsible,
|
||||
zDirection: options.zDirection,
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.gutter_ = options.gutter !== undefined ? options.gutter : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number} Gutter.
|
||||
*/
|
||||
getGutter() {
|
||||
return this.gutter_;
|
||||
}
|
||||
}
|
||||
|
||||
export default XYZ;
|
||||
307
node_modules/ol/src/source/Zoomify.js
generated
vendored
Normal file
307
node_modules/ol/src/source/Zoomify.js
generated
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
/**
|
||||
* @module ol/source/Zoomify
|
||||
*/
|
||||
import {DEFAULT_TILE_SIZE} from '../tilegrid/common.js';
|
||||
|
||||
import ImageTile from '../ImageTile.js';
|
||||
import TileGrid from '../tilegrid/TileGrid.js';
|
||||
import TileImage from './TileImage.js';
|
||||
import TileState from '../TileState.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {createCanvasContext2D} from '../dom.js';
|
||||
import {createFromTileUrlFunctions, expandUrl} from '../tileurlfunction.js';
|
||||
import {getCenter} from '../extent.js';
|
||||
import {toSize} from '../size.js';
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
const TierSizeCalculation = {
|
||||
DEFAULT: 'default',
|
||||
TRUNCATED: 'truncated',
|
||||
};
|
||||
|
||||
export class CustomTile extends ImageTile {
|
||||
/**
|
||||
* @param {import("../size.js").Size} tileSize Full tile size.
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {import("../TileState.js").default} state State.
|
||||
* @param {string} src Image source URI.
|
||||
* @param {?string} crossOrigin Cross origin.
|
||||
* @param {import("../Tile.js").LoadFunction} tileLoadFunction Tile load function.
|
||||
* @param {import("../Tile.js").Options} [opt_options] Tile options.
|
||||
*/
|
||||
constructor(
|
||||
tileSize,
|
||||
tileCoord,
|
||||
state,
|
||||
src,
|
||||
crossOrigin,
|
||||
tileLoadFunction,
|
||||
opt_options
|
||||
) {
|
||||
super(tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement}
|
||||
*/
|
||||
this.zoomifyImage_ = null;
|
||||
|
||||
/**
|
||||
* @type {import("../size.js").Size}
|
||||
*/
|
||||
this.tileSize_ = tileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the image element for this tile.
|
||||
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
|
||||
*/
|
||||
getImage() {
|
||||
if (this.zoomifyImage_) {
|
||||
return this.zoomifyImage_;
|
||||
}
|
||||
const image = super.getImage();
|
||||
if (this.state == TileState.LOADED) {
|
||||
const tileSize = this.tileSize_;
|
||||
if (image.width == tileSize[0] && image.height == tileSize[1]) {
|
||||
this.zoomifyImage_ = image;
|
||||
return image;
|
||||
} else {
|
||||
const context = createCanvasContext2D(tileSize[0], tileSize[1]);
|
||||
context.drawImage(image, 0, 0);
|
||||
this.zoomifyImage_ = context.canvas;
|
||||
return context.canvas;
|
||||
}
|
||||
} else {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||
* @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport.
|
||||
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
|
||||
* you must provide a `crossOrigin` value you want to access pixel data with the Canvas renderer.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
|
||||
* @property {boolean} [imageSmoothing=true] Deprecated. Use the `interpolate` option instead.
|
||||
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||
* linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection.
|
||||
* @property {number} [tilePixelRatio] The pixel ratio used by the tile service. For example, if the tile service advertizes 256px by 256px tiles but actually sends 512px by 512px images (for retina/hidpi devices) then `tilePixelRatio` should be set to `2`
|
||||
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {string} url URL template or base URL of the Zoomify service.
|
||||
* A base URL is the fixed part
|
||||
* of the URL, excluding the tile group, z, x, and y folder structure, e.g.
|
||||
* `http://my.zoomify.info/IMAGE.TIF/`. A URL template must include
|
||||
* `{TileGroup}`, `{x}`, `{y}`, and `{z}` placeholders, e.g.
|
||||
* `http://my.zoomify.info/IMAGE.TIF/{TileGroup}/{z}-{x}-{y}.jpg`.
|
||||
* Internet Imaging Protocol (IIP) with JTL extension can be also used with
|
||||
* `{tileIndex}` and `{z}` placeholders, e.g.
|
||||
* `http://my.zoomify.info?FIF=IMAGE.TIF&JTL={z},{tileIndex}`.
|
||||
* A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be
|
||||
* used instead of defining each one separately in the `urls` option.
|
||||
* @property {string} [tierSizeCalculation] Tier size calculation method: `default` or `truncated`.
|
||||
* @property {import("../size.js").Size} size Size.
|
||||
* @property {import("../extent.js").Extent} [extent] Extent for the TileGrid that is created.
|
||||
* Default sets the TileGrid in the
|
||||
* fourth quadrant, meaning extent is `[0, -height, width, 0]`. To change the
|
||||
* extent to the first quadrant (the default for OpenLayers 2) set the extent
|
||||
* as `[0, 0, width, height]`.
|
||||
* @property {number} [transition] Duration of the opacity transition for rendering.
|
||||
* To disable the opacity transition, pass `transition: 0`.
|
||||
* @property {number} [tileSize=256] Tile size. Same tile size is used for all zoom levels.
|
||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
|
||||
* Choose whether to use tiles with a higher or lower zoom level when between integer
|
||||
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer source for tile data in Zoomify format (both Zoomify and Internet
|
||||
* Imaging Protocol are supported).
|
||||
* @api
|
||||
*/
|
||||
class Zoomify extends TileImage {
|
||||
/**
|
||||
* @param {Options} opt_options Options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
const options = opt_options;
|
||||
|
||||
let interpolate =
|
||||
options.imageSmoothing !== undefined ? options.imageSmoothing : true;
|
||||
if (options.interpolate !== undefined) {
|
||||
interpolate = options.interpolate;
|
||||
}
|
||||
|
||||
const size = options.size;
|
||||
const tierSizeCalculation =
|
||||
options.tierSizeCalculation !== undefined
|
||||
? options.tierSizeCalculation
|
||||
: TierSizeCalculation.DEFAULT;
|
||||
|
||||
const tilePixelRatio = options.tilePixelRatio || 1;
|
||||
const imageWidth = size[0];
|
||||
const imageHeight = size[1];
|
||||
const tierSizeInTiles = [];
|
||||
const tileSize = options.tileSize || DEFAULT_TILE_SIZE;
|
||||
let tileSizeForTierSizeCalculation = tileSize * tilePixelRatio;
|
||||
|
||||
switch (tierSizeCalculation) {
|
||||
case TierSizeCalculation.DEFAULT:
|
||||
while (
|
||||
imageWidth > tileSizeForTierSizeCalculation ||
|
||||
imageHeight > tileSizeForTierSizeCalculation
|
||||
) {
|
||||
tierSizeInTiles.push([
|
||||
Math.ceil(imageWidth / tileSizeForTierSizeCalculation),
|
||||
Math.ceil(imageHeight / tileSizeForTierSizeCalculation),
|
||||
]);
|
||||
tileSizeForTierSizeCalculation += tileSizeForTierSizeCalculation;
|
||||
}
|
||||
break;
|
||||
case TierSizeCalculation.TRUNCATED:
|
||||
let width = imageWidth;
|
||||
let height = imageHeight;
|
||||
while (
|
||||
width > tileSizeForTierSizeCalculation ||
|
||||
height > tileSizeForTierSizeCalculation
|
||||
) {
|
||||
tierSizeInTiles.push([
|
||||
Math.ceil(width / tileSizeForTierSizeCalculation),
|
||||
Math.ceil(height / tileSizeForTierSizeCalculation),
|
||||
]);
|
||||
width >>= 1;
|
||||
height >>= 1;
|
||||
}
|
||||
break;
|
||||
default: // Unknown `tierSizeCalculation` configured
|
||||
assert(false, 53);
|
||||
break;
|
||||
}
|
||||
|
||||
tierSizeInTiles.push([1, 1]);
|
||||
tierSizeInTiles.reverse();
|
||||
|
||||
const resolutions = [tilePixelRatio];
|
||||
const tileCountUpToTier = [0];
|
||||
for (let i = 1, ii = tierSizeInTiles.length; i < ii; i++) {
|
||||
resolutions.push(tilePixelRatio << i);
|
||||
tileCountUpToTier.push(
|
||||
tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] +
|
||||
tileCountUpToTier[i - 1]
|
||||
);
|
||||
}
|
||||
resolutions.reverse();
|
||||
|
||||
const tileGrid = new TileGrid({
|
||||
tileSize: tileSize,
|
||||
extent: options.extent || [0, -imageHeight, imageWidth, 0],
|
||||
resolutions: resolutions,
|
||||
});
|
||||
|
||||
let url = options.url;
|
||||
if (
|
||||
url &&
|
||||
url.indexOf('{TileGroup}') == -1 &&
|
||||
url.indexOf('{tileIndex}') == -1
|
||||
) {
|
||||
url += '{TileGroup}/{z}-{x}-{y}.jpg';
|
||||
}
|
||||
const urls = expandUrl(url);
|
||||
|
||||
let tileWidth = tileSize * tilePixelRatio;
|
||||
|
||||
/**
|
||||
* @param {string} template Template.
|
||||
* @return {import("../Tile.js").UrlFunction} Tile URL function.
|
||||
*/
|
||||
function createFromTemplate(template) {
|
||||
return (
|
||||
/**
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile Coordinate.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||
* @return {string|undefined} Tile URL.
|
||||
*/
|
||||
function (tileCoord, pixelRatio, projection) {
|
||||
if (!tileCoord) {
|
||||
return undefined;
|
||||
} else {
|
||||
const tileCoordZ = tileCoord[0];
|
||||
const tileCoordX = tileCoord[1];
|
||||
const tileCoordY = tileCoord[2];
|
||||
const tileIndex =
|
||||
tileCoordX + tileCoordY * tierSizeInTiles[tileCoordZ][0];
|
||||
const tileGroup =
|
||||
((tileIndex + tileCountUpToTier[tileCoordZ]) / tileWidth) | 0;
|
||||
const localContext = {
|
||||
'z': tileCoordZ,
|
||||
'x': tileCoordX,
|
||||
'y': tileCoordY,
|
||||
'tileIndex': tileIndex,
|
||||
'TileGroup': 'TileGroup' + tileGroup,
|
||||
};
|
||||
return template.replace(/\{(\w+?)\}/g, function (m, p) {
|
||||
return localContext[p];
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const tileUrlFunction = createFromTileUrlFunctions(
|
||||
urls.map(createFromTemplate)
|
||||
);
|
||||
|
||||
const ZoomifyTileClass = CustomTile.bind(
|
||||
null,
|
||||
toSize(tileSize * tilePixelRatio)
|
||||
);
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: options.crossOrigin,
|
||||
interpolate: interpolate,
|
||||
projection: options.projection,
|
||||
tilePixelRatio: tilePixelRatio,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
tileClass: ZoomifyTileClass,
|
||||
tileGrid: tileGrid,
|
||||
tileUrlFunction: tileUrlFunction,
|
||||
transition: options.transition,
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {number|import("../array.js").NearestDirectionFunction}
|
||||
*/
|
||||
this.zDirection = options.zDirection;
|
||||
|
||||
// Server retina tile detection (non-standard):
|
||||
// Try loading the center tile for the highest resolution. If it is not
|
||||
// available, we are dealing with retina tiles, and need to adjust the
|
||||
// tile url calculation.
|
||||
const tileUrl = tileGrid.getTileCoordForCoordAndResolution(
|
||||
getCenter(tileGrid.getExtent()),
|
||||
resolutions[resolutions.length - 1]
|
||||
);
|
||||
const testTileUrl = tileUrlFunction(tileUrl, 1, null);
|
||||
const image = new Image();
|
||||
image.addEventListener(
|
||||
'error',
|
||||
function () {
|
||||
tileWidth = tileSize;
|
||||
this.changed();
|
||||
}.bind(this)
|
||||
);
|
||||
image.src = testTileUrl;
|
||||
}
|
||||
}
|
||||
|
||||
export default Zoomify;
|
||||
9
node_modules/ol/src/source/common.js
generated
vendored
Normal file
9
node_modules/ol/src/source/common.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @module ol/source/common
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default WMS version.
|
||||
* @type {string}
|
||||
*/
|
||||
export const DEFAULT_WMS_VERSION = '1.3.0';
|
||||
406
node_modules/ol/src/source/ogcTileUtil.js
generated
vendored
Normal file
406
node_modules/ol/src/source/ogcTileUtil.js
generated
vendored
Normal file
@@ -0,0 +1,406 @@
|
||||
/**
|
||||
* @module ol/source/ogcTileUtil
|
||||
*/
|
||||
|
||||
import TileGrid from '../tilegrid/TileGrid.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {getJSON, resolveUrl} from '../net.js';
|
||||
import {get as getProjection} from '../proj.js';
|
||||
import {getIntersection as intersectExtents} from '../extent.js';
|
||||
|
||||
/**
|
||||
* See https://ogcapi.ogc.org/tiles/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {'map' | 'vector'} TileType
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {'topLeft' | 'bottomLeft'} CornerOfOrigin
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} TileSet
|
||||
* @property {TileType} dataType Type of data represented in the tileset.
|
||||
* @property {string} [tileMatrixSetDefinition] Reference to a tile matrix set definition.
|
||||
* @property {TileMatrixSet} [tileMatrixSet] Tile matrix set definition.
|
||||
* @property {Array<TileMatrixSetLimit>} [tileMatrixSetLimits] Tile matrix set limits.
|
||||
* @property {Array<Link>} links Tileset links.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Link
|
||||
* @property {string} rel The link rel attribute.
|
||||
* @property {string} href The link URL.
|
||||
* @property {string} type The link type.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} TileMatrixSetLimit
|
||||
* @property {string} tileMatrix The tile matrix id.
|
||||
* @property {number} minTileRow The minimum tile row.
|
||||
* @property {number} maxTileRow The maximum tile row.
|
||||
* @property {number} minTileCol The minimum tile column.
|
||||
* @property {number} maxTileCol The maximum tile column.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} TileMatrixSet
|
||||
* @property {string} id The tile matrix set identifier.
|
||||
* @property {string} crs The coordinate reference system.
|
||||
* @property {Array<TileMatrix>} tileMatrices Array of tile matrices.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} TileMatrix
|
||||
* @property {string} id The tile matrix identifier.
|
||||
* @property {number} cellSize The pixel resolution (map units per pixel).
|
||||
* @property {Array<number>} pointOfOrigin The map location of the matrix origin.
|
||||
* @property {CornerOfOrigin} [cornerOfOrigin='topLeft'] The corner of the matrix that represents the origin ('topLeft' or 'bottomLeft').
|
||||
* @property {number} matrixWidth The number of columns.
|
||||
* @property {number} matrixHeight The number of rows.
|
||||
* @property {number} tileWidth The pixel width of a tile.
|
||||
* @property {number} tileHeight The pixel height of a tile.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {Object<string, boolean>}
|
||||
*/
|
||||
const knownMapMediaTypes = {
|
||||
'image/png': true,
|
||||
'image/jpeg': true,
|
||||
'image/gif': true,
|
||||
'image/webp': true,
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {Object<string, boolean>}
|
||||
*/
|
||||
const knownVectorMediaTypes = {
|
||||
'application/vnd.mapbox-vector-tile': true,
|
||||
'application/geo+json': true,
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} TileSetInfo
|
||||
* @property {string} urlTemplate The tile URL template.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} grid The tile grid.
|
||||
* @property {import("../Tile.js").UrlFunction} urlFunction The tile URL function.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SourceInfo
|
||||
* @property {string} url The tile set URL.
|
||||
* @property {string} mediaType The preferred tile media type.
|
||||
* @property {Array<string>} [supportedMediaTypes] The supported media types.
|
||||
* @property {import("../proj/Projection.js").default} projection The source projection.
|
||||
* @property {Object} [context] Optional context for constructing the URL.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Array<Link>} links Tileset links.
|
||||
* @param {string} [mediaType] The preferred media type.
|
||||
* @return {string} The tile URL template.
|
||||
*/
|
||||
export function getMapTileUrlTemplate(links, mediaType) {
|
||||
let tileUrlTemplate;
|
||||
let fallbackUrlTemplate;
|
||||
for (let i = 0; i < links.length; ++i) {
|
||||
const link = links[i];
|
||||
if (link.rel === 'item') {
|
||||
if (link.type === mediaType) {
|
||||
tileUrlTemplate = link.href;
|
||||
break;
|
||||
}
|
||||
if (knownMapMediaTypes[link.type]) {
|
||||
fallbackUrlTemplate = link.href;
|
||||
} else if (!fallbackUrlTemplate && link.type.indexOf('image/') === 0) {
|
||||
fallbackUrlTemplate = link.href;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tileUrlTemplate) {
|
||||
if (fallbackUrlTemplate) {
|
||||
tileUrlTemplate = fallbackUrlTemplate;
|
||||
} else {
|
||||
throw new Error('Could not find "item" link');
|
||||
}
|
||||
}
|
||||
|
||||
return tileUrlTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<Link>} links Tileset links.
|
||||
* @param {string} [mediaType] The preferred media type.
|
||||
* @param {Array<string>} [supportedMediaTypes] The media types supported by the parser.
|
||||
* @return {string} The tile URL template.
|
||||
*/
|
||||
export function getVectorTileUrlTemplate(
|
||||
links,
|
||||
mediaType,
|
||||
supportedMediaTypes
|
||||
) {
|
||||
let tileUrlTemplate;
|
||||
let fallbackUrlTemplate;
|
||||
|
||||
/**
|
||||
* Lookup of URL by media type.
|
||||
* @type {Object<string, string>}
|
||||
*/
|
||||
const hrefLookup = {};
|
||||
|
||||
for (let i = 0; i < links.length; ++i) {
|
||||
const link = links[i];
|
||||
hrefLookup[link.type] = link.href;
|
||||
if (link.rel === 'item') {
|
||||
if (link.type === mediaType) {
|
||||
tileUrlTemplate = link.href;
|
||||
break;
|
||||
}
|
||||
if (knownVectorMediaTypes[link.type]) {
|
||||
fallbackUrlTemplate = link.href;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tileUrlTemplate && supportedMediaTypes) {
|
||||
for (let i = 0; i < supportedMediaTypes.length; ++i) {
|
||||
const supportedMediaType = supportedMediaTypes[i];
|
||||
if (hrefLookup[supportedMediaType]) {
|
||||
tileUrlTemplate = hrefLookup[supportedMediaType];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tileUrlTemplate) {
|
||||
if (fallbackUrlTemplate) {
|
||||
tileUrlTemplate = fallbackUrlTemplate;
|
||||
} else {
|
||||
throw new Error('Could not find "item" link');
|
||||
}
|
||||
}
|
||||
|
||||
return tileUrlTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SourceInfo} sourceInfo The source info.
|
||||
* @param {TileMatrixSet} tileMatrixSet Tile matrix set.
|
||||
* @param {string} tileUrlTemplate Tile URL template.
|
||||
* @param {Array<TileMatrixSetLimit>} [tileMatrixSetLimits] Tile matrix set limits.
|
||||
* @return {TileSetInfo} Tile set info.
|
||||
*/
|
||||
function parseTileMatrixSet(
|
||||
sourceInfo,
|
||||
tileMatrixSet,
|
||||
tileUrlTemplate,
|
||||
tileMatrixSetLimits
|
||||
) {
|
||||
let projection = sourceInfo.projection;
|
||||
if (!projection) {
|
||||
projection = getProjection(tileMatrixSet.crs);
|
||||
if (!projection) {
|
||||
throw new Error(`Unsupported CRS: ${tileMatrixSet.crs}`);
|
||||
}
|
||||
}
|
||||
const backwards = projection.getAxisOrientation().substr(0, 2) !== 'en';
|
||||
|
||||
const matrices = tileMatrixSet.tileMatrices;
|
||||
|
||||
/**
|
||||
* @type {Object<string, TileMatrix>}
|
||||
*/
|
||||
const matrixLookup = {};
|
||||
for (let i = 0; i < matrices.length; ++i) {
|
||||
const matrix = matrices[i];
|
||||
matrixLookup[matrix.id] = matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Object<string, TileMatrixSetLimit>}
|
||||
*/
|
||||
const limitLookup = {};
|
||||
|
||||
/**
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
const matrixIds = [];
|
||||
|
||||
if (tileMatrixSetLimits) {
|
||||
for (let i = 0; i < tileMatrixSetLimits.length; ++i) {
|
||||
const limit = tileMatrixSetLimits[i];
|
||||
const id = limit.tileMatrix;
|
||||
matrixIds.push(id);
|
||||
limitLookup[id] = limit;
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < matrices.length; ++i) {
|
||||
const id = matrices[i].id;
|
||||
matrixIds.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
const length = matrixIds.length;
|
||||
const origins = new Array(length);
|
||||
const resolutions = new Array(length);
|
||||
const sizes = new Array(length);
|
||||
const tileSizes = new Array(length);
|
||||
const extent = [-Infinity, -Infinity, Infinity, Infinity];
|
||||
|
||||
for (let i = 0; i < length; ++i) {
|
||||
const id = matrixIds[i];
|
||||
const matrix = matrixLookup[id];
|
||||
const origin = matrix.pointOfOrigin;
|
||||
if (backwards) {
|
||||
origins[i] = [origin[1], origin[0]];
|
||||
} else {
|
||||
origins[i] = origin;
|
||||
}
|
||||
resolutions[i] = matrix.cellSize;
|
||||
sizes[i] = [matrix.matrixWidth, matrix.matrixHeight];
|
||||
tileSizes[i] = [matrix.tileWidth, matrix.tileHeight];
|
||||
const limit = limitLookup[id];
|
||||
if (limit) {
|
||||
const tileMapWidth = matrix.cellSize * matrix.tileWidth;
|
||||
const minX = origins[i][0] + limit.minTileCol * tileMapWidth;
|
||||
const maxX = origins[i][0] + (limit.maxTileCol + 1) * tileMapWidth;
|
||||
|
||||
const tileMapHeight = matrix.cellSize * matrix.tileHeight;
|
||||
const upsideDown = matrix.cornerOfOrigin === 'bottomLeft';
|
||||
|
||||
let minY;
|
||||
let maxY;
|
||||
if (upsideDown) {
|
||||
minY = origins[i][1] + limit.minTileRow * tileMapHeight;
|
||||
maxY = origins[i][1] + (limit.maxTileRow + 1) * tileMapHeight;
|
||||
} else {
|
||||
minY = origins[i][1] - (limit.maxTileRow + 1) * tileMapHeight;
|
||||
maxY = origins[i][1] - limit.minTileRow * tileMapHeight;
|
||||
}
|
||||
|
||||
intersectExtents(extent, [minX, minY, maxX, maxY], extent);
|
||||
}
|
||||
}
|
||||
|
||||
const tileGrid = new TileGrid({
|
||||
origins: origins,
|
||||
resolutions: resolutions,
|
||||
sizes: sizes,
|
||||
tileSizes: tileSizes,
|
||||
extent: tileMatrixSetLimits ? extent : undefined,
|
||||
});
|
||||
|
||||
const context = sourceInfo.context;
|
||||
const base = sourceInfo.url;
|
||||
|
||||
function tileUrlFunction(tileCoord, pixelRatio, projection) {
|
||||
if (!tileCoord) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const id = matrixIds[tileCoord[0]];
|
||||
const matrix = matrixLookup[id];
|
||||
const upsideDown = matrix.cornerOfOrigin === 'bottomLeft';
|
||||
|
||||
const localContext = {
|
||||
tileMatrix: id,
|
||||
tileCol: tileCoord[1],
|
||||
tileRow: upsideDown ? -tileCoord[2] - 1 : tileCoord[2],
|
||||
};
|
||||
|
||||
if (tileMatrixSetLimits) {
|
||||
const limit = limitLookup[matrix.id];
|
||||
if (
|
||||
localContext.tileCol < limit.minTileCol ||
|
||||
localContext.tileCol > limit.maxTileCol ||
|
||||
localContext.tileRow < limit.minTileRow ||
|
||||
localContext.tileRow > limit.maxTileRow
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
assign(localContext, context);
|
||||
|
||||
const url = tileUrlTemplate.replace(/\{(\w+?)\}/g, function (m, p) {
|
||||
return localContext[p];
|
||||
});
|
||||
|
||||
return resolveUrl(base, url);
|
||||
}
|
||||
|
||||
return {
|
||||
grid: tileGrid,
|
||||
urlTemplate: tileUrlTemplate,
|
||||
urlFunction: tileUrlFunction,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SourceInfo} sourceInfo The source info.
|
||||
* @param {TileSet} tileSet Tile set.
|
||||
* @return {TileSetInfo|Promise<TileSetInfo>} Tile set info.
|
||||
*/
|
||||
function parseTileSetMetadata(sourceInfo, tileSet) {
|
||||
const tileMatrixSetLimits = tileSet.tileMatrixSetLimits;
|
||||
let tileUrlTemplate;
|
||||
|
||||
if (tileSet.dataType === 'map') {
|
||||
tileUrlTemplate = getMapTileUrlTemplate(
|
||||
tileSet.links,
|
||||
sourceInfo.mediaType
|
||||
);
|
||||
} else if (tileSet.dataType === 'vector') {
|
||||
tileUrlTemplate = getVectorTileUrlTemplate(
|
||||
tileSet.links,
|
||||
sourceInfo.mediaType,
|
||||
sourceInfo.supportedMediaTypes
|
||||
);
|
||||
} else {
|
||||
throw new Error('Expected tileset data type to be "map" or "vector"');
|
||||
}
|
||||
|
||||
if (tileSet.tileMatrixSet) {
|
||||
return parseTileMatrixSet(
|
||||
sourceInfo,
|
||||
tileSet.tileMatrixSet,
|
||||
tileUrlTemplate,
|
||||
tileMatrixSetLimits
|
||||
);
|
||||
}
|
||||
|
||||
const tileMatrixSetLink = tileSet.links.find(
|
||||
(link) =>
|
||||
link.rel === 'http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme'
|
||||
);
|
||||
if (!tileMatrixSetLink) {
|
||||
throw new Error(
|
||||
'Expected http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme link or tileMatrixSet'
|
||||
);
|
||||
}
|
||||
const tileMatrixSetDefinition = tileMatrixSetLink.href;
|
||||
|
||||
const url = resolveUrl(sourceInfo.url, tileMatrixSetDefinition);
|
||||
return getJSON(url).then(function (tileMatrixSet) {
|
||||
return parseTileMatrixSet(
|
||||
sourceInfo,
|
||||
tileMatrixSet,
|
||||
tileUrlTemplate,
|
||||
tileMatrixSetLimits
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SourceInfo} sourceInfo Source info.
|
||||
* @return {Promise<TileSetInfo>} Tile set info.
|
||||
*/
|
||||
export function getTileSetInfo(sourceInfo) {
|
||||
return getJSON(sourceInfo.url).then(function (tileSet) {
|
||||
return parseTileSetMetadata(sourceInfo, tileSet);
|
||||
});
|
||||
}
|
||||
19
node_modules/ol/src/source/wms.js
generated
vendored
Normal file
19
node_modules/ol/src/source/wms.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @module ol/source/wms
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default WMS version.
|
||||
* @type {string}
|
||||
*/
|
||||
export const DEFAULT_VERSION = '1.3.0';
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @typedef {'carmentaserver' | 'geoserver' | 'mapserver' | 'qgis'} ServerType
|
||||
* Set the server type to use implementation-specific parameters beyond the WMS specification.
|
||||
* - `'carmentaserver'`: HiDPI support for [Carmenta Server](https://www.carmenta.com/en/products/carmenta-server)
|
||||
* - `'geoserver'`: HiDPI support for [GeoServer](https://geoserver.org/)
|
||||
* - `'mapserver'`: HiDPI support for [MapServer](https://mapserver.org/)
|
||||
* - `'qgis'`: HiDPI support for [QGIS](https://qgis.org/)
|
||||
*/
|
||||
Reference in New Issue
Block a user