Add supported media type list to feature formats
This commit is contained in:
@@ -10,7 +10,6 @@ const map = new Map({
|
|||||||
new VectorTileLayer({
|
new VectorTileLayer({
|
||||||
source: new OGCVectorTile({
|
source: new OGCVectorTile({
|
||||||
url: 'https://maps.ecere.com/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad',
|
url: 'https://maps.ecere.com/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad',
|
||||||
mediaType: 'application/vnd.mapbox-vector-tile',
|
|
||||||
format: new MVT(),
|
format: new MVT(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -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',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ import {getTileSetInfo} from './ogcTileUtil.js';
|
|||||||
* (zoom level), `{tileRow}`, and `{tileCol}` variables in the URL will always be provided by the source.
|
* (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 {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,
|
* @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 supported vector type. The chosen media type
|
* the source will try to find a link with rel="item" that uses a vector type supported by the configured format.
|
||||||
* must be parseable by the configured format.
|
|
||||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||||
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
|
* @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 {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least twice the number of tiles in the viewport.
|
||||||
@@ -41,6 +40,10 @@ import {getTileSetInfo} from './ogcTileUtil.js';
|
|||||||
* Layer source for map tiles from an [OGC API - Tiles](https://ogcapi.ogc.org/tiles/) service that provides "vector" type tiles.
|
* 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)
|
* 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.
|
* 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 {
|
class OGCVectorTile extends VectorTile {
|
||||||
/**
|
/**
|
||||||
@@ -65,6 +68,7 @@ class OGCVectorTile extends VectorTile {
|
|||||||
url: options.url,
|
url: options.url,
|
||||||
projection: this.getProjection(),
|
projection: this.getProjection(),
|
||||||
mediaType: options.mediaType,
|
mediaType: options.mediaType,
|
||||||
|
supportedMediaTypes: options.format.supportedMediaTypes,
|
||||||
context: options.context || null,
|
context: options.context || null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ const knownVectorMediaTypes = {
|
|||||||
* @typedef {Object} SourceInfo
|
* @typedef {Object} SourceInfo
|
||||||
* @property {string} url The tile set URL.
|
* @property {string} url The tile set URL.
|
||||||
* @property {string} mediaType The preferred tile media type.
|
* @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 {import("../proj/Projection.js").default} projection The source projection.
|
||||||
* @property {Object} [context] Optional context for constructing the URL.
|
* @property {Object} [context] Optional context for constructing the URL.
|
||||||
*/
|
*/
|
||||||
@@ -134,13 +135,26 @@ export function getMapTileUrlTemplate(links, mediaType) {
|
|||||||
/**
|
/**
|
||||||
* @param {Array<Link>} links Tileset links.
|
* @param {Array<Link>} links Tileset links.
|
||||||
* @param {string} [mediaType] The preferred media type.
|
* @param {string} [mediaType] The preferred media type.
|
||||||
|
* @param {Array<string>} [supportedMediaTypes] The media types supported by the parser.
|
||||||
* @return {string} The tile URL template.
|
* @return {string} The tile URL template.
|
||||||
*/
|
*/
|
||||||
export function getVectorTileUrlTemplate(links, mediaType) {
|
export function getVectorTileUrlTemplate(
|
||||||
|
links,
|
||||||
|
mediaType,
|
||||||
|
supportedMediaTypes
|
||||||
|
) {
|
||||||
let tileUrlTemplate;
|
let tileUrlTemplate;
|
||||||
let fallbackUrlTemplate;
|
let fallbackUrlTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup of URL by media type.
|
||||||
|
* @type {Object<string, string>}
|
||||||
|
*/
|
||||||
|
const hrefLookup = {};
|
||||||
|
|
||||||
for (let i = 0; i < links.length; ++i) {
|
for (let i = 0; i < links.length; ++i) {
|
||||||
const link = links[i];
|
const link = links[i];
|
||||||
|
hrefLookup[link.type] = link.href;
|
||||||
if (link.rel === 'item') {
|
if (link.rel === 'item') {
|
||||||
if (link.type === mediaType) {
|
if (link.type === mediaType) {
|
||||||
tileUrlTemplate = link.href;
|
tileUrlTemplate = link.href;
|
||||||
@@ -152,6 +166,16 @@ export function getVectorTileUrlTemplate(links, mediaType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (!tileUrlTemplate) {
|
||||||
if (fallbackUrlTemplate) {
|
if (fallbackUrlTemplate) {
|
||||||
tileUrlTemplate = fallbackUrlTemplate;
|
tileUrlTemplate = fallbackUrlTemplate;
|
||||||
@@ -333,7 +357,8 @@ function parseTileSetMetadata(sourceInfo, tileSet) {
|
|||||||
} else if (tileSet.dataType === 'vector') {
|
} else if (tileSet.dataType === 'vector') {
|
||||||
tileUrlTemplate = getVectorTileUrlTemplate(
|
tileUrlTemplate = getVectorTileUrlTemplate(
|
||||||
tileSet.links,
|
tileSet.links,
|
||||||
sourceInfo.mediaType
|
sourceInfo.mediaType,
|
||||||
|
sourceInfo.supportedMediaTypes
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Expected tileset data type to be "map" or "vector"');
|
throw new Error('Expected tileset data type to be "map" or "vector"');
|
||||||
|
|||||||
@@ -143,6 +143,48 @@ describe('ol/source/ogcTileUtil.js', () => {
|
|||||||
'https://maps.ecere.com/ogcapi/collections/NaturalEarth:cultural:ne_10m_admin_0_countries/tiles/WebMercatorQuad/3/1/2.mvt'
|
'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()', () => {
|
describe('getVectorTileUrlTemplate()', () => {
|
||||||
@@ -173,6 +215,15 @@ describe('ol/source/ogcTileUtil.js', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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', () => {
|
it('throws if it cannot find preferred media type or a known fallback', () => {
|
||||||
function call() {
|
function call() {
|
||||||
getVectorTileUrlTemplate([], 'application/vnd.mapbox-vector-tile');
|
getVectorTileUrlTemplate([], 'application/vnd.mapbox-vector-tile');
|
||||||
|
|||||||
Reference in New Issue
Block a user