diff --git a/package.json b/package.json
index d1fd3528b9..0e37065b12 100644
--- a/package.json
+++ b/package.json
@@ -105,6 +105,7 @@
"leaflet-plugins": "https://github.com/Polyconseil/leaflet-plugins/tarball/master",
"leaflet-simple-graticule": "1.0.2",
"leaflet.locatecontrol": "0.45.1",
+ "leaflet.nontiledlayer": "1.0.3",
"lodash": "4.16.6",
"moment": "2.13.0",
"object-assign": "4.1.1",
diff --git a/web/client/components/TOC/fragments/settings/Display.jsx b/web/client/components/TOC/fragments/settings/Display.jsx
index e81441641b..286f7059ce 100644
--- a/web/client/components/TOC/fragments/settings/Display.jsx
+++ b/web/client/components/TOC/fragments/settings/Display.jsx
@@ -49,10 +49,16 @@ module.exports = React.createClass({
{this.props.onChange("transparent", event.target.checked); }}>
this.props.onChange("tiled", e.target.checked)}
checked={this.props.element && this.props.element.tiled !== undefined ? this.props.element.tiled : true} >
+ this.props.onChange("singleTile", e.target.checked)}>
+
+
)] : null}
);
}
diff --git a/web/client/components/TOC/fragments/settings/__tests__/Display-test.jsx b/web/client/components/TOC/fragments/settings/__tests__/Display-test.jsx
index d90b90a48c..60b7004d26 100644
--- a/web/client/components/TOC/fragments/settings/__tests__/Display-test.jsx
+++ b/web/client/components/TOC/fragments/settings/__tests__/Display-test.jsx
@@ -68,7 +68,7 @@ describe('test Layer Properties Display module component', () => {
expect(comp).toExist();
const inputs = ReactTestUtils.scryRenderedDOMComponentsWithTag( comp, "input" );
expect(inputs).toExist();
- expect(inputs.length).toBe(2);
+ expect(inputs.length).toBe(3);
inputs[0].click();
expect(spy.calls.length).toBe(1);
});
diff --git a/web/client/components/map/cesium/Layer.jsx b/web/client/components/map/cesium/Layer.jsx
index cf494d5044..27a0de196c 100644
--- a/web/client/components/map/cesium/Layer.jsx
+++ b/web/client/components/map/cesium/Layer.jsx
@@ -1,5 +1,5 @@
-/**
- * Copyright 2015, GeoSolutions Sas.
+/*
+ * Copyright 2017, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
@@ -19,13 +19,13 @@ const CesiumLayer = React.createClass({
componentDidMount() {
this.createLayer(this.props.type, this.props.options, this.props.position, this.props.map);
if (this.props.options && this.layer && this.props.options.visibility !== false) {
- this.addLayer();
+ this.addLayer(this.props);
this.updateZIndex();
}
},
componentWillReceiveProps(newProps) {
const newVisibility = newProps.options && newProps.options.visibility !== false;
- this.setLayerVisibility(newVisibility);
+ this.setLayerVisibility(newVisibility, newProps);
const newOpacity = (newProps.options && newProps.options.opacity !== undefined) ? newProps.options.opacity : 1.0;
this.setLayerOpacity(newOpacity);
@@ -47,7 +47,7 @@ const CesiumLayer = React.createClass({
const oldProvider = this.provider;
const newLayer = this.layer.updateParams(newProps.options.params);
this.layer = newLayer;
- this.addLayer();
+ this.addLayer(newProps);
setTimeout(() => {
this.removeLayer(oldProvider);
}, 1000);
@@ -106,11 +106,11 @@ const CesiumLayer = React.createClass({
});
}
},
- setLayerVisibility(visibility) {
+ setLayerVisibility(visibility, newProps) {
var oldVisibility = this.props.options && this.props.options.visibility !== false;
if (visibility !== oldVisibility) {
if (visibility) {
- this.addLayer();
+ this.addLayer(newProps);
this.updateZIndex();
} else {
this.removeLayer();
@@ -136,26 +136,28 @@ const CesiumLayer = React.createClass({
updateLayer(newProps, oldProps) {
const newLayer = Layers.updateLayer(newProps.type, this.layer, newProps.options, oldProps.options, this.props.map);
if (newLayer) {
+ this.removeLayer();
this.layer = newLayer;
+ this.addLayer(newProps);
}
},
- addLayerInternal() {
+ addLayerInternal(newProps) {
this.provider = this.props.map.imageryLayers.addImageryProvider(this.layer);
this.provider._position = this.props.position;
- if (this.props.options.opacity) {
- this.provider.alpha = this.props.options.opacity;
+ if (newProps.options.opacity !== undefined) {
+ this.provider.alpha = newProps.options.opacity;
}
},
- addLayer() {
+ addLayer(newProps) {
if (this.layer && !this.layer.detached) {
- this.addLayerInternal();
+ this.addLayerInternal(newProps);
if (this.props.options.refresh && this.layer.updateParams) {
let counter = 0;
this.refreshTimer = setInterval(() => {
const newLayer = this.layer.updateParams(assign({}, this.props.options.params, {_refreshCounter: counter++}));
this.removeLayer();
this.layer = newLayer;
- this.addLayerInternal();
+ this.addLayerInternal(newProps);
}, this.props.options.refresh);
}
}
diff --git a/web/client/components/map/cesium/plugins/TileProviderLayer.js b/web/client/components/map/cesium/plugins/TileProviderLayer.js
index 929e07b952..5115509319 100644
--- a/web/client/components/map/cesium/plugins/TileProviderLayer.js
+++ b/web/client/components/map/cesium/plugins/TileProviderLayer.js
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright 2017, GeoSolutions Sas.
* All rights reserved.
*
@@ -10,7 +10,7 @@ var Layers = require('../../../../utils/cesium/Layers');
var Cesium = require('../../../../libs/cesium');
var TileProvider = require('../../../../utils/TileConfigProvider');
var ConfigUtils = require('../../../../utils/ConfigUtils');
-var {isObject, isArray} = require('lodash');
+const ProxyUtils = require('../../../../utils/ProxyUtils');
function splitUrl(originalUrl) {
let url = originalUrl;
@@ -34,7 +34,7 @@ TileProviderProxy.prototype.getURL = function(resource) {
if (url.indexOf("//") === 0) {
url = location.protocol + url;
}
- return this.proxy + encodeURIComponent(url + queryString);
+ return this.proxy.url + encodeURIComponent(url + queryString);
};
function NoProxy() {
@@ -64,16 +64,7 @@ Layers.registerType('tileprovider', (options) => {
let proxyUrl = ConfigUtils.getProxyUrl({});
let proxy;
if (proxyUrl) {
- let useCORS = [];
- if (isObject(proxyUrl)) {
- useCORS = proxyUrl.useCORS || [];
- proxyUrl = proxyUrl.url;
- }
- if (isArray(url)) {
- url = url[0];
- }
- const isCORS = useCORS.reduce((found, current) => found || url.indexOf(current) === 0, false);
- proxy = !isCORS && proxyUrl;
+ proxy = opt.noCors || ProxyUtils.needProxy(url);
}
const cr = opt.credits;
const credit = cr ? new Cesium.Credit(cr.text, cr.imageUrl, cr.link) : opt.attribution;
@@ -84,6 +75,6 @@ Layers.registerType('tileprovider', (options) => {
maximumLevel: opt.maxZoom,
minimumLevel: opt.minZoom,
credit,
- proxy: proxy && opt.noCors ? new TileProviderProxy(proxyUrl) : new NoProxy()
+ proxy: proxy ? new TileProviderProxy(proxyUrl) : new NoProxy()
});
});
diff --git a/web/client/components/map/cesium/plugins/WMSLayer.js b/web/client/components/map/cesium/plugins/WMSLayer.js
index 5af9dfcec9..b400061a51 100644
--- a/web/client/components/map/cesium/plugins/WMSLayer.js
+++ b/web/client/components/map/cesium/plugins/WMSLayer.js
@@ -1,5 +1,5 @@
/*
- * Copyright 2015, GeoSolutions Sas.
+ * Copyright 2017, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
@@ -12,6 +12,7 @@ const ProxyUtils = require('../../../../utils/ProxyUtils');
const Cesium = require('../../../../libs/cesium');
const assign = require('object-assign');
const {isArray} = require('lodash');
+const WMSUtils = require('../../../../utils/cesium/WMSUtils');
function getWMSURLs( urls ) {
return urls.map((url) => url.split("\?")[0]);
@@ -37,7 +38,7 @@ function WMSProxy(proxy) {
WMSProxy.prototype.getURL = function(resource) {
let {url, queryString} = splitUrl(resource);
- return this.proxy + encodeURIComponent(url + queryString);
+ return this.proxy.url + encodeURIComponent(url + queryString);
};
function NoProxy() {
@@ -111,5 +112,21 @@ const createLayer = (options) => {
};
return layer;
};
-
-Layers.registerType('wms', createLayer);
+const updateLayer = (layer, newOptions, oldOptions) => {
+ const requiresUpdate = (el) => WMSUtils.PARAM_OPTIONS.indexOf(el.toLowerCase()) >= 0;
+ const newParams = (newOptions && newOptions.params);
+ const oldParams = (oldOptions && oldOptions.params);
+ const allParams = {...newParams, ...oldParams };
+ let newParameters = Object.keys({...newOptions, ...oldOptions, ...allParams})
+ .filter(requiresUpdate)
+ .filter((key) => {
+ const oldOption = oldOptions[key] === undefined ? oldParams && oldParams[key] : oldOptions[key];
+ const newOption = newOptions[key] === undefined ? newParams && newParams[key] : newOptions[key];
+ return oldOption !== newOption;
+ });
+ if (newParameters.length > 0) {
+ return createLayer(newOptions);
+ }
+ return null;
+};
+Layers.registerType('wms', {create: createLayer, update: updateLayer});
diff --git a/web/client/components/map/leaflet/Layer.jsx b/web/client/components/map/leaflet/Layer.jsx
index b8f08a214d..f2b89f7c79 100644
--- a/web/client/components/map/leaflet/Layer.jsx
+++ b/web/client/components/map/leaflet/Layer.jsx
@@ -134,7 +134,13 @@ const LeafletLayer = React.createClass({
}
},
updateLayer(newProps, oldProps) {
- Layers.updateLayer(newProps.type, this.layer, this.generateOpts(newProps.options, newProps.position), this.generateOpts(oldProps.options, oldProps.position));
+ const newLayer = Layers.updateLayer(newProps.type, this.layer, this.generateOpts(newProps.options, newProps.position),
+ this.generateOpts(oldProps.options, oldProps.position));
+ if (newLayer) {
+ this.removeLayer();
+ this.layer = newLayer;
+ this.addLayer();
+ }
},
addLayer() {
if (this.isValid()) {
diff --git a/web/client/components/map/leaflet/plugins/WMSLayer.js b/web/client/components/map/leaflet/plugins/WMSLayer.js
index 74ec6034d5..8c4a9eb5b4 100644
--- a/web/client/components/map/leaflet/plugins/WMSLayer.js
+++ b/web/client/components/map/leaflet/plugins/WMSLayer.js
@@ -1,5 +1,5 @@
-/**
- * Copyright 2015, GeoSolutions Sas.
+/*
+ * Copyright 2017, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
@@ -13,6 +13,7 @@ const L = require('leaflet');
const objectAssign = require('object-assign');
const {isArray, isEqual} = require('lodash');
const SecurityUtils = require('../../../../utils/SecurityUtils');
+require('leaflet.nontiledlayer');
L.TileLayer.MultipleUrlWMS = L.TileLayer.WMS.extend({
@@ -42,7 +43,6 @@ L.TileLayer.MultipleUrlWMS = L.TileLayer.WMS.extend({
L.setOptions(this, options);
},
-
getTileUrl: function(tilePoint) { // (Point, Number) -> String
let map = this._map;
let tileSize = this.options.tileSize;
@@ -79,6 +79,7 @@ function wmsToLeafletOptions(options) {
transparent: options.transparent !== undefined ? options.transparent : true,
tiled: options.tiled !== undefined ? options.tiled : true,
opacity: opacity,
+ zIndex: options.zIndex,
version: options.version || "1.3.0",
SRS: CoordinatesUtils.normalizeSRS(options.srs || 'EPSG:3857', options.allowedSRS),
CRS: CoordinatesUtils.normalizeSRS(options.srs || 'EPSG:3857', options.allowedSRS),
@@ -95,6 +96,9 @@ Layers.registerType('wms', {
const urls = getWMSURLs(isArray(options.url) ? options.url : [options.url]);
const queryParameters = wmsToLeafletOptions(options) || {};
urls.forEach(url => SecurityUtils.addAuthenticationParameter(url, queryParameters));
+ if (options.singleTile) {
+ return L.nonTiledLayer.wms(urls[0], queryParameters);
+ }
return L.tileLayer.multipleUrlWMS(urls, queryParameters);
},
update: function(layer, newOptions, oldOptions) {
@@ -103,12 +107,36 @@ Layers.registerType('wms', {
let newQueryParameters = WMSUtils.filterWMSParamOptions(wmsToLeafletOptions(newOptions));
let newParameters = Object.keys(newQueryParameters).filter((key) => {return newQueryParameters[key] !== oldqueryParameters[key]; });
let newParams = {};
+ let newLayer;
+ if (oldOptions.singleTile !== newOptions.singleTile) {
+ const urls = getWMSURLs(isArray(newOptions.url) ? newOptions.url : [newOptions.url]);
+ urls.forEach(url => SecurityUtils.addAuthenticationParameter(url, newQueryParameters));
+ if (newOptions.singleTile) {
+ // return the nonTiledLayer
+ newLayer = L.nonTiledLayer.wms(urls[0], newQueryParameters);
+ } else {
+ newLayer = L.tileLayer.multipleUrlWMS(urls, newQueryParameters);
+ }
+ if ( newParameters.length > 0 ) {
+ newParams = newParameters.reduce( (accumulator, currentValue) => {
+ return objectAssign({}, accumulator, {[currentValue]: newQueryParameters[currentValue] });
+ }, newParams);
+ // set new options as parameters, merged with params
+ newLayer.setParams(objectAssign(newParams, newParams.params, newOptions.params));
+ } else if (!isEqual(newOptions.params, oldOptions.params)) {
+ newLayer.setParams(newOptions.params);
+ }
+ return newLayer;
+ }
if ( newParameters.length > 0 ) {
- newParameters.forEach( key => newParams[key] = newQueryParameters[key] );
+ newParams = newParameters.reduce( (accumulator, currentValue) => {
+ return objectAssign({}, accumulator, {[currentValue]: newQueryParameters[currentValue] });
+ }, newParams);
// set new options as parameters, merged with params
layer.setParams(objectAssign(newParams, newParams.params, newOptions.params));
} else if (!isEqual(newOptions.params, oldOptions.params)) {
layer.setParams(newOptions.params);
}
+ return null;
}
});
diff --git a/web/client/components/map/openlayers/Layer.jsx b/web/client/components/map/openlayers/Layer.jsx
index c9f36421f6..7da08c9776 100644
--- a/web/client/components/map/openlayers/Layer.jsx
+++ b/web/client/components/map/openlayers/Layer.jsx
@@ -121,13 +121,18 @@ const OpenlayersLayer = React.createClass({
return;
}
}
- Layers.updateLayer(
+ const newLayer = Layers.updateLayer(
this.props.type,
this.layer,
this.generateOpts(newProps.options, newProps.position, newProps.projection),
this.generateOpts(oldProps.options, oldProps.position, oldProps.projection),
this.props.map,
this.props.mapId);
+ if (newLayer) {
+ this.props.map.removeLayer(this.layer);
+ this.layer = newLayer;
+ this.addLayer(newProps.options);
+ }
},
addLayer(options) {
if (this.isValid()) {
diff --git a/web/client/components/map/openlayers/plugins/WMSLayer.js b/web/client/components/map/openlayers/plugins/WMSLayer.js
index 6ceeca0737..f1aa5fcb74 100644
--- a/web/client/components/map/openlayers/plugins/WMSLayer.js
+++ b/web/client/components/map/openlayers/plugins/WMSLayer.js
@@ -1,5 +1,5 @@
-/**
- * Copyright 2015, GeoSolutions Sas.
+/*
+ * Copyright 2017, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
@@ -77,7 +77,7 @@ Layers.registerType('wms', {
}, (options.forceProxy) ? {tileLoadFunction: proxyTileLoadFunction} : {}))
});
},
- update: (layer, newOptions, oldOptions) => {
+ update: (layer, newOptions, oldOptions, map) => {
if (oldOptions && layer && layer.getSource() && layer.getSource().updateParams) {
let changed = false;
if (oldOptions.params && newOptions.params) {
@@ -110,6 +110,45 @@ Layers.registerType('wms', {
if (changed) {
layer.getSource().updateParams(objectAssign(newParams, newOptions.params));
}
+ if (oldOptions.singleTile !== newOptions.singleTile) {
+ const urls = getWMSURLs(isArray(newOptions.url) ? newOptions.url : [newOptions.url]);
+ const queryParameters = wmsToOpenlayersOptions(newOptions) || {};
+ urls.forEach(url => SecurityUtils.addAuthenticationParameter(url, queryParameters));
+ let newLayer;
+ if (newOptions.singleTile) {
+ // return the Image Layer with the related source
+ newLayer = new ol.layer.Image({
+ opacity: newOptions.opacity !== undefined ? newOptions.opacity : 1,
+ visible: newOptions.visibility !== false,
+ zIndex: newOptions.zIndex,
+ source: new ol.source.ImageWMS({
+ url: urls[0],
+ params: queryParameters
+ })
+ });
+ } else {
+ // return the Tile Layer with the related source
+ const mapSrs = map && map.getView() && map.getView().getProjection() && map.getView().getProjection().getCode() || 'EPSG:3857';
+ const extent = ol.proj.get(CoordinatesUtils.normalizeSRS(newOptions.srs || mapSrs, newOptions.allowedSRS)).getExtent();
+ newLayer = new ol.layer.Tile({
+ opacity: newOptions.opacity !== undefined ? newOptions.opacity : 1,
+ visible: newOptions.visibility !== false,
+ zIndex: newOptions.zIndex,
+ source: new ol.source.TileWMS(objectAssign({
+ urls: urls,
+ params: queryParameters,
+ tileGrid: new ol.tilegrid.TileGrid({
+ extent: extent,
+ resolutions: mapUtils.getResolutions(),
+ tileSize: newOptions.tileSize ? newOptions.tileSize : 256,
+ origin: newOptions.origin ? newOptions.origin : [extent[0], extent[1]]
+ })
+ }, (newOptions.forceProxy) ? {tileLoadFunction: proxyTileLoadFunction} : {}))
+ });
+ }
+ return newLayer;
+ }
+ return null;
}
}
});
diff --git a/web/client/translations/data.de-DE b/web/client/translations/data.de-DE
index 097b527add..01df880190 100644
--- a/web/client/translations/data.de-DE
+++ b/web/client/translations/data.de-DE
@@ -30,6 +30,7 @@
"display": "Darstellung",
"style": "Stil",
"transparent": "Transparent",
+ "singleTile": "Single Tile",
"cached": "Verwenden Sie Cache-Optionen",
"styleCustom": "Stil \"{value}\" nutzen",
"styleListLoadError": "Es gab einen Fehler beim Laden der Liste von Stilen",
diff --git a/web/client/translations/data.en-US b/web/client/translations/data.en-US
index 35bfcc02d6..ce11eb37fb 100644
--- a/web/client/translations/data.en-US
+++ b/web/client/translations/data.en-US
@@ -30,6 +30,7 @@
"display": "Display",
"style": "Style",
"transparent": "Transparent",
+ "singleTile": "Single Tile",
"cached": "Use cache options",
"styleCustom": "Use style named \"{value}\"",
"styleListLoadError": "There was an error loading the styles list",
diff --git a/web/client/translations/data.fr-FR b/web/client/translations/data.fr-FR
index 734842f9e8..9fb8b1e6c9 100644
--- a/web/client/translations/data.fr-FR
+++ b/web/client/translations/data.fr-FR
@@ -30,6 +30,7 @@
"display": "Affichage",
"style": "Style",
"transparent": "Transparent",
+ "singleTile": "Single Tile",
"cached": "Utiliser les options de cache",
"styleCustom": "Utilisez un style nommé \"{value} \"",
"styleListLoadError": "Une erreur s'est produite lors du chargement de la liste de styles",
diff --git a/web/client/translations/data.it-IT b/web/client/translations/data.it-IT
index 07efd849cd..31afee639c 100644
--- a/web/client/translations/data.it-IT
+++ b/web/client/translations/data.it-IT
@@ -30,6 +30,7 @@
"display": "Visualizzazione",
"style": "Stile",
"transparent": "Trasparenza",
+ "singleTile": "Single Tile",
"cached": "Usa la cache",
"styleCustom": "Usa stile con nome \"{value}\"",
"styleListLoadError": "Si è verificato un errore durante il caricamento della lista degli stili",
diff --git a/web/client/utils/cesium/Layers.js b/web/client/utils/cesium/Layers.js
index 20af4b3236..068793115d 100644
--- a/web/client/utils/cesium/Layers.js
+++ b/web/client/utils/cesium/Layers.js
@@ -1,5 +1,5 @@
-/**
- * Copyright 2015, GeoSolutions Sas.
+/*
+ * Copyright 2017, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
@@ -37,7 +37,6 @@ var Layers = {
if (layerCreator && layerCreator.update) {
return layerCreator.update(layer, newOptions, oldOptions, map);
}
-
}
};
diff --git a/web/client/utils/cesium/WMSUtils.js b/web/client/utils/cesium/WMSUtils.js
new file mode 100644
index 0000000000..5b5c15e25d
--- /dev/null
+++ b/web/client/utils/cesium/WMSUtils.js
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2017, GeoSolutions Sas.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+const WMSUtils = {
+ PARAM_OPTIONS: ["layers", "styles", "style", "format", "transparent", "version", "tiled", "opacity", "zindex", "srs", "singletile" ]
+};
+
+module.exports = WMSUtils;
diff --git a/web/client/utils/leaflet/WMSUtils.js b/web/client/utils/leaflet/WMSUtils.js
index 7698bd7ea4..c5792ee9c1 100644
--- a/web/client/utils/leaflet/WMSUtils.js
+++ b/web/client/utils/leaflet/WMSUtils.js
@@ -1,5 +1,5 @@
-/**
- * Copyright 2016, GeoSolutions Sas.
+/*
+ * Copyright 2017, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
@@ -8,7 +8,7 @@
var objectAssign = require('object-assign');
var WMSUtils = {
- PARAM_OPTIONS: ["layers", "styles", "format", "transparent", "version", "tiled" ],
+ PARAM_OPTIONS: ["layers", "styles", "format", "transparent", "version", "tiled", "opacity", "zindex" ],
wmsToLeafletOptions: function(options) {
var opacity = options.opacity !== undefined ? options.opacity : 1;
// NOTE: can we use opacity to manage visibility?