planning
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s

This commit is contained in:
2024-10-14 09:15:30 +02:00
parent bcba00a730
commit 6e64e138e2
21059 changed files with 2317811 additions and 1 deletions

335
node_modules/ol/src/source/BingMaps.js generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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 =
'&#169; ' +
'<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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

62
node_modules/ol/src/source/VectorEventType.js generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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/)
*/