Mercurial > gemma
changeset 3678:8f58851927c0
client: make layer factory only return new layer config for individual maps
instead of each time it is invoked. The purpose of the factory was to support multiple maps with individual layers.
But returning a new config each time it is invoked leads to bugs that rely on the layer's state. Now this factory
reuses the same objects it created before, per map.
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Mon, 17 Jun 2019 17:31:35 +0200 |
parents | 24fafb86b528 |
children | 0227670dedd5 |
files | client/src/components/map/layers.js |
diffstat | 1 files changed, 425 insertions(+), 413 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/map/layers.js Mon Jun 17 17:27:24 2019 +0200 +++ b/client/src/components/map/layers.js Mon Jun 17 17:31:35 2019 +0200 @@ -169,6 +169,8 @@ } }); +const layerConfigs = {}; + export default function(mapId) { const styles = styleFactory(mapId); // Shared feature source for layers: @@ -220,432 +222,442 @@ ) ); - return { - get(id) { - return this.config.find(l => l.get("id") === id); - }, - config: [ - new TileLayer({ - id: "OPENSTREETMAP", - label: "Open Streetmap", - visible: true, - source: new OSM() - }), - new ImageLayer({ - id: "INLANDECDIS", - label: "Inland ECDIS chart Danube", - visible: true, - source: new ImageSource({ - preload: 1, - url: store.state.application.config.ecdis_wms_url, - crossOrigin: "anonymous", - params: JSON.parse(store.state.application.config.ecdis_wms_params) - }) - }), - new ImageLayer({ - id: "WATERWAYAREA", - label: "Waterway Area", - maxResolution: 100, - minResolution: 0, - source: new ImageSource({ - url: window.location.origin + "/api/internal/wms", - params: { LAYERS: "waterway_area", VERSION: "1.1.1", TILED: true }, - imageLoadFunction: function(tile, src) { - HTTP.get(src, { - headers: { - "X-Gemma-Auth": localStorage.getItem("token") - }, - responseType: "blob" - }).then(response => { - tile.getImage().src = URL.createObjectURL(response.data); - }); - } // TODO tile.setState(TileState.ERROR); - }) - }), - (function() { - const source = new VectorSource({ strategy: bboxStrategy }); - source.setLoader( - buildVectorLoader( - { - featureTypes: ["stretches_geoserver"], - geometryName: "area" - }, - source, - true, - (f, store) => { - if (f.getId() === store.state.imports.selectedStretchId) { - f.set("highlighted", true); - } - return f; - } - ) - ); - return new VectorLayer({ - id: "STRETCHES", - label: "Stretches", - visible: false, - style: styles.stretches, - source - }); - })(), - (function() { - const source = new VectorSource({ strategy: bboxStrategy }); - source.setLoader( - buildVectorLoader( - { - featureTypes: ["sections_geoserver"], - geometryName: "area" - }, - source, - true, - (f, store) => { - if (f.getId() === store.state.imports.selectedSectionId) { - f.set("highlighted", true); - } - return f; - } - ) - ); - return new VectorLayer({ - id: "SECTIONS", - label: "Sections", - visible: false, - style: styles.sections, - source - }); - })(), - (function() { - const source = new VectorSource(); - source.setLoader( - buildVectorLoader( - { - featureTypes: ["fairway_dimensions"], - filter: equalTo("level_of_service", 1) - }, - source, - true - ) - ); - return new VectorLayer({ - id: "FAIRWAYDIMENSIONSLOS1", - label: "LOS 1 Fairway Dimensions", - visible: false, - style: styles.fwd1, - maxResolution: 80, - minResolution: 0, - source - }); - })(), - (function() { - const source = new VectorSource(); - source.setLoader( - buildVectorLoader( - { - featureTypes: ["fairway_dimensions"], - filter: equalTo("level_of_service", 2) - }, - source, - true - ) - ); - return new VectorLayer({ - id: "FAIRWAYDIMENSIONSLOS2", - label: "LOS 2 Fairway Dimensions", - visible: false, - style: styles.fwd2, - maxResolution: 80, - minResolution: 0, - source - }); - })(), - (function() { - const source = new VectorSource(); - source.setLoader( - buildVectorLoader( - { - featureTypes: ["fairway_dimensions"], - filter: equalTo("level_of_service", 3) - }, - source, - true - ) - ); - return new VectorLayer({ - id: "FAIRWAYDIMENSIONSLOS3", - label: "LOS 3 Fairway Dimensions", + // either use existing config or create new one + // important is only each map has its individual layer config + // but we don't want to create new layer objects each time a store value + // that is used here changes. + const config = layerConfigs.hasOwnProperty(mapId) + ? layerConfigs[mapId] + : [ + new TileLayer({ + id: "OPENSTREETMAP", + label: "Open Streetmap", visible: true, - style: styles.fwd3, - maxResolution: 80, + source: new OSM() + }), + new ImageLayer({ + id: "INLANDECDIS", + label: "Inland ECDIS chart Danube", + visible: true, + source: new ImageSource({ + preload: 1, + url: store.state.application.config.ecdis_wms_url, + crossOrigin: "anonymous", + params: JSON.parse(store.state.application.config.ecdis_wms_params) + }) + }), + new ImageLayer({ + id: "WATERWAYAREA", + label: "Waterway Area", + maxResolution: 100, minResolution: 0, - source - }); - })(), - new ImageLayer({ - id: "WATERWAYAXIS", - label: "Waterway Axis", - source: new ImageSource({ - url: window.location.origin + "/api/internal/wms", - params: { LAYERS: "waterway_axis", VERSION: "1.1.1", TILED: true }, - imageLoadFunction: function(tile, src) { - HTTP.get(src, { - headers: { - "X-Gemma-Auth": localStorage.getItem("token") + source: new ImageSource({ + url: window.location.origin + "/api/internal/wms", + params: { LAYERS: "waterway_area", VERSION: "1.1.1", TILED: true }, + imageLoadFunction: function(tile, src) { + HTTP.get(src, { + headers: { + "X-Gemma-Auth": localStorage.getItem("token") + }, + responseType: "blob" + }).then(response => { + tile.getImage().src = URL.createObjectURL(response.data); + }); + } // TODO tile.setState(TileState.ERROR); + }) + }), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["stretches_geoserver"], + geometryName: "area" }, - responseType: "blob" - }).then(response => { - tile.getImage().src = URL.createObjectURL(response.data); - }); - } // TODO tile.setState(TileState.ERROR); - }) - }), - (function() { - const source = new VectorSource({ strategy: bboxStrategy }); - source.setLoader( - buildVectorLoader( - { - featureTypes: ["waterway_profiles"], - geometryName: "geom" - }, + source, + true, + (f, store) => { + if (f.getId() === store.state.imports.selectedStretchId) { + f.set("highlighted", true); + } + return f; + } + ) + ); + return new VectorLayer({ + id: "STRETCHES", + label: "Stretches", + visible: false, + style: styles.stretches, source - ) - ); - return new VectorLayer({ - id: "WATERWAYPROFILES", - label: "Waterway Profiles", - visible: true, - style: new Style({ - stroke: new Stroke({ - color: "rgba(0, 0, 255, .5)", - lineDash: [5, 5], - width: 2 - }) - }), - maxResolution: 2.5, - minResolution: 0, - source - }); - })(), - (function() { - return new VectorLayer({ - id: "BOTTLENECKS", - label: "Bottlenecks", - visible: true, - style: styles.bottleneck, - source: bottlenecksSource - }); - })(), - new TileLayer({ - id: "BOTTLENECKISOLINE", - label: "Bottleneck isolines", - visible: false, - source: new TileWMS({ - preload: 0, - projection: "EPSG:3857", - url: window.location.origin + "/api/internal/wms", - params: { - LAYERS: "sounding_results_contour_lines_geoserver", - VERSION: "1.1.1", - TILED: true - }, - tileLoadFunction: function(tile, src) { - // console.log("calling for", tile, src); - HTTP.get(src, { - headers: { - "X-Gemma-Auth": localStorage.getItem("token") + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["sections_geoserver"], + geometryName: "area" + }, + source, + true, + (f, store) => { + if (f.getId() === store.state.imports.selectedSectionId) { + f.set("highlighted", true); + } + return f; + } + ) + ); + return new VectorLayer({ + id: "SECTIONS", + label: "Sections", + visible: false, + style: styles.sections, + source + }); + })(), + (function() { + const source = new VectorSource(); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["fairway_dimensions"], + filter: equalTo("level_of_service", 1) + }, + source, + true + ) + ); + return new VectorLayer({ + id: "FAIRWAYDIMENSIONSLOS1", + label: "LOS 1 Fairway Dimensions", + visible: false, + style: styles.fwd1, + maxResolution: 80, + minResolution: 0, + source + }); + })(), + (function() { + const source = new VectorSource(); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["fairway_dimensions"], + filter: equalTo("level_of_service", 2) + }, + source, + true + ) + ); + return new VectorLayer({ + id: "FAIRWAYDIMENSIONSLOS2", + label: "LOS 2 Fairway Dimensions", + visible: false, + style: styles.fwd2, + maxResolution: 80, + minResolution: 0, + source + }); + })(), + (function() { + const source = new VectorSource(); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["fairway_dimensions"], + filter: equalTo("level_of_service", 3) }, - responseType: "blob" - }).then(response => { - tile.getImage().src = URL.createObjectURL(response.data); - }); - } // TODO tile.setState(TileState.ERROR); - }) - }), - new TileLayer({ - id: "DIFFERENCES", - label: "Bottleneck Differences", - visible: false, - source: new TileWMS({ - preload: 0, - projection: "EPSG:3857", - url: window.location.origin + "/api/internal/wms", - params: { - LAYERS: "sounding_differences", - VERSION: "1.1.1", - TILED: true - }, - tileLoadFunction: function(tile, src) { - // console.log("calling for", tile, src); - HTTP.get(src, { - headers: { - "X-Gemma-Auth": localStorage.getItem("token") + source, + true + ) + ); + return new VectorLayer({ + id: "FAIRWAYDIMENSIONSLOS3", + label: "LOS 3 Fairway Dimensions", + visible: true, + style: styles.fwd3, + maxResolution: 80, + minResolution: 0, + source + }); + })(), + new ImageLayer({ + id: "WATERWAYAXIS", + label: "Waterway Axis", + source: new ImageSource({ + url: window.location.origin + "/api/internal/wms", + params: { LAYERS: "waterway_axis", VERSION: "1.1.1", TILED: true }, + imageLoadFunction: function(tile, src) { + HTTP.get(src, { + headers: { + "X-Gemma-Auth": localStorage.getItem("token") + }, + responseType: "blob" + }).then(response => { + tile.getImage().src = URL.createObjectURL(response.data); + }); + } // TODO tile.setState(TileState.ERROR); + }) + }), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["waterway_profiles"], + geometryName: "geom" }, - responseType: "blob" - }).then(response => { - tile.getImage().src = URL.createObjectURL(response.data); - }); - } // TODO tile.setState(TileState.ERROR); - }) - }), - (function() { - return new VectorLayer({ - id: "BOTTLENECKSTATUS", - label: "Critical Bottlenecks", - forLegendStyle: { point: true, resolution: 16 }, - visible: true, - zIndex: 1, - style: styles.bottleneckStatus, - source: bottlenecksSource - }); - })(), - (function() { - return new VectorLayer({ - id: "BOTTLENECKFAIRWAYAVAILABILITY", - label: "Bottlenecks Fairway Availability", - forLegendStyle: { point: true, resolution: 16 }, + source + ) + ); + return new VectorLayer({ + id: "WATERWAYPROFILES", + label: "Waterway Profiles", + visible: true, + style: new Style({ + stroke: new Stroke({ + color: "rgba(0, 0, 255, .5)", + lineDash: [5, 5], + width: 2 + }) + }), + maxResolution: 2.5, + minResolution: 0, + source + }); + })(), + (function() { + return new VectorLayer({ + id: "BOTTLENECKS", + label: "Bottlenecks", + visible: true, + style: styles.bottleneck, + source: bottlenecksSource + }); + })(), + new TileLayer({ + id: "BOTTLENECKISOLINE", + label: "Bottleneck isolines", + visible: false, + source: new TileWMS({ + preload: 0, + projection: "EPSG:3857", + url: window.location.origin + "/api/internal/wms", + params: { + LAYERS: "sounding_results_contour_lines_geoserver", + VERSION: "1.1.1", + TILED: true + }, + tileLoadFunction: function(tile, src) { + // console.log("calling for", tile, src); + HTTP.get(src, { + headers: { + "X-Gemma-Auth": localStorage.getItem("token") + }, + responseType: "blob" + }).then(response => { + tile.getImage().src = URL.createObjectURL(response.data); + }); + } // TODO tile.setState(TileState.ERROR); + }) + }), + new TileLayer({ + id: "DIFFERENCES", + label: "Bottleneck Differences", visible: false, - zIndex: 1, - style: styles.bottleneckFairwayAvailability, - source: bottlenecksSource - }); - })(), - (function() { - const source = new VectorSource({ strategy: bboxStrategy }); - source.setLoader( - buildVectorLoader( - { - featureTypes: [ - "bottlenecks_geoserver", - "gauges_geoserver", - "stretches_geoserver", - "sections_geoserver" - ] + source: new TileWMS({ + preload: 0, + projection: "EPSG:3857", + url: window.location.origin + "/api/internal/wms", + params: { + LAYERS: "sounding_differences", + VERSION: "1.1.1", + TILED: true }, - source, - true, - // since we don't use bbox strategy, features will contain all features and we can use it - // to find reference gauges for bottlenecks, yeah! - async (f, store, features) => { - // attach reference gauge to bottleneck - if (f.getId().indexOf("bottlenecks") > -1) { - f.set( - "gauge_obj", - features.find(feat => { - return ( - feat.getId().indexOf("gauges") > -1 && - feat.get("objname") === f.get("gauge_objname") - ); - }) - ); - } + tileLoadFunction: function(tile, src) { + // console.log("calling for", tile, src); + HTTP.get(src, { + headers: { + "X-Gemma-Auth": localStorage.getItem("token") + }, + responseType: "blob" + }).then(response => { + tile.getImage().src = URL.createObjectURL(response.data); + }); + } // TODO tile.setState(TileState.ERROR); + }) + }), + (function() { + return new VectorLayer({ + id: "BOTTLENECKSTATUS", + label: "Critical Bottlenecks", + forLegendStyle: { point: true, resolution: 16 }, + visible: true, + zIndex: 1, + style: styles.bottleneckStatus, + source: bottlenecksSource + }); + })(), + (function() { + return new VectorLayer({ + id: "BOTTLENECKFAIRWAYAVAILABILITY", + label: "Bottlenecks Fairway Availability", + forLegendStyle: { point: true, resolution: 16 }, + visible: false, + zIndex: 1, + style: styles.bottleneckFairwayAvailability, + source: bottlenecksSource + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: [ + "bottlenecks_geoserver", + "gauges_geoserver", + "stretches_geoserver", + "sections_geoserver" + ] + }, + source, + true, + // since we don't use bbox strategy, features will contain all features and we can use it + // to find reference gauges for bottlenecks, yeah! + async (f, store, features) => { + // attach reference gauge to bottleneck + if (f.getId().indexOf("bottlenecks") > -1) { + f.set( + "gauge_obj", + features.find(feat => { + return ( + feat.getId().indexOf("gauges") > -1 && + feat.get("objname") === f.get("gauge_objname") + ); + }) + ); + } - // attach nsc data to gauge - if (f.getId().indexOf("gauges") > -1) { - // look for nashSutcliffeOverview in store. If present and - // not older than 15 min use it or fetch new data and store it. - let data = store.getters["gauges/nashSutcliffeOverview"](f); - if ( - data && - new Date().getTime() - data.createdAt.getTime() < 900000 - ) { - f.set("nsc_data", data.data); - } else { - data = await store.dispatch( - "gauges/loadNashSutcliffeForOverview", - f.get("isrs_code") - ); - if (data) { - store.commit("gauges/addNashSutcliffeOverviewEntry", { - feature: f, - data, - createdAt: new Date() - }); - f.set("nsc_data", data); + // attach nsc data to gauge + if (f.getId().indexOf("gauges") > -1) { + // look for nashSutcliffeOverview in store. If present and + // not older than 15 min use it or fetch new data and store it. + let data = store.getters["gauges/nashSutcliffeOverview"](f); + if ( + data && + new Date().getTime() - data.createdAt.getTime() < 900000 + ) { + f.set("nsc_data", data.data); + } else { + data = await store.dispatch( + "gauges/loadNashSutcliffeForOverview", + f.get("isrs_code") + ); + if (data) { + store.commit("gauges/addNashSutcliffeOverviewEntry", { + feature: f, + data, + createdAt: new Date() + }); + f.set("nsc_data", data); + } } } } - } - ) - ); - return new VectorLayer({ - id: "DATAAVAILABILITY", - label: "Data Availability/Accuracy", - forLegendStyle: { point: true, resolution: 16 }, - visible: false, - zIndex: 1, - style: styles.dataAvailability, - source - }); - })(), - new ImageLayer({ - id: "DISTANCEMARKS", - label: "Distance Marks", - maxResolution: 10, - minResolution: 0, - source: new ImageSource({ - url: window.location.origin + "/api/internal/wms", - params: { - LAYERS: "distance_marks_ashore_geoserver", - VERSION: "1.1.1", - TILED: true - }, - imageLoadFunction: function(tile, src) { - HTTP.get(src, { - headers: { - "X-Gemma-Auth": localStorage.getItem("token") + ) + ); + return new VectorLayer({ + id: "DATAAVAILABILITY", + label: "Data Availability/Accuracy", + forLegendStyle: { point: true, resolution: 16 }, + visible: false, + zIndex: 1, + style: styles.dataAvailability, + source + }); + })(), + new ImageLayer({ + id: "DISTANCEMARKS", + label: "Distance Marks", + maxResolution: 10, + minResolution: 0, + source: new ImageSource({ + url: window.location.origin + "/api/internal/wms", + params: { + LAYERS: "distance_marks_ashore_geoserver", + VERSION: "1.1.1", + TILED: true + }, + imageLoadFunction: function(tile, src) { + HTTP.get(src, { + headers: { + "X-Gemma-Auth": localStorage.getItem("token") + }, + responseType: "blob" + }).then(response => { + tile.getImage().src = URL.createObjectURL(response.data); + }); + } // TODO tile.setState(TileState.ERROR); + }) + }), + new ImageLayer({ + id: "DISTANCEMARKSAXIS", + label: "Distance Marks, Axis", + source: new ImageSource({ + url: window.location.origin + "/api/internal/wms", + params: { + LAYERS: "distance_marks_geoserver", + VERSION: "1.1.1", + TILED: true + }, + imageLoadFunction: function(tile, src) { + HTTP.get(src, { + headers: { + "X-Gemma-Auth": localStorage.getItem("token") + }, + responseType: "blob" + }).then(response => { + tile.getImage().src = URL.createObjectURL(response.data); + }); + } // TODO tile.setState(TileState.ERROR); + }) + }), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["gauges_geoserver"], + geometryName: "geom" }, - responseType: "blob" - }).then(response => { - tile.getImage().src = URL.createObjectURL(response.data); - }); - } // TODO tile.setState(TileState.ERROR); - }) - }), - new ImageLayer({ - id: "DISTANCEMARKSAXIS", - label: "Distance Marks, Axis", - source: new ImageSource({ - url: window.location.origin + "/api/internal/wms", - params: { - LAYERS: "distance_marks_geoserver", - VERSION: "1.1.1", - TILED: true - }, - imageLoadFunction: function(tile, src) { - HTTP.get(src, { - headers: { - "X-Gemma-Auth": localStorage.getItem("token") - }, - responseType: "blob" - }).then(response => { - tile.getImage().src = URL.createObjectURL(response.data); - }); - } // TODO tile.setState(TileState.ERROR); - }) - }), - (function() { - const source = new VectorSource({ strategy: bboxStrategy }); - source.setLoader( - buildVectorLoader( - { - featureTypes: ["gauges_geoserver"], - geometryName: "geom" - }, + source + ) + ); + return new VectorLayer({ + id: "GAUGES", + label: "Gauges", + forLegendStyle: { point: true, resolution: 8 }, + visible: true, + style: styles.gauge, + maxResolution: 100, + minResolution: 0, source - ) - ); - return new VectorLayer({ - id: "GAUGES", - label: "Gauges", - forLegendStyle: { point: true, resolution: 8 }, - visible: true, - style: styles.gauge, - maxResolution: 100, - minResolution: 0, - source - }); - })(), - DRAWLAYER, - CUTLAYER - ] + }); + })(), + DRAWLAYER, + CUTLAYER + ]; + + layerConfigs[mapId] = config; + + return { + get(id) { + return config.find(l => l.get("id") === id); + }, + config }; }