/* eslint-disable @typescript-eslint/ban-ts-comment */ import Browser from '../../core/Browser'; import { extend } from '../../core/util'; import { LayerJSONType } from '../Layer'; import TileLayer, { TileLayerOptionsType } from './TileLayer'; /** * @property options - TileLayer's options * @property [options.service=WMS] - WMS Service * @property options.layers - Comma-separated list of WMS layers to show. * @property [options.styles=''] - Comma-separated list of WMS styles. * @property [options.format=image/jpeg] - WMS image format (use `'image/png'` for layers with transparency). * @property [options.transparent=false] - Is the tile transparent * @property [options.version=1.1.1] - Version of the WMS service to use * @property [options.crs=null] - Coordinate Reference System to use for the WMS requests, defaults to map CRS. Don't change this if you're not sure what it means. * @property [options.uppercase=false] - If `true`, WMS request parameter keys will be uppercase. * @property [options.detectRetina=false] - If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution. * @memberOf WMSTileLayer * @instance */ const options: WMSTileLayerOptionsType = { urlTemplate: '', crs: null, uppercase: false, detectRetina: false }; const defaultWmsParams = { service: 'WMS', request: 'GetMap', layers: '', styles: '', format: 'image/jpeg', transparent: false, version: '1.1.1' }; let wmsExcludeParams: WMSTileLayerOptionsType; /** * @classdesc * Used to display [WMS]{https://en.wikipedia.org/wiki/Web_Map_Service} services as tile layers on the map. Extends [TileLayer]{@link TileLayer}. * Implemented based on Leaflet's TileLayer.WMS. * @category layer * @extends TileLayer * @param id - tile layer's id * @param - options defined in [WMSTileLayer]{@link TileLayer#options} * @example * var layer = new maptalks.WMSTileLayer('wms', { * 'urlTemplate' : 'https://demo.boundlessgeo.com/geoserver/ows', * 'crs' : 'EPSG:3857', * 'layers' : 'ne:ne', * 'styles' : '', * 'version' : '1.3.0', * 'format': 'image/png', * 'transparent' : true, * 'uppercase' : true * }); */ class WMSTileLayer extends TileLayer { wmsParams: WMSTileLayerOptionsType; options: WMSTileLayerOptionsType; //@internal _wmsVersion: number; constructor(id: string, options: WMSTileLayerOptionsType) { super(id); if (!wmsExcludeParams) { wmsExcludeParams = extend({}, this.options); } this.wmsParams = extend({} as WMSTileLayerOptionsType, defaultWmsParams); this._setOptions(options); this.setZIndex(options.zIndex); if (!Browser.proxy) { this._optionsHook(options); } } //in Hook,Reset wmsParams //@internal _optionsHook(options = {}) { for (const p in options) { //clear tilesize cache if (p === 'tileSize') { this._tileSize = null; } if (!(p in wmsExcludeParams)) { this.wmsParams[p] = options[p]; } } const tileSize = this.getTileSize(); this.wmsParams.width = tileSize.width; this.wmsParams.height = tileSize.height; this._wmsVersion = parseFloat(this.wmsParams.version); return this; } onAdd() { const dpr = this.getMap().getDevicePixelRatio(); const r = options.detectRetina ? dpr : 1; this.wmsParams.width *= r; this.wmsParams.height *= r; // @ts-ignore const crs = this.options.crs || this.getMap().getProjection().code; const projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs'; this.wmsParams[projectionKey] = crs; super.onAdd(); } getTileUrl(x: number, y: number, z: number): string { const res = this.getSpatialReference().getResolution(z), tileConfig = this._getTileConfig(), tileExtent = tileConfig.getTilePrjExtent(x, y, res); const max = tileExtent.getMax(), min = tileExtent.getMin(); const bbox = (this._wmsVersion >= 1.3 && (this.wmsParams.crs === 'EPSG:4326' || this.wmsParams.crs === 'EPSG:4490') ? [min.y, min.x, max.y, max.x] : [min.x, min.y, max.x, max.y]).join(','); const url = super.getTileUrl(x, y, z); return url + // @ts-ignore getParamString(this.wmsParams, url, this.options.uppercase) + // @ts-ignore (this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox; } /** * Export the WMSTileLayer's json.
* It can be used to reproduce the instance by [fromJSON]{@link Layer#fromJSON} method * @return layer's JSON */ toJSON(): LayerJSONType { return { 'type': 'WMSTileLayer', 'id': this.getId(), 'options': this.config() }; } /** * Reproduce a WMSTileLayer from layer's JSON. * @param layerJSON - layer's JSON * @return a WMSTileLayer instance * @static * @private * @function */ static fromJSON(layerJSON: { [x: string]: any; }): WMSTileLayer { if (!layerJSON || layerJSON['type'] !== 'WMSTileLayer') { return null; } return new WMSTileLayer(layerJSON['id'], layerJSON['options']); } } WMSTileLayer.registerJSONType('WMSTileLayer'); WMSTileLayer.mergeOptions(options); export default WMSTileLayer; // From Leaflet // Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}` // translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will // be appended at the end. If `uppercase` is `true`, the parameter names will // be uppercased (e.g. `'?A=foo&B=bar'`) export function getParamString(obj: Record, existingUrl: string, uppercase: boolean) { const params = []; for (const i in obj) { params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); } return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); } export type WMSTileLayerOptionsType = TileLayerOptionsType & { service?: string; layers?: string; styles?: string; format?: string; transparent?: boolean; version?: string; crs?: string; uppercase?: boolean; detectRetina?: boolean; width?: number; height?: number; }