diff --git a/app-starter/static/app-conf.json b/app-starter/static/app-conf.json
index 1b7bca7b..90bdf8a3 100644
--- a/app-starter/static/app-conf.json
+++ b/app-starter/static/app-conf.json
@@ -50,6 +50,21 @@
"history": true
},
+ "tileGridDefs": {
+ "usgs": {
+ "type": "WMTS",
+ "origin": [ -20037508.342789244, 20037508.342789244 ],
+ "resolutions": [156543.03,78271.51,39135.75,19567.87,9783.93,4891.96,2445.984,1222.99,611.49,305.748,152.87,76.437,38.218,19.109,9.55,4.77,2.388,1.194,0.595],
+ "matrixIds": [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
+ },
+ "ignfr": {
+ "type": "WMTS",
+ "origin": [ -20037508.342789244, 20037508.342789244 ],
+ "resolutions": [156543.03392804097,78271.51696402048,39135.75848201024,19567.87924100512,9783.93962050256,4891.96981025128,2445.98490512564,1222.99245256282,611.49622628141,305.748113140705,152.8740565703525,76.43702828517625,38.21851414258813,19.109257071294063,9.554628535647032,4.777314267823516,2.388657133911758,1.194328566955879,0.5971642834779395,0.29858214173896974],
+ "matrixIds": ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19"]
+ }
+ },
+
"mapLayers": [
{
@@ -145,6 +160,49 @@
"fillColor": "rgb(255, 255, 0, 0.2)"
}
},
+ {
+ "type": "WMTS",
+ "name": "USGS demo",
+ "format": "image/png",
+ "url": "https://mrdata.usgs.gov/mapcache/wmts",
+ "lid": "usgs_demo",
+ "isBaseLayer": false,
+ "layers": "",
+ "projection": "EPSG:3857",
+ "layer": "sgmc2",
+ "matrixSet": "GoogleMapsCompatible",
+ "attributions": "Tiles © USGS",
+ "tileGridRef": "usgs",
+ "style": "default",
+ "wrapX": true
+ },
+ {
+ "type": "WMTS",
+ "name": "IGN Plan",
+ "format": "image/png",
+ "url": "https://wxs.ign.fr/choisirgeoportail/geoportail/wmts",
+ "lid": "ign_demo",
+ "isBaseLayer": true,
+ "projection": "EPSG:3857",
+ "layer": "GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2",
+ "matrixSet": "PM",
+ "attributions": "Basemap © '
",
+ "tileGridRef": "ignfr",
+ "style": "normal"
+ },
+ {
+ "type": "WMTS",
+ "name": "RV_DTM",
+ "lid": "rv-dtm",
+ "optionsFromCapabilities": {
+ "url": "https://idt2.regione.veneto.it/gwc/service/wmts?request=GetCapabilities",
+ "layer": "rv:DTM_RV_5m_3003",
+ "format": "image/png",
+ "matrixSet": "EPSG:4326",
+ "crossOrigin": "anonymous"
+ },
+ "attributions": "DTM © 2024 Regione del Veneto"
+ },
{
"type": "TILEWMS",
"lid": "ahocevar-wms",
diff --git a/docs/map-layer-configuration.md b/docs/map-layer-configuration.md
index 3b460b4a..83c45f12 100644
--- a/docs/map-layer-configuration.md
+++ b/docs/map-layer-configuration.md
@@ -112,6 +112,24 @@ Similar properties as Tiled WMS, with these exceptions:
| interpolate | By default, linear interpolation is used when resampling. Set to false to use the nearest neighbor instead. | `"interpolate": false` |
| tileGridRef | Parameter is not used for `IMAGEWMS` | |
+## WMTS (tiled)
+
+| Property | Meaning (from Openlayers [API docs](https://openlayers.org/en/latest/apidoc/module-ol_source_WMTS.html)) | Example |
+|--------------------|:----------|---------|
+| **type** | Indicator that the layer is a WMTS, use `WMTS` | `"type": "WMTS"` |
+| **layer** | Layer name as advertised in the WMTS capabilities. | `"layer": "sgmc2"` |
+| **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. | `"url": "https://mrdata.usgs.gov/mapcache/wmts"` |
+| projection | The projection of the layer. Has to be defined in `projectionDefs` if not `EPSG:4326` or `EPSG:3857`. if not set the projection of the map is used | `"projection": "EPSG:3857"` |
+| format | Image format. Only used when requestEncoding is 'KVP' | `"format": "image/png"` |
+| transparent | Boolean value, whether the WMS layer should be queried with a transparent background | `"transparent": true` |
+| tileGridRef | Identifier of the tile grid to use for this layer (has to be defined in `tileGridDefs`) The grid has to be correctly identified with `"type": "WMTS"` | `"tileGridRef": "usgs"` |
+| crossOrigin | Provides support for CORS, defining how the layers source handles crossorigin requests. For more information and the supported values see [HTML attribute: crossorigin](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin) | `"crossOrigin": "anonymous"` |
+| cacheSize, interpolate, reprojectionErrorThreshold, tilePixelRatio, version, matrixSet, urls, wrapX, transition, zDirection | The module wraps ol/source/WMTS layer options: https://openlayers.org/en/latest/apidoc/module-ol_source_WMTS.html | `"cacheSize": 16` |
+| optionsFromCapabilities | In WMTS layers options can be retrieved parsing the service capabilities document, the option is an object containing at least the following keys: `url`, `layer`, `matrixSet` or `projection` | `"optionsFromCapabilities": {"url": "https://idt2.regione.veneto.it/gwc/service/wmts?request=GetCapabilities", "layer": "rv:DTM_RV_5m_3003", "matrixSet": "EPSG:4326"}` |
+| hoverAttribute | Attribute to be shown if a feature of the layer is hovered. Only has an effect if `hoverable` is set to `true`. | `"hoverAttribute": "name"` |
+| hoverOverlay | ID of a custom map overlay to display when a feature of the layer is hovered. Only has an effect if `hoverable` is set to `true`. For more information on how to implement a map overlay see the [reusable components](reusable-components?id=map-overlay) section. | `"hoverOverlay": "my-custom-overlay"` |
+| params | This allows to inject custom HTTP parameters to the GetMap request of the layer. | `"params": {"FEATUREID": 1}"` |
+
## XYZ
diff --git a/src/components/ol/Map.vue b/src/components/ol/Map.vue
index 86dc6e5e..ec7aff90 100644
--- a/src/components/ol/Map.vue
+++ b/src/components/ol/Map.vue
@@ -16,6 +16,7 @@ import {
import RotateControl from 'ol/control/Rotate';
import Projection from 'ol/proj/Projection';
import TileGrid from 'ol/tilegrid/TileGrid';
+import WMTSTileGrid from 'ol/tilegrid/WMTS.js';
import { register as olproj4 } from 'ol/proj/proj4';
import { get as getProj } from 'ol/proj';
import { GPX, GeoJSON, IGC, KML, TopoJSON } from 'ol/format';
@@ -163,7 +164,7 @@ export default {
// Optional TileGrid definitions by name, for ref in Layers
Object.keys(this.tileGridDefs).forEach(name => {
- this.tileGrids[name] = new TileGrid(this.tileGridDefs[name]);
+ this.tileGrids[name] = this.tileGridDefs[name].type === 'WMTS' ? new WMTSTileGrid(this.tileGridDefs[name]) : new TileGrid(this.tileGridDefs[name]);
});
this.map = new Map({
@@ -207,7 +208,6 @@ export default {
// Remarks: Passing null instead of undefined as parameters into the
// constructor of OpenLayers sources overwrites OpenLayers defaults.
lConf.tileGrid = lConf.tileGridRef ? me.tileGrids[lConf.tileGridRef] : undefined;
-
// Automatically set the appropriate z-index for the layer type,
// if not defined explicitly.
lConf.zIndex = lConf.zIndex ?? (lConf.isBaseLayer ? -1 : 0);
diff --git a/src/factory/Layer.js b/src/factory/Layer.js
index 20fdb5ea..0aef4b7a 100644
--- a/src/factory/Layer.js
+++ b/src/factory/Layer.js
@@ -1,6 +1,8 @@
import { Image as ImageLayer, Tile as TileLayer } from 'ol/layer';
import ImageWMS from 'ol/source/ImageWMS';
import TileWmsSource from 'ol/source/TileWMS';
+import WMTS, { optionsFromCapabilities } from 'ol/source/WMTS.js';
+import WMTSCapabilities from 'ol/format/WMTSCapabilities.js';
import OsmSource from 'ol/source/OSM';
import VectorTileLayer from 'ol/layer/VectorTile'
import VectorTileSource from 'ol/source/VectorTile'
@@ -65,6 +67,8 @@ export const LayerFactory = {
return this.createTileWmsLayer(lConf);
} else if (lConf.type === 'IMAGEWMS') {
return this.createImageWmsLayer(lConf);
+ } else if (lConf.type === 'WMTS') {
+ return this.createTileWmtsLayer(lConf);
} else if (lConf.type === 'WFS') {
return this.createWfsLayer(lConf, olMap);
} else if (lConf.type === 'XYZ') {
@@ -165,6 +169,74 @@ export const LayerFactory = {
return layer;
},
+ /**
+ * Returns an OpenLayers Tiled WMTS layer instance due to given config.
+ *
+ * @param {Object} lConf Layer config object
+ * @return {ol.layer.Tile} OL Tiled WMTS layer instance
+ */
+ createTileWmtsLayer (lConf) {
+ // apply additional HTTP params
+
+ const WMTSlayer = new TileLayer({
+ ...this.getCommonLayerOptions(lConf),
+ source: new TileWmsSource({ // fake source, will be replaced
+ url: ''
+ })
+ })
+
+ if (lConf.optionsFromCapabilities) {
+ const parser = new WMTSCapabilities();
+
+ fetch(lConf.optionsFromCapabilities.url).then(function (response) {
+ return response.text();
+ }).then(function (text) {
+ const capabilities = parser.read(text);
+ const options = optionsFromCapabilities(capabilities, {
+ layer: lConf.optionsFromCapabilities.layer,
+ matrixSet: lConf.optionsFromCapabilities.matrixSet,
+ projection: lConf.optionsFromCapabilities.projection,
+ requestEncoding: lConf.optionsFromCapabilities.requestEncoding,
+ style: lConf.optionsFromCapabilities.style,
+ format: lConf.optionsFromCapabilities.format,
+ crossOrigin: lConf.optionsFromCapabilities.crossOrigin
+ })
+ const Source = new WMTS({
+ ...options,
+ attributions: lConf.attributions,
+ hoverable: lConf.hoverable,
+ hoverAttribute: lConf.hoverAttribute,
+ hoverOverlay: lConf.hoverOverlay
+ })
+ WMTSlayer.setSource(Source)
+ });
+ } else {
+ WMTSlayer.setSource(new WMTS({
+ url: lConf.url,
+ tileGrid: lConf.tileGrid,
+ cacheSize: lConf.cacheSize,
+ interpolate: lConf.interpolate,
+ reprojectionErrorThreshold: lConf.reprojectionErrorThreshold,
+ projection: lConf.projection,
+ crossOrigin: lConf.crossOrigin,
+ layer: lConf.layer,
+ style: lConf.style,
+ tilePixelRatio: lConf.tilePixelRatio,
+ format: lConf.format,
+ version: lConf.version,
+ matrixSet: lConf.matrixSet,
+ urls: lConf.urls,
+ wrapX: lConf.wrapX,
+ transition: lConf.transition,
+ zDirection: lConf.zDirection,
+ hoverable: lConf.hoverable,
+ hoverAttribute: lConf.hoverAttribute,
+ hoverOverlay: lConf.hoverOverlay
+ }))
+ }
+ return WMTSlayer;
+ },
+
/**
* Returns an OpenLayers WFS layer instance due to given config.
*