Merge pull request #10963 from tschaub/ogc-tiles
OGC map and vector tile sources
This commit is contained in:
11
examples/ogc-map-tiles-geographic.html
Normal file
11
examples/ogc-map-tiles-geographic.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
layout: example.html
|
||||||
|
title: OGC Map Tiles (Geographic)
|
||||||
|
shortdesc: Rendering map tiles from an OGC API – Tiles service.
|
||||||
|
docs: >
|
||||||
|
The <a href="https://ogcapi.ogc.org/tiles/">OGC API – Tiles</a> specification describes how a service can provide map tiles. Because the specification
|
||||||
|
has not yet been finalized, the <code>OGCMapTile</code> source is not yet part of the stable API.
|
||||||
|
tags: "ogc"
|
||||||
|
experimental: true
|
||||||
|
---
|
||||||
|
<div id="map" class="map"></div>
|
||||||
20
examples/ogc-map-tiles-geographic.js
Normal file
20
examples/ogc-map-tiles-geographic.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import Map from '../src/ol/Map.js';
|
||||||
|
import OGCMapTile from '../src/ol/source/OGCMapTile.js';
|
||||||
|
import TileLayer from '../src/ol/layer/Tile.js';
|
||||||
|
import View from '../src/ol/View.js';
|
||||||
|
|
||||||
|
const map = new Map({
|
||||||
|
target: 'map',
|
||||||
|
layers: [
|
||||||
|
new TileLayer({
|
||||||
|
source: new OGCMapTile({
|
||||||
|
url: 'https://maps.ecere.com/ogcapi/collections/blueMarble/map/tiles/WorldCRS84Quad',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
view: new View({
|
||||||
|
projection: 'EPSG:4326',
|
||||||
|
center: [0, 0],
|
||||||
|
zoom: 1,
|
||||||
|
}),
|
||||||
|
});
|
||||||
11
examples/ogc-map-tiles.html
Normal file
11
examples/ogc-map-tiles.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
layout: example.html
|
||||||
|
title: OGC Map Tiles
|
||||||
|
shortdesc: Rendering map tiles from an OGC API – Tiles service.
|
||||||
|
docs: >
|
||||||
|
The <a href="https://ogcapi.ogc.org/tiles/">OGC API – Tiles</a> specification describes how a service can provide map tiles. Because the specification
|
||||||
|
has not yet been finalized, the <code>OGCMapTile</code> source is not yet part of the stable API.
|
||||||
|
tags: "ogc"
|
||||||
|
experimental: true
|
||||||
|
---
|
||||||
|
<div id="map" class="map"></div>
|
||||||
19
examples/ogc-map-tiles.js
Normal file
19
examples/ogc-map-tiles.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import Map from '../src/ol/Map.js';
|
||||||
|
import OGCMapTile from '../src/ol/source/OGCMapTile.js';
|
||||||
|
import TileLayer from '../src/ol/layer/Tile.js';
|
||||||
|
import View from '../src/ol/View.js';
|
||||||
|
|
||||||
|
const map = new Map({
|
||||||
|
target: 'map',
|
||||||
|
layers: [
|
||||||
|
new TileLayer({
|
||||||
|
source: new OGCMapTile({
|
||||||
|
url: 'https://maps.ecere.com/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
view: new View({
|
||||||
|
center: [0, 0],
|
||||||
|
zoom: 1,
|
||||||
|
}),
|
||||||
|
});
|
||||||
11
examples/ogc-vector-tiles.html
Normal file
11
examples/ogc-vector-tiles.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
layout: example.html
|
||||||
|
title: OGC Vector Tiles
|
||||||
|
shortdesc: Rendering vector tiles from an OGC API – Tiles service.
|
||||||
|
docs: >
|
||||||
|
The <a href="https://ogcapi.ogc.org/tiles/">OGC API – Tiles</a> specification describes how a service can provide vector tiles. Because the specification
|
||||||
|
has not yet been finalized, the <code>OGCVectorTile</code> source is not yet part of the stable API.
|
||||||
|
tags: "ogc, vector"
|
||||||
|
experimental: true
|
||||||
|
---
|
||||||
|
<div id="map" class="map"></div>
|
||||||
21
examples/ogc-vector-tiles.js
Normal file
21
examples/ogc-vector-tiles.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import MVT from '../src/ol/format/MVT.js';
|
||||||
|
import Map from '../src/ol/Map.js';
|
||||||
|
import OGCVectorTile from '../src/ol/source/OGCVectorTile.js';
|
||||||
|
import VectorTileLayer from '../src/ol/layer/VectorTile.js';
|
||||||
|
import View from '../src/ol/View.js';
|
||||||
|
|
||||||
|
const map = new Map({
|
||||||
|
target: 'map',
|
||||||
|
layers: [
|
||||||
|
new VectorTileLayer({
|
||||||
|
source: new OGCVectorTile({
|
||||||
|
url: 'https://maps.ecere.com/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad',
|
||||||
|
format: new MVT(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
view: new View({
|
||||||
|
center: [0, 0],
|
||||||
|
zoom: 1,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@@ -76,6 +76,12 @@ class FeatureFormat {
|
|||||||
* @type {import("../proj/Projection.js").default|undefined}
|
* @type {import("../proj/Projection.js").default|undefined}
|
||||||
*/
|
*/
|
||||||
this.defaultFeatureProjection = undefined;
|
this.defaultFeatureProjection = undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list media types supported by the format in descending order of preference.
|
||||||
|
* @type {Array<string>}
|
||||||
|
*/
|
||||||
|
this.supportedMediaTypes = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ class GMLBase extends XMLFeature {
|
|||||||
'featureMember': makeArrayPusher(this.readFeaturesInternal),
|
'featureMember': makeArrayPusher(this.readFeaturesInternal),
|
||||||
'featureMembers': makeReplacer(this.readFeaturesInternal),
|
'featureMembers': makeReplacer(this.readFeaturesInternal),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.supportedMediaTypes = ['application/gml+xml'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -82,6 +82,11 @@ class GeoJSON extends JSONFeature {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.extractGeometryName_ = options.extractGeometryName;
|
this.extractGeometryName_ = options.extractGeometryName;
|
||||||
|
|
||||||
|
this.supportedMediaTypes = [
|
||||||
|
'application/geo+json',
|
||||||
|
'application/vnd.geo+json',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -489,6 +489,8 @@ class KML extends XMLFeature {
|
|||||||
this.iconUrlFunction_ = options.iconUrlFunction
|
this.iconUrlFunction_ = options.iconUrlFunction
|
||||||
? options.iconUrlFunction
|
? options.iconUrlFunction
|
||||||
: defaultIconUrlFunction;
|
: defaultIconUrlFunction;
|
||||||
|
|
||||||
|
this.supportedMediaTypes = ['application/vnd.google-earth.kml+xml'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -89,6 +89,11 @@ class MVT extends FeatureFormat {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
this.idProperty_ = options.idProperty;
|
this.idProperty_ = options.idProperty;
|
||||||
|
|
||||||
|
this.supportedMediaTypes = [
|
||||||
|
'application/vnd.mapbox-vector-tile',
|
||||||
|
'application/x-protobuf',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
107
src/ol/net.js
107
src/ol/net.js
@@ -41,3 +41,110 @@ export function jsonp(url, callback, opt_errback, opt_callbackParam) {
|
|||||||
};
|
};
|
||||||
document.getElementsByTagName('head')[0].appendChild(script);
|
document.getElementsByTagName('head')[0].appendChild(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ResponseError extends Error {
|
||||||
|
/**
|
||||||
|
* @param {XMLHttpRequest} response The XHR object.
|
||||||
|
*/
|
||||||
|
constructor(response) {
|
||||||
|
const message = 'Unexpected response status: ' + response.status;
|
||||||
|
super(message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.name = 'ResponseError';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {XMLHttpRequest}
|
||||||
|
*/
|
||||||
|
this.response = response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClientError extends Error {
|
||||||
|
/**
|
||||||
|
* @param {XMLHttpRequest} client The XHR object.
|
||||||
|
*/
|
||||||
|
constructor(client) {
|
||||||
|
super('Failed to issue request');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.name = 'ClientError';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {XMLHttpRequest}
|
||||||
|
*/
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} url The URL.
|
||||||
|
* @return {Promise<Object>} A promise that resolves to the JSON response.
|
||||||
|
*/
|
||||||
|
export function getJSON(url) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
/**
|
||||||
|
* @param {ProgressEvent<XMLHttpRequest>} event The load event.
|
||||||
|
*/
|
||||||
|
function onLoad(event) {
|
||||||
|
const client = event.target;
|
||||||
|
// status will be 0 for file:// urls
|
||||||
|
if (!client.status || (client.status >= 200 && client.status < 300)) {
|
||||||
|
let data;
|
||||||
|
try {
|
||||||
|
data = JSON.parse(client.responseText);
|
||||||
|
} catch (err) {
|
||||||
|
const message = 'Error parsing response text as JSON: ' + err.message;
|
||||||
|
reject(new Error(message));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reject(new ResponseError(client));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ProgressEvent<XMLHttpRequest>} event The error event.
|
||||||
|
*/
|
||||||
|
function onError(event) {
|
||||||
|
reject(new ClientError(event.target));
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = new XMLHttpRequest();
|
||||||
|
client.addEventListener('load', onLoad);
|
||||||
|
client.addEventListener('error', onError);
|
||||||
|
client.open('GET', url);
|
||||||
|
client.setRequestHeader('Accept', 'application/json');
|
||||||
|
client.send();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} base The base URL.
|
||||||
|
* @param {string} url The potentially relative URL.
|
||||||
|
* @return {string} The full URL.
|
||||||
|
*/
|
||||||
|
export function resolveUrl(base, url) {
|
||||||
|
if (url.indexOf('://') >= 0) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
return new URL(url, base).href;
|
||||||
|
}
|
||||||
|
|
||||||
|
let originalXHR;
|
||||||
|
export function overrideXHR(xhr) {
|
||||||
|
if (typeof XMLHttpRequest !== 'undefined') {
|
||||||
|
originalXHR = XMLHttpRequest;
|
||||||
|
}
|
||||||
|
global.XMLHttpRequest = xhr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function restoreXHR() {
|
||||||
|
global.XMLHttpRequest = originalXHR;
|
||||||
|
}
|
||||||
|
|||||||
93
src/ol/source/OGCMapTile.js
Normal file
93
src/ol/source/OGCMapTile.js
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* @module ol/source/OGCMapTile
|
||||||
|
*/
|
||||||
|
import SourceState from './State.js';
|
||||||
|
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] Enable image smoothing.
|
||||||
|
* @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) {
|
||||||
|
super({
|
||||||
|
attributions: options.attributions,
|
||||||
|
cacheSize: options.cacheSize,
|
||||||
|
crossOrigin: options.crossOrigin,
|
||||||
|
imageSmoothing: options.imageSmoothing,
|
||||||
|
projection: options.projection,
|
||||||
|
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||||
|
state: SourceState.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(SourceState.READY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {Error} error The error.
|
||||||
|
*/
|
||||||
|
handleError_(error) {
|
||||||
|
console.error(error); // eslint-disable-line no-console
|
||||||
|
this.setState(SourceState.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OGCMapTile;
|
||||||
100
src/ol/source/OGCVectorTile.js
Normal file
100
src/ol/source/OGCVectorTile.js
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/**
|
||||||
|
* @module ol/source/OGCVectorTile
|
||||||
|
*/
|
||||||
|
|
||||||
|
import SourceState from './State.js';
|
||||||
|
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}.
|
||||||
|
* @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: SourceState.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(SourceState.READY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {Error} error The error.
|
||||||
|
*/
|
||||||
|
handleError_(error) {
|
||||||
|
console.error(error); // eslint-disable-line no-console
|
||||||
|
this.setState(SourceState.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OGCVectorTile;
|
||||||
399
src/ol/source/ogcTileUtil.js
Normal file
399
src/ol/source/ogcTileUtil.js
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
/**
|
||||||
|
* @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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tileSet.tileMatrixSetDefinition) {
|
||||||
|
throw new Error('Expected tileMatrixSetDefinition or tileMatrixSet');
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = resolveUrl(sourceInfo.url, tileSet.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);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,7 +1,40 @@
|
|||||||
|
import {
|
||||||
|
getJSON,
|
||||||
|
jsonp as requestJSONP,
|
||||||
|
resolveUrl,
|
||||||
|
} from '../../../../src/ol/net.js';
|
||||||
import {getUid} from '../../../../src/ol/util.js';
|
import {getUid} from '../../../../src/ol/util.js';
|
||||||
import {jsonp as requestJSONP} from '../../../../src/ol/net.js';
|
|
||||||
|
|
||||||
describe('ol.net', function () {
|
describe('ol/net', function () {
|
||||||
|
describe('getJSON()', function () {
|
||||||
|
it('returns a promise that resolves to a parsed JSON object', function (done) {
|
||||||
|
const url = 'spec/ol/data/point.json';
|
||||||
|
const result = getJSON(url);
|
||||||
|
expect(result).to.be.a(Promise);
|
||||||
|
result.then(function (json) {
|
||||||
|
expect(json).to.be.an(Object);
|
||||||
|
expect(json.type).to.be('FeatureCollection');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
result.catch(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('resolveUrl()', function () {
|
||||||
|
it('resolves an absolute URL given a base and relative URL', function () {
|
||||||
|
const url = resolveUrl('https://example.com/base/', 'relative/path');
|
||||||
|
expect(url).to.be('https://example.com/base/relative/path');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the second arg if it is an absolute URL', function () {
|
||||||
|
const url = resolveUrl(
|
||||||
|
'https://example.com',
|
||||||
|
'https://other-example.com'
|
||||||
|
);
|
||||||
|
expect(url).to.be('https://other-example.com');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('jsonp()', function () {
|
describe('jsonp()', function () {
|
||||||
const head = document.getElementsByTagName('head')[0];
|
const head = document.getElementsByTagName('head')[0];
|
||||||
const origAppendChild = head.appendChild;
|
const origAppendChild = head.appendChild;
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"title" : "blueMarble",
|
||||||
|
"dataType" : "map",
|
||||||
|
"tileMatrixSetURI" : "http://www.opengis.net/def/tilematrixset/OGC/1.0/WebMercatorQuad",
|
||||||
|
"tileMatrixSetDefinition" : "https://maps.ecere.com/ogcapi/tileMatrixSets/WebMercatorQuad",
|
||||||
|
"tileMatrixSetLimits" : [
|
||||||
|
{ "tileMatrix" : "0", "minTileRow" : 0, "maxTileRow" : 0, "minTileCol" : 0, "maxTileCol" : 0 },
|
||||||
|
{ "tileMatrix" : "1", "minTileRow" : 0, "maxTileRow" : 1, "minTileCol" : 0, "maxTileCol" : 1 },
|
||||||
|
{ "tileMatrix" : "2", "minTileRow" : 0, "maxTileRow" : 3, "minTileCol" : 0, "maxTileCol" : 3 },
|
||||||
|
{ "tileMatrix" : "3", "minTileRow" : 0, "maxTileRow" : 7, "minTileCol" : 0, "maxTileCol" : 7 },
|
||||||
|
{ "tileMatrix" : "4", "minTileRow" : 0, "maxTileRow" : 15, "minTileCol" : 0, "maxTileCol" : 15 },
|
||||||
|
{ "tileMatrix" : "5", "minTileRow" : 0, "maxTileRow" : 31, "minTileCol" : 0, "maxTileCol" : 31 },
|
||||||
|
{ "tileMatrix" : "6", "minTileRow" : 0, "maxTileRow" : 63, "minTileCol" : 0, "maxTileCol" : 63 },
|
||||||
|
{ "tileMatrix" : "7", "minTileRow" : 0, "maxTileRow" : 127, "minTileCol" : 0, "maxTileCol" : 127 },
|
||||||
|
{ "tileMatrix" : "8", "minTileRow" : 0, "maxTileRow" : 255, "minTileCol" : 0, "maxTileCol" : 255 },
|
||||||
|
{ "tileMatrix" : "9", "minTileRow" : 0, "maxTileRow" : 511, "minTileCol" : 0, "maxTileCol" : 511 }
|
||||||
|
],
|
||||||
|
"centerPoint" : {
|
||||||
|
"coordinates" : [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"tileMatrix" : "4",
|
||||||
|
"scaleDenominator" : 34942641.501794859767,
|
||||||
|
"cellSize" : 9783.9396205025605
|
||||||
|
},
|
||||||
|
"links" : [
|
||||||
|
{
|
||||||
|
"rel" : "self",
|
||||||
|
"type" : "application/json",
|
||||||
|
"title" : "The JSON representation of the WebMercatorQuad map tileset for blueMarble",
|
||||||
|
"href" : "/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad?f=json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "alternate",
|
||||||
|
"type" : "text/plain",
|
||||||
|
"title" : "The ECON representation of the WebMercatorQuad map tileset for blueMarble",
|
||||||
|
"href" : "/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad?f=econ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "alternate",
|
||||||
|
"type" : "text/html",
|
||||||
|
"title" : "The HTML representation of the WebMercatorQuad map tileset for blueMarble",
|
||||||
|
"href" : "/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad?=html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "alternate",
|
||||||
|
"type" : "application/json+tile",
|
||||||
|
"title" : "The TileJSON representation of the WebMercatorQuad map tileset for blueMarble",
|
||||||
|
"href" : "/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad?f=tilejson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "http://www.opengis.net/def/rel/ogc/1.0/geodata",
|
||||||
|
"href" : "/ogcapi/collections/blueMarble"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "item",
|
||||||
|
"type" : "application/vnd.gnosis-map-tile",
|
||||||
|
"title" : "WebMercatorQuad map tiles for blueMarble (as GNOSIS Map Tiles)",
|
||||||
|
"href" : "/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.gmt",
|
||||||
|
"templated" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "item",
|
||||||
|
"type" : "image/png",
|
||||||
|
"title" : "WebMercatorQuad map tiles for blueMarble (as PNG)",
|
||||||
|
"href" : "/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.png",
|
||||||
|
"templated" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "item",
|
||||||
|
"type" : "image/jpeg",
|
||||||
|
"title" : "WebMercatorQuad map tiles for blueMarble (as JPG)",
|
||||||
|
"href" : "/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.jpg",
|
||||||
|
"templated" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "item",
|
||||||
|
"type" : "image/tiff; application=geotiff",
|
||||||
|
"title" : "WebMercatorQuad map tiles for blueMarble (as GeoTIFF)",
|
||||||
|
"href" : "/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.tif",
|
||||||
|
"templated" : true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
{
|
||||||
|
"title" : "ne_10m_admin_0_countries",
|
||||||
|
"dataType" : "vector",
|
||||||
|
"tileMatrixSetURI" : "http://www.opengis.net/def/tilematrixset/OGC/1.0/WebMercatorQuad",
|
||||||
|
"tileMatrixSetDefinition" : "https://maps.ecere.com/ogcapi/tileMatrixSets/WebMercatorQuad",
|
||||||
|
"tileMatrixSetLimits" : [
|
||||||
|
{ "tileMatrix" : "0", "minTileRow" : 0, "maxTileRow" : 0, "minTileCol" : 0, "maxTileCol" : 0 },
|
||||||
|
{ "tileMatrix" : "1", "minTileRow" : 0, "maxTileRow" : 1, "minTileCol" : 0, "maxTileCol" : 1 },
|
||||||
|
{ "tileMatrix" : "2", "minTileRow" : 0, "maxTileRow" : 3, "minTileCol" : 0, "maxTileCol" : 3 },
|
||||||
|
{ "tileMatrix" : "3", "minTileRow" : 0, "maxTileRow" : 7, "minTileCol" : 0, "maxTileCol" : 7 },
|
||||||
|
{ "tileMatrix" : "4", "minTileRow" : 0, "maxTileRow" : 15, "minTileCol" : 0, "maxTileCol" : 15 },
|
||||||
|
{ "tileMatrix" : "5", "minTileRow" : 0, "maxTileRow" : 31, "minTileCol" : 0, "maxTileCol" : 31 },
|
||||||
|
{ "tileMatrix" : "6", "minTileRow" : 0, "maxTileRow" : 63, "minTileCol" : 0, "maxTileCol" : 63 },
|
||||||
|
{ "tileMatrix" : "7", "minTileRow" : 0, "maxTileRow" : 127, "minTileCol" : 0, "maxTileCol" : 127 }
|
||||||
|
],
|
||||||
|
"layers" : [
|
||||||
|
{
|
||||||
|
"id" : "ne_10m_admin_0_countries",
|
||||||
|
"dataType" : "vector",
|
||||||
|
"geometryType" : "polygon",
|
||||||
|
"minScaleDenominator" : 4367830.1877243574709,
|
||||||
|
"minCellSize" : 1222.9924525628201,
|
||||||
|
"maxTileMatrix" : "7",
|
||||||
|
"links" : [
|
||||||
|
{
|
||||||
|
"rel" : "http://www.opengis.net/def/rel/ogc/1.0/geodata",
|
||||||
|
"href" : "/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"propertiesSchema" : {
|
||||||
|
"type" : "object",
|
||||||
|
"properties" : { "abbrev" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "abbrev_len" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "adm0_a3" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "adm0_a3_is" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "adm0_a3_un" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "adm0_a3_us" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "adm0_a3_wb" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "adm0_dif" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "admin" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "brk_a3" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "brk_diff" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "brk_group" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "brk_name" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "continent" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "economy" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "featurecla" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "fips_10" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "formal_en" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "formal_fr" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "gdp_md_est" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "gdp_year" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "geou_dif" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "geounit" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "gu_a3" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "homepart" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "income_grp" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "iso_a2" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "iso_a3" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "iso_n3" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "labelrank" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "lastcensus" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "level" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "long_len" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "mapcolor13" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "mapcolor7" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "mapcolor8" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "mapcolor9" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "name" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "name_alt" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "name_len" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "name_long" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "name_sort" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "note_adm0" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "note_brk" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "pop_est" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "pop_year" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "postal" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "region_un" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "region_wb" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "scalerank" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "sov_a3" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "sovereignt" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "su_a3" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "su_dif" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "subregion" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "subunit" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "tiny" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "type" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "un_a3" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "wb_a2" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "wb_a3" : {
|
||||||
|
"type" : "string"
|
||||||
|
}, "wikipedia" : {
|
||||||
|
"type" : "integer"
|
||||||
|
}, "woe_id" : {
|
||||||
|
"type" : "integer"
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"centerPoint" : {
|
||||||
|
"coordinates" : [
|
||||||
|
0,
|
||||||
|
0.000102911832
|
||||||
|
],
|
||||||
|
"tileMatrix" : "4",
|
||||||
|
"scaleDenominator" : 34942641.501794859767,
|
||||||
|
"cellSize" : 9783.9396205025605
|
||||||
|
},
|
||||||
|
"links" : [
|
||||||
|
{
|
||||||
|
"rel" : "self",
|
||||||
|
"type" : "application/json",
|
||||||
|
"title" : "The JSON representation of the WebMercatorQuad vector tileset for NaturalEarth:cultural:ne_10m_admin_0_countries",
|
||||||
|
"href" : "/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad?f=json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "alternate",
|
||||||
|
"type" : "text/plain",
|
||||||
|
"title" : "The ECON representation of the WebMercatorQuad vector tileset for NaturalEarth:cultural:ne_10m_admin_0_countries",
|
||||||
|
"href" : "/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad?f=econ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "alternate",
|
||||||
|
"type" : "text/html",
|
||||||
|
"title" : "The HTML representation of the WebMercatorQuad vector tileset for NaturalEarth:cultural:ne_10m_admin_0_countries",
|
||||||
|
"href" : "/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad?=html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "alternate",
|
||||||
|
"type" : "application/json+tile",
|
||||||
|
"title" : "The TileJSON representation of the WebMercatorQuad vector tileset for NaturalEarth:cultural:ne_10m_admin_0_countries",
|
||||||
|
"href" : "/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad?f=tilejson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "http://www.opengis.net/def/rel/ogc/1.0/geodata",
|
||||||
|
"href" : "/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "item",
|
||||||
|
"type" : "application/vnd.gnosis-map-tile",
|
||||||
|
"title" : "WebMercatorQuad vector tiles for NaturalEarth:cultural:ne_10m_admin_0_countries (as GNOSIS Map Tiles)",
|
||||||
|
"href" : "/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.gmt",
|
||||||
|
"templated" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "item",
|
||||||
|
"type" : "application/vnd.mapbox-vector-tile",
|
||||||
|
"title" : "WebMercatorQuad vector tiles for NaturalEarth:cultural:ne_10m_admin_0_countries (as Mapbox Vector Tiles)",
|
||||||
|
"href" : "/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.mvt",
|
||||||
|
"templated" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "item",
|
||||||
|
"type" : "application/geo+json",
|
||||||
|
"title" : "WebMercatorQuad vector tiles for NaturalEarth:cultural:ne_10m_admin_0_countries (as GeoJSON)",
|
||||||
|
"href" : "/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.json",
|
||||||
|
"templated" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel" : "item",
|
||||||
|
"type" : "text/mapml",
|
||||||
|
"title" : "WebMercatorQuad vector tiles for NaturalEarth:cultural:ne_10m_admin_0_countries (as MapML)",
|
||||||
|
"href" : "/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.mapml",
|
||||||
|
"templated" : true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
{
|
||||||
|
"id" : "WebMercatorQuad",
|
||||||
|
"title" : "WebMercatorQuad",
|
||||||
|
"uri" : "http://www.opengis.net/def/tilematrixset/OGC/1.0/WebMercatorQuad",
|
||||||
|
"crs" : "http://www.opengis.net/def/crs/EPSG/0/3857",
|
||||||
|
"orderedAxes" : [
|
||||||
|
"E",
|
||||||
|
"N"
|
||||||
|
],
|
||||||
|
"wellKnownScaleSet" : "http://www.opengis.net/def/wkss/OGC/1.0/GoogleMapsCompatible",
|
||||||
|
"tileMatrices" : [
|
||||||
|
{
|
||||||
|
"id" : "0",
|
||||||
|
"scaleDenominator" : 559082264.0287177562714,
|
||||||
|
"cellSize" : 156543.033928040968,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 1,
|
||||||
|
"matrixHeight" : 1,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "1",
|
||||||
|
"scaleDenominator" : 279541132.0143588781357,
|
||||||
|
"cellSize" : 78271.516964020484,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 2,
|
||||||
|
"matrixHeight" : 2,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "2",
|
||||||
|
"scaleDenominator" : 139770566.0071794390678,
|
||||||
|
"cellSize" : 39135.758482010242,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 4,
|
||||||
|
"matrixHeight" : 4,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "3",
|
||||||
|
"scaleDenominator" : 69885283.0035897195339,
|
||||||
|
"cellSize" : 19567.879241005121,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 8,
|
||||||
|
"matrixHeight" : 8,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "4",
|
||||||
|
"scaleDenominator" : 34942641.501794859767,
|
||||||
|
"cellSize" : 9783.9396205025605,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 16,
|
||||||
|
"matrixHeight" : 16,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "5",
|
||||||
|
"scaleDenominator" : 17471320.7508974298835,
|
||||||
|
"cellSize" : 4891.9698102512803,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 32,
|
||||||
|
"matrixHeight" : 32,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "6",
|
||||||
|
"scaleDenominator" : 8735660.3754487149417,
|
||||||
|
"cellSize" : 2445.9849051256401,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 64,
|
||||||
|
"matrixHeight" : 64,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "7",
|
||||||
|
"scaleDenominator" : 4367830.1877243574709,
|
||||||
|
"cellSize" : 1222.9924525628201,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 128,
|
||||||
|
"matrixHeight" : 128,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "8",
|
||||||
|
"scaleDenominator" : 2183915.0938621787354,
|
||||||
|
"cellSize" : 611.49622628141,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 256,
|
||||||
|
"matrixHeight" : 256,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "9",
|
||||||
|
"scaleDenominator" : 1091957.5469310893677,
|
||||||
|
"cellSize" : 305.748113140705,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 512,
|
||||||
|
"matrixHeight" : 512,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "10",
|
||||||
|
"scaleDenominator" : 545978.7734655446839,
|
||||||
|
"cellSize" : 152.8740565703525,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 1024,
|
||||||
|
"matrixHeight" : 1024,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "11",
|
||||||
|
"scaleDenominator" : 272989.3867327723419,
|
||||||
|
"cellSize" : 76.4370282851763,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 2048,
|
||||||
|
"matrixHeight" : 2048,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "12",
|
||||||
|
"scaleDenominator" : 136494.693366386171,
|
||||||
|
"cellSize" : 38.2185141425881,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 4096,
|
||||||
|
"matrixHeight" : 4096,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "13",
|
||||||
|
"scaleDenominator" : 68247.3466831930855,
|
||||||
|
"cellSize" : 19.1092570712941,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 8192,
|
||||||
|
"matrixHeight" : 8192,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "14",
|
||||||
|
"scaleDenominator" : 34123.6733415965427,
|
||||||
|
"cellSize" : 9.554628535647,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 16384,
|
||||||
|
"matrixHeight" : 16384,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "15",
|
||||||
|
"scaleDenominator" : 17061.8366707982714,
|
||||||
|
"cellSize" : 4.7773142678235,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 32768,
|
||||||
|
"matrixHeight" : 32768,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "16",
|
||||||
|
"scaleDenominator" : 8530.9183353991357,
|
||||||
|
"cellSize" : 2.3886571339118,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 65536,
|
||||||
|
"matrixHeight" : 65536,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "17",
|
||||||
|
"scaleDenominator" : 4265.4591676995678,
|
||||||
|
"cellSize" : 1.1943285669559,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 131072,
|
||||||
|
"matrixHeight" : 131072,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "18",
|
||||||
|
"scaleDenominator" : 2132.7295838497839,
|
||||||
|
"cellSize" : 0.5971642834779,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 262144,
|
||||||
|
"matrixHeight" : 262144,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "19",
|
||||||
|
"scaleDenominator" : 1066.364791924892,
|
||||||
|
"cellSize" : 0.298582141739,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 524288,
|
||||||
|
"matrixHeight" : 524288,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "20",
|
||||||
|
"scaleDenominator" : 533.182395962446,
|
||||||
|
"cellSize" : 0.1492910708695,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 1048576,
|
||||||
|
"matrixHeight" : 1048576,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "21",
|
||||||
|
"scaleDenominator" : 266.591197981223,
|
||||||
|
"cellSize" : 0.0746455354347,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 2097152,
|
||||||
|
"matrixHeight" : 2097152,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "22",
|
||||||
|
"scaleDenominator" : 133.2955989906115,
|
||||||
|
"cellSize" : 0.0373227677174,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 4194304,
|
||||||
|
"matrixHeight" : 4194304,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "23",
|
||||||
|
"scaleDenominator" : 66.6477994953057,
|
||||||
|
"cellSize" : 0.0186613838587,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 8388608,
|
||||||
|
"matrixHeight" : 8388608,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "24",
|
||||||
|
"scaleDenominator" : 33.3238997476529,
|
||||||
|
"cellSize" : 0.0093306919293,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 16777216,
|
||||||
|
"matrixHeight" : 16777216,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "25",
|
||||||
|
"scaleDenominator" : 16.6619498738264,
|
||||||
|
"cellSize" : 0.0046653459647,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 33554432,
|
||||||
|
"matrixHeight" : 33554432,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "26",
|
||||||
|
"scaleDenominator" : 8.3309749369132,
|
||||||
|
"cellSize" : 0.0023326729823,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 67108864,
|
||||||
|
"matrixHeight" : 67108864,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "27",
|
||||||
|
"scaleDenominator" : 4.1654874684566,
|
||||||
|
"cellSize" : 0.0011663364912,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 134217728,
|
||||||
|
"matrixHeight" : 134217728,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "28",
|
||||||
|
"scaleDenominator" : 2.0827437342283,
|
||||||
|
"cellSize" : 0.0005831682456,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 268435456,
|
||||||
|
"matrixHeight" : 268435456,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" : "29",
|
||||||
|
"scaleDenominator" : 1.0413718671142,
|
||||||
|
"cellSize" : 0.0002915841228,
|
||||||
|
"cornerOfOrigin" : "topLeft",
|
||||||
|
"pointOfOrigin" : [
|
||||||
|
-20037508.3427892439067,
|
||||||
|
20037508.3427892439067
|
||||||
|
],
|
||||||
|
"matrixWidth" : 536870912,
|
||||||
|
"matrixHeight" : 536870912,
|
||||||
|
"tileWidth" : 256,
|
||||||
|
"tileHeight" : 256
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
267
test/node/ol/source/ogcTileUtil.test.js
Normal file
267
test/node/ol/source/ogcTileUtil.test.js
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
import TileGrid from '../../../../src/ol/tilegrid/TileGrid.js';
|
||||||
|
import events from 'events';
|
||||||
|
import expect from '../../expect.js';
|
||||||
|
import fse from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import {fileURLToPath} from 'url';
|
||||||
|
import {
|
||||||
|
getMapTileUrlTemplate,
|
||||||
|
getTileSetInfo,
|
||||||
|
getVectorTileUrlTemplate,
|
||||||
|
} from '../../../../src/ol/source/ogcTileUtil.js';
|
||||||
|
import {overrideXHR, restoreXHR} from '../../../../src/ol/net.js';
|
||||||
|
|
||||||
|
function getDataDir() {
|
||||||
|
const modulePath = fileURLToPath(import.meta.url);
|
||||||
|
return path.join(path.dirname(modulePath), 'data');
|
||||||
|
}
|
||||||
|
|
||||||
|
let baseUrl;
|
||||||
|
|
||||||
|
class MockXHR extends events.EventEmitter {
|
||||||
|
addEventListener(type, listener) {
|
||||||
|
this.addListener(type, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
open(method, url) {
|
||||||
|
if (url.startsWith(baseUrl)) {
|
||||||
|
url = url.slice(baseUrl.length);
|
||||||
|
}
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
setRequestHeader(key, value) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
send() {
|
||||||
|
let url = path.resolve(getDataDir(), this.url);
|
||||||
|
if (!url.endsWith('.json')) {
|
||||||
|
url = url + '.json';
|
||||||
|
}
|
||||||
|
fse.readJSON(url).then(
|
||||||
|
(data) => {
|
||||||
|
this.status = 200;
|
||||||
|
this.responseText = JSON.stringify(data);
|
||||||
|
this.emit('load', {target: this});
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.error(err); // eslint-disable-line no-console
|
||||||
|
this.emit('error', {target: this});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('ol/source/ogcTileUtil.js', () => {
|
||||||
|
describe('getTileSetInfo()', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
overrideXHR(MockXHR);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
baseUrl = '';
|
||||||
|
restoreXHR();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fetches and parses map tile info', async () => {
|
||||||
|
baseUrl = 'https://maps.ecere.com/';
|
||||||
|
const sourceInfo = {
|
||||||
|
url: 'https://maps.ecere.com/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad',
|
||||||
|
};
|
||||||
|
const tileInfo = await getTileSetInfo(sourceInfo);
|
||||||
|
expect(tileInfo).to.be.an(Object);
|
||||||
|
expect(tileInfo.urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.jpg'
|
||||||
|
);
|
||||||
|
expect(tileInfo.grid).to.be.a(TileGrid);
|
||||||
|
expect(tileInfo.grid.getTileSize(0)).to.eql([256, 256]);
|
||||||
|
expect(tileInfo.grid.getResolutions()).to.have.length(10);
|
||||||
|
expect(tileInfo.urlFunction).to.be.a(Function);
|
||||||
|
expect(tileInfo.urlFunction([3, 2, 1])).to.be(
|
||||||
|
'https://maps.ecere.com/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad/3/1/2.jpg'
|
||||||
|
);
|
||||||
|
expect(tileInfo.urlFunction([3, -1, 0])).to.be(undefined); // below min x
|
||||||
|
expect(tileInfo.urlFunction([3, 8, 0])).to.be(undefined); // above max x
|
||||||
|
expect(tileInfo.urlFunction([3, 0, -1])).to.be(undefined); // below min y
|
||||||
|
expect(tileInfo.urlFunction([3, 0, 8])).to.be(undefined); // above max y
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows preferred media type to be configured', async () => {
|
||||||
|
baseUrl = 'https://maps.ecere.com/';
|
||||||
|
const sourceInfo = {
|
||||||
|
url: 'https://maps.ecere.com/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad',
|
||||||
|
mediaType: 'image/png',
|
||||||
|
};
|
||||||
|
const tileInfo = await getTileSetInfo(sourceInfo);
|
||||||
|
expect(tileInfo).to.be.an(Object);
|
||||||
|
expect(tileInfo.urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.png'
|
||||||
|
);
|
||||||
|
expect(tileInfo.urlFunction).to.be.a(Function);
|
||||||
|
expect(tileInfo.urlFunction([3, 2, 1])).to.be(
|
||||||
|
'https://maps.ecere.com/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad/3/1/2.png'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fetches and parses vector tile info', async () => {
|
||||||
|
baseUrl = 'https://maps.ecere.com/';
|
||||||
|
const sourceInfo = {
|
||||||
|
url: 'https://maps.ecere.com/ogcapi/collections/ne_10m_admin_0_countries/tiles/WebMercatorQuad',
|
||||||
|
};
|
||||||
|
const tileInfo = await getTileSetInfo(sourceInfo);
|
||||||
|
expect(tileInfo).to.be.an(Object);
|
||||||
|
expect(tileInfo.urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.json'
|
||||||
|
);
|
||||||
|
expect(tileInfo.grid).to.be.a(TileGrid);
|
||||||
|
expect(tileInfo.grid.getTileSize(0)).to.eql([256, 256]);
|
||||||
|
expect(tileInfo.grid.getResolutions()).to.have.length(8);
|
||||||
|
expect(tileInfo.urlFunction).to.be.a(Function);
|
||||||
|
expect(tileInfo.urlFunction([3, 2, 1])).to.be(
|
||||||
|
'https://maps.ecere.com/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/3/1/2.json'
|
||||||
|
);
|
||||||
|
expect(tileInfo.urlFunction([2, -1, 0])).to.be(undefined); // below min x
|
||||||
|
expect(tileInfo.urlFunction([2, 4, 0])).to.be(undefined); // above max x
|
||||||
|
expect(tileInfo.urlFunction([2, 0, -1])).to.be(undefined); // below min y
|
||||||
|
expect(tileInfo.urlFunction([2, 0, 4])).to.be(undefined); // above max y
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows preferred media type to be configured', async () => {
|
||||||
|
baseUrl = 'https://maps.ecere.com/';
|
||||||
|
const sourceInfo = {
|
||||||
|
url: 'https://maps.ecere.com/ogcapi/collections/ne_10m_admin_0_countries/tiles/WebMercatorQuad',
|
||||||
|
mediaType: 'application/vnd.mapbox-vector-tile',
|
||||||
|
};
|
||||||
|
const tileInfo = await getTileSetInfo(sourceInfo);
|
||||||
|
expect(tileInfo).to.be.an(Object);
|
||||||
|
expect(tileInfo.urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.mvt'
|
||||||
|
);
|
||||||
|
expect(tileInfo.urlFunction).to.be.a(Function);
|
||||||
|
expect(tileInfo.urlFunction([3, 2, 1])).to.be(
|
||||||
|
'https://maps.ecere.com/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/3/1/2.mvt'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses supported media types if available', async () => {
|
||||||
|
baseUrl = 'https://maps.ecere.com/';
|
||||||
|
const sourceInfo = {
|
||||||
|
url: 'https://maps.ecere.com/ogcapi/collections/ne_10m_admin_0_countries/tiles/WebMercatorQuad',
|
||||||
|
supportedMediaTypes: [
|
||||||
|
'bogus-media-type',
|
||||||
|
'application/vnd.mapbox-vector-tile',
|
||||||
|
'application/geo+json', // should not be used
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const tileInfo = await getTileSetInfo(sourceInfo);
|
||||||
|
expect(tileInfo).to.be.an(Object);
|
||||||
|
expect(tileInfo.urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.mvt'
|
||||||
|
);
|
||||||
|
expect(tileInfo.urlFunction).to.be.a(Function);
|
||||||
|
expect(tileInfo.urlFunction([3, 2, 1])).to.be(
|
||||||
|
'https://maps.ecere.com/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/3/1/2.mvt'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('treats supported media types in descending order of priority', async () => {
|
||||||
|
baseUrl = 'https://maps.ecere.com/';
|
||||||
|
const sourceInfo = {
|
||||||
|
url: 'https://maps.ecere.com/ogcapi/collections/ne_10m_admin_0_countries/tiles/WebMercatorQuad',
|
||||||
|
supportedMediaTypes: [
|
||||||
|
'bogus-media-type',
|
||||||
|
'application/geo+json', // should be preferred
|
||||||
|
'application/vnd.mapbox-vector-tile',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const tileInfo = await getTileSetInfo(sourceInfo);
|
||||||
|
expect(tileInfo).to.be.an(Object);
|
||||||
|
expect(tileInfo.urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.json'
|
||||||
|
);
|
||||||
|
expect(tileInfo.urlFunction).to.be.a(Function);
|
||||||
|
expect(tileInfo.urlFunction([3, 2, 1])).to.be(
|
||||||
|
'https://maps.ecere.com/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/3/1/2.json'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getVectorTileUrlTemplate()', () => {
|
||||||
|
let links;
|
||||||
|
before(async () => {
|
||||||
|
const url = path.join(
|
||||||
|
getDataDir(),
|
||||||
|
'ogcapi/collections/ne_10m_admin_0_countries/tiles/WebMercatorQuad.json'
|
||||||
|
);
|
||||||
|
const tileSet = await fse.readJSON(url);
|
||||||
|
links = tileSet.links;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gets the last known vector type if the preferred media type is absent', () => {
|
||||||
|
const urlTemplate = getVectorTileUrlTemplate(links);
|
||||||
|
expect(urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.json'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gets the preferred media type if given', () => {
|
||||||
|
const urlTemplate = getVectorTileUrlTemplate(
|
||||||
|
links,
|
||||||
|
'application/vnd.mapbox-vector-tile'
|
||||||
|
);
|
||||||
|
expect(urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.mvt'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses supported media types is preferred media type is not given', () => {
|
||||||
|
const urlTemplate = getVectorTileUrlTemplate(links, undefined, [
|
||||||
|
'application/vnd.mapbox-vector-tile',
|
||||||
|
]);
|
||||||
|
expect(urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.mvt'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws if it cannot find preferred media type or a known fallback', () => {
|
||||||
|
function call() {
|
||||||
|
getVectorTileUrlTemplate([], 'application/vnd.mapbox-vector-tile');
|
||||||
|
}
|
||||||
|
expect(call).to.throwException('Could not find "item" link');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getMapTileUrlTemplate()', () => {
|
||||||
|
let links;
|
||||||
|
before(async () => {
|
||||||
|
const url = path.join(
|
||||||
|
getDataDir(),
|
||||||
|
'ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad.json'
|
||||||
|
);
|
||||||
|
const tileSet = await fse.readJSON(url);
|
||||||
|
links = tileSet.links;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gets the last known image type if the preferred media type is absent', () => {
|
||||||
|
const urlTemplate = getMapTileUrlTemplate(links);
|
||||||
|
expect(urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.jpg'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gets the preferred media type if given', () => {
|
||||||
|
const urlTemplate = getMapTileUrlTemplate(links, 'image/png');
|
||||||
|
expect(urlTemplate).to.be(
|
||||||
|
'/ogcapi/collections/blueMarble/map/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}.png'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws if it cannot find preferred media type or a known fallback', () => {
|
||||||
|
function call() {
|
||||||
|
getMapTileUrlTemplate([], 'image/png');
|
||||||
|
}
|
||||||
|
expect(call).to.throwException('Could not find "item" link');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user