UNPKG

@geogirafe/lib-geoportal

Version:

GeoGirafe is a flexible application to build online geoportals.

256 lines (255 loc) 9.26 kB
import { getAbsoluteUrl, getWmtsMatrices, getWmtsUrl, MFPVectorEncoder } from '@geoblocks/mapfishprint'; import { toDegrees } from 'ol/math'; import LayerLocalFile from '../../../models/layers/layerlocalfile'; import LayerWms from '../../../models/layers/layerwms'; import LayerWmts from '../../../models/layers/layerwmts'; import VectorLayer from 'ol/layer/Vector'; import { isLayerVisible } from './printUtils'; import VectorSource from 'ol/source/Vector'; /** * Class representing a Mapfish Print Encoder. */ export default class MFPEncoder { constructor() { Object.defineProperty(this, "printResolution", { enumerable: true, configurable: true, writable: true, value: 100 }); Object.defineProperty(this, "options", { enumerable: true, configurable: true, writable: true, value: void 0 }); } /** * Sets the options for encoding the map. */ setOptions(options) { this.options = options; } /** * Encodes the map options, notably the map state and the ol map into a top-level MFPMap object. * @returns A Promise that resolves with the encoded map object. */ encodeMap(options) { this.setOptions(options); const mapManager = options.mapManager; const view = mapManager.getMap().getView(); const center = view.getCenter() ?? [0, 0]; const projection = view.getProjection().getCode(); const rotation = toDegrees(view.getRotation()); this.printResolution = view.getResolution() || 100; const allLayers = this.getAllLayers(options.state); const mfpLayers = this.encodeLayers(allLayers); mfpLayers.unshift(...this.encodeSpecialLayers(mapManager, options.customizer)); return { center, dpi: options.dpi, projection, rotation, scale: options.scale, layers: mfpLayers, useNearestScale: false }; } /** * @returns An array of all active layers from the state object in the right order */ getAllLayers(state) { // Sort layers from layertree const treeLayers = this.getFlatLayers(state.layers.layersList).filter((layer) => layer.active); const sortedLayers = [...treeLayers].sort((a, b) => a.order - b.order); // But basemaps are always at the bottom const baseMap = state.activeBasemap?.layersList ?? []; return [...sortedLayers, ...baseMap]; } /** * @returns The flattened array of base layers. */ getFlatLayers(baseLayers) { return baseLayers.reduce((layers, layer) => { if (layer.children) { const resultLayers = this.getFlatLayers(layer.children); layers.push(...resultLayers); } else { layers.push(layer); } return layers; }, []); } /** * Encode special layers, meaning not-in-the-layer-tree layers. * These layers are from the mapManager.getLayersToPrint method. * @returns An array of encodedlayers. */ encodeSpecialLayers(mapManager, customizer) { const encoded = [...mapManager.getLayersToPrint()] .sort((olayerA, olayerB) => { const indexA = olayerA.getZIndex() ?? 0; const indexB = olayerB.getZIndex() ?? 0; return indexB - indexA; }) .map((olayer) => { if (olayer instanceof VectorLayer) { return new MFPVectorEncoder(olayer.getLayerState(), customizer).encodeVectorLayer(this.printResolution); } return null; }); return encoded.filter((spec) => spec !== null); } /** * Encode layers recursively. * @returns a list of Mapfish print layer specs for the given layers. */ encodeLayers(baseLayers) { const mfpLayers = []; for (const layer of baseLayers) { const spec = this.encodeLayer(layer); if (spec) { if (Array.isArray(spec)) { mfpLayers.push(...spec); } else { mfpLayers.push(spec); } } } return mfpLayers; } /** * Encodes a layer object according to it's className and options. * @returns A promise that resolves to an array of MFP layers, a single MFP layer, or null. */ encodeLayer(layer) { if (layer.className === LayerWms.name) { return this.encodeImageLayer(layer); } if (layer.className === LayerWmts.name) { return this.encodeTileWmtsLayer(layer); } if (layer.className === LayerLocalFile.name) { return this.encodeLocalFileLayer(layer); } return null; } /** * Encodes an image layer from a WMS layer object. * @returns The encoded image layer or null if the layer is not visible. */ encodeImageLayer(layerWms) { if (!isLayerVisible(layerWms, this.options?.printResolution)) { return null; } let url = layerWms.ogcServer.url; if (layerWms.ogcServer.url.startsWith('//')) { url = window.location.protocol + url; } const url_url = new URL(url); const customParams = { TRANSPARENT: 'true' }; if (url_url.searchParams) { url_url.searchParams.forEach((value, key) => { customParams[key] = value; }); } const ogcServer = this.options?.state.ogcServers[layerWms.ogcServer.name]; let serverType = ogcServer?.type; if (serverType === 'arcgis') { serverType = undefined; } const layers = layerWms.layers?.split(',') ?? ['']; // Add empty styles if needed let styles = layerWms.style?.split(','); if (!styles) { styles = ['']; } // Get the same amount of styles than layers to print while (layers.length > styles.length) { styles.push(''); } const object = { baseURL: getAbsoluteUrl(url_url.origin + url_url.pathname), imageFormat: layerWms.ogcServer.imageType ?? 'image/png', layers: layers, customParams: customParams, serverType: serverType, type: 'wms', opacity: layerWms.opacity, useNativeAngle: layerWms.printNativeAngle, styles: styles }; return object; } /** * Encodes a WMTS layer into a MFPWmtsLayer or MFPImageLayer object. * @returns The encoded layer object, or null if the layer is not visible. */ encodeTileWmtsLayer(layerWmts) { if (!isLayerVisible(layerWmts, this.options?.printResolution)) { return null; } if (layerWmts.printLayers || layerWmts.wmsLayers) { // Print configured wms layer instead. const spec = this.encodeWmsFromWmtsLayer(layerWmts); if (spec) { return spec; } } const oLayer = layerWmts._olayer; const source = oLayer?.getSource(); if (!oLayer || !source) { console.warn('Can not encode tile layer: ', layerWmts); return null; } const dimensionParams = source.getDimensions(); const dimensions = Object.keys(dimensionParams); return { baseURL: getWmtsUrl(source), dimensions, dimensionParams, imageFormat: source.getFormat(), layer: source.getLayer(), matrices: getWmtsMatrices(source), matrixSet: source.getMatrixSet(), name: layerWmts.name, opacity: layerWmts.opacity, requestEncoding: source.getRequestEncoding(), style: source.getStyle(), type: 'wmts', version: source.getVersion() }; } /** * Encodes a local file layer. * @returns The encoded local file layer or null if the layer is not visible. */ encodeLocalFileLayer(layer) { const vectorSource = new VectorSource({ features: layer._features }); const olayer = new VectorLayer({ source: vectorSource }); if (!this.options?.customizer) { return null; } return new MFPVectorEncoder(olayer.getLayerState(), this.options.customizer).encodeVectorLayer(this.printResolution); } /** * Encodes a WMS layer from a WMTS layer. * @returns The encoded WMS layer or null if the ogcServer is missing. */ encodeWmsFromWmtsLayer(layerWmts) { if (!layerWmts.ogcServer) { console.error('Missing ogcServer'); return null; } const printLayers = layerWmts.printLayers ?? layerWmts.wmsLayers ?? ''; const layerWms = new LayerWms(0, printLayers, 0, layerWmts.ogcServer, { layers: printLayers }); layerWms.opacity = layerWmts.opacity; return this.encodeImageLayer(layerWms); } }