diff --git a/web/client/utils/PrintUtils.js b/web/client/utils/PrintUtils.js index 1af84bc825..9350dcba0c 100644 --- a/web/client/utils/PrintUtils.js +++ b/web/client/utils/PrintUtils.js @@ -12,11 +12,12 @@ const MapUtils = require('./MapUtils'); const {optionsToVendorParams} = require('./VendorParamsUtils'); const AnnotationsUtils = require("./AnnotationsUtils"); const {colorToHexStr} = require("./ColorUtils"); +const {getLayerConfig} = require('./TileConfigProvider').default; +const {get} = require("ol/proj"); +const {isArray, filter, find, isEmpty, toNumber, random} = require('lodash'); const { getFeature } = require('../api/WFS'); const {generateEnvString} = require('./LayerLocalizationUtils'); -const {isArray, filter, find} = require('lodash'); - const url = require('url'); const defaultScales = MapUtils.getGoogleMercatorScales(0, 21); @@ -414,8 +415,72 @@ const PrintUtils = { 0.5971642833948135 ] }) + }, + wmts: { + map: (layer) => ({ + "baseURL": layer.capabilitiesURL, + "dimensions": isEmpty(layer.dimensions) && layer.dimensions || null, + "format": layer.format || "image/png", + "type": "WMTS", + "layer": layer.name, + "customParams ": SecurityUtils.addAuthenticationParameter(layer.capabilitiesURL, assign({ + "TRANSPARENT": true + })), + "matrixIds": PrintUtils.getWMTSMatrixIds(layer), + "matrixSet": CoordinatesUtils.normalizeSRS(layer.srs || 'EPSG:3857', layer.allowedSRS), + "style": layer.style || '', + "name": layer.name, + "requestEncoding": layer.requestEncoding, + "opacity": layer.opacity || 1.0, + "version": layer.version || "1.0.0" + }) + }, + tileprovider: { + map: (layer) => ({ + ...PrintUtils.getTileProviderLayerSpec(layer) + }) } }, + getTileProviderLayerSpec: (layer) => { + const layerConfig = getLayerConfig(layer.provider, layer)[1]; + if (!isEmpty(layerConfig)) { + let baseURL = layerConfig && layerConfig.url; + if (baseURL.indexOf("{s}") > 0) { + const subdomains = layerConfig && layerConfig.subdomains; + baseURL = baseURL.replace("{s}", typeof subdomains === "string" ? subdomains : subdomains[random(0, subdomains.length - 1)]); + } + return { + "baseURL": baseURL.indexOf('{z}') > 0 ? baseURL.substring(0, baseURL.indexOf('{z}') - 1) : baseURL, + "type": 'xyz', + "maxExtent": [-20037508.3392, -20037508.3392, 20037508.3392, 20037508.3392], + "tileSize": [256, 256], + "resolutions": MapUtils.getResolutions(), + "extension": baseURL.split('.').pop() || "png", + "opacity": 1 + }; + } + return {}; + }, + getWMTSMatrixIds: (layer) => { + let modifiedTileMatrixSet = []; + const srs = CoordinatesUtils.normalizeSRS(layer.srs || 'EPSG:3857', layer.allowedSRS); + const projection = get(srs); + const identifierText = "ows:Identifier"; + const metersPerUnit = projection.getMetersPerUnit(); + const scaleToResolution = s => s * 0.28E-3 / metersPerUnit; + const [tileMatrixSet] = layer.tileMatrixSet.filter(tile=> tile[identifierText] === srs); + + tileMatrixSet && tileMatrixSet.TileMatrix.map(tileMatrix => { + const identifier = tileMatrix[identifierText]; + const resolution = scaleToResolution(tileMatrix.ScaleDenominator); + const tileSize = [toNumber(tileMatrix.TileWidth), toNumber(tileMatrix.TileHeight)]; + const topLeftCorner = tileMatrix.TopLeftCorner && tileMatrix.TopLeftCorner.split(" ").map(v => toNumber(v)); + const matrixSize = [toNumber(tileMatrix.MatrixWidth), toNumber(tileMatrix.MatrixHeight)]; + + return modifiedTileMatrixSet.push({ identifier, matrixSize, resolution, tileSize, topLeftCorner}); + }); + return modifiedTileMatrixSet; + }, rgbaTorgb: (rgba = "") => { return rgba.indexOf("rgba") !== -1 ? `rgb${rgba.slice(rgba.indexOf("("), rgba.lastIndexOf(","))})` : rgba; }, diff --git a/web/client/utils/__tests__/PrintUtils-test.js b/web/client/utils/__tests__/PrintUtils-test.js index 3e2fbee79e..6e255a0a52 100644 --- a/web/client/utils/__tests__/PrintUtils-test.js +++ b/web/client/utils/__tests__/PrintUtils-test.js @@ -222,6 +222,116 @@ const mapFishVectorLayer = { } }; +const tileProviderLayer = { + "type": "tileprovider", + "visibility": true, + "url": "https://nls-{s}.tileserver.com/nls/{z}/{x}/{y}.jpg", + "title": "NLS_API", + "options": { + "subdomains": [ + "0", + "1", + "2", + "3" + ] + }, + "provider": "custom", + "name": "custom", + "id": "custom__7", + "loading": false, + "previousLoadingError": false, + "loadingError": false +}; +const wmtsLayer = { + "type": "wmts", + "requestEncoding": "KVP", + "style": "poi", + "format": "image/png", + "url": "https://gs-stable.geo-solutions.it/geoserver/gwc/service/wmts", + "capabilitiesURL": "https://gs-stable.geo-solutions.it/geoserver/gwc/service/wmts", + "dimensions": [], + "name": "gs:ny_poi", + "title": "poi", + "matrixIds": { + "EPSG:4326": [ + { + "identifier": "EPSG:4326:0", + "ranges": { + "cols": { + "min": "0", + "max": "0" + }, + "rows": { + "min": "0", + "max": "0" + } + } + } + ] + }, + "description": "poi", + "tileMatrixSet": [ + { + "ows:Identifier": "EPSG:4326", + "ows:SupportedCRS": "urn:ogc:def:crs:EPSG::4326", + "TileMatrix": [ + { + "ows:Identifier": "EPSG:4326:0", + "ScaleDenominator": "2.795411320143589E8", + "TopLeftCorner": "90.0 -180.0", + "TileWidth": "256", + "TileHeight": "256", + "MatrixWidth": "2", + "MatrixHeight": "1" + } + ] + }, + { + "ows:Identifier": "EPSG:900913", + "ows:SupportedCRS": "urn:ogc:def:crs:EPSG::900913", + "TileMatrix": [ + { + "ows:Identifier": "EPSG:900913:0", + "ScaleDenominator": "5.590822639508929E8", + "TopLeftCorner": "-2.003750834E7 2.0037508E7", + "TileWidth": "256", + "TileHeight": "256", + "MatrixWidth": "1", + "MatrixHeight": "1" + }, + { + "ows:Identifier": "EPSG:900913:1", + "ScaleDenominator": "2.7954113197544646E8", + "TopLeftCorner": "-2.003750834E7 2.0037508E7", + "TileWidth": "256", + "TileHeight": "256", + "MatrixWidth": "2", + "MatrixHeight": "2" + } + ] + } + ], + "bbox": { + "crs": "EPSG:4326", + "bounds": { + "minx": "-74.0118315772888", + "miny": "40.70754683896324", + "maxx": "-74.00153046439813", + "maxy": "40.719885123828675" + } + }, + "links": [], + "params": {}, + "allowedSRS": { + "EPSG:4326": true, + "EPSG:900913": true + }, + "id": "gs:ny_poi__8", + "loading": false, + "previousLoadingError": false, + "loadingError": false +}; + const testSpec = { "antiAliasing": true, "iconSize": 24, @@ -448,4 +558,66 @@ describe('PrintUtils', () => { expect(rgb).toExist(); expect(rgb).toBe("rgb(255, 255, 255)"); }); + it('WMTS layer generation for print', () => { + const printSpec = PrintUtils.getMapfishLayersSpecification([wmtsLayer], {projection: "EPSG:900913"}, 'map'); + expect(printSpec.length).toBe(1); + const [spec] = printSpec; + expect(spec.matrixIds).toExist(); + expect(spec.matrixIds[0].identifier).toContain("EPSG:900913"); + expect(spec.matrixSet).toExist(); + expect(spec.matrixSet).toBe("EPSG:900913"); + expect(spec.requestEncoding).toExist(); + expect(spec.requestEncoding).toBe('KVP'); + }); + it('get MatrixIds for WMTS', () => { + const matrixIds = PrintUtils.getWMTSMatrixIds(wmtsLayer); + expect(matrixIds.length > 0).toBe(true); + const [matrixId] = matrixIds; + expect(matrixId.identifier).toExist(); + expect(matrixId.identifier).toContain("EPSG:900913"); + expect(matrixId.matrixSize).toExist(); + expect(matrixId.matrixSize).toEqual([1, 1]); + expect(matrixId.resolution).toExist(); + expect(matrixId.tileSize).toExist(); + expect(matrixId.tileSize).toEqual([256, 256]); + expect(matrixId.topLeftCorner).toExist(); + }); + it('Tile provider layer generation for print', () => { + const printSpec = PrintUtils.getMapfishLayersSpecification([tileProviderLayer], {projection: "EPSG:900913"}, 'map'); + expect(printSpec.length).toBe(1); + const [spec] = printSpec; + expect(spec.baseURL).toNotContain("/{z}/{x}/{y}"); + expect(spec.type).toBe('xyz'); + expect(spec.maxExtent.length > 0).toBe(true); + expect(spec.tileSize).toExist(); + expect(spec.tileSize).toEqual([256, 256]); + expect(spec.resolutions.length > 0).toBe(true); + expect(spec.extension).toEqual("jpg"); + }); + it('get TileProvider layer specification from custom provider', () => { + const customTileProviderLayer = { + url: "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png", + options: {"subdomains": ["0", "1", "2", "3"]}, + provider: "custom" + }; + const tileProviderLayerSpec = PrintUtils.getTileProviderLayerSpec(customTileProviderLayer); + expect(tileProviderLayerSpec.baseURL).toNotContain("/{z}/{x}/{y}"); + expect(tileProviderLayerSpec.tileSize).toExist(); + expect(tileProviderLayerSpec.resolutions.length > 0).toBe(true); + expect(tileProviderLayerSpec.extension).toEqual("png"); + expect(tileProviderLayerSpec.type).toEqual("xyz"); + }); + it('get TileProvider layer specification for existing provider', () => { + const customTileProviderLayer = { + url: "https://tile.opentopomap.org/{z}/{x}/{y}.png", + provider: "Stamen.Watercolor" + }; + const tileProviderLayerSpec = PrintUtils.getTileProviderLayerSpec(customTileProviderLayer); + expect(()=> { throw new URL(tileProviderLayerSpec);}).toExist(); + expect(tileProviderLayerSpec.baseURL).toNotContain("/{z}/{x}/{y}"); + expect(tileProviderLayerSpec.tileSize).toExist(); + expect(tileProviderLayerSpec.resolutions.length > 0).toBe(true); + expect(tileProviderLayerSpec.extension).toEqual("png"); + expect(tileProviderLayerSpec.type).toEqual("xyz"); + }); });