# HG changeset patch # User Markus Kottlaender # Date 1554975851 -7200 # Node ID 44493664d40e5f4feb2aa04eef5aa948e87f02ba # Parent 870d2a0e866b78dd64824ff6e612b4716cc418cb client: refactored layers config Layers are not stored in the vuex store anymore but instead they are served from a factory function, so that different maps can haved individual layer objects diff -r 870d2a0e866b -r 44493664d40e client/src/components/ImportStretches.vue --- a/client/src/components/ImportStretches.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/ImportStretches.vue Thu Apr 11 11:44:11 2019 +0200 @@ -338,7 +338,11 @@ }, computed: { ...mapState("application", ["searchQuery"]), - ...mapState("map", ["layers", "identifiedFeatures", "currentMeasurement"]), + ...mapState("map", [ + "openLayersMap", + "identifiedFeatures", + "currentMeasurement" + ]), ...mapGetters("user", ["isSysAdmin"]), ...mapState("imports", ["stretches"]), defineStretchesLabel() { @@ -458,7 +462,7 @@ }, moveMapToStretch(stretch) { this.$store.commit("imports/selectedStretchId", stretch.id); - this.layers.STRETCHES.setVisible(true); + this.openLayersMap.getLayer("STRETCHES").setVisible(true); this.$store.commit("map/moveToExtent", { feature: stretch, zoom: 17, @@ -496,7 +500,7 @@ this.edit = true; }, togglePipette(t) { - this.layers.DISTANCEMARKSAXIS.setVisible(true); + this.openLayersMap.getLayer("DISTANCEMARKSAXIS").setVisible(true); if (t === "start") { this.pipetteStart = !this.pipetteStart; this.pipetteEnd = false; diff -r 870d2a0e866b -r 44493664d40e client/src/components/Maplayer.vue --- a/client/src/components/Maplayer.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/Maplayer.vue Thu Apr 11 11:44:11 2019 +0200 @@ -41,11 +41,10 @@ import { HTTP } from "@/lib/http"; import { mapState } from "vuex"; import { Map, View } from "ol"; -import { WFS, GeoJSON } from "ol/format"; -import { equalTo } from "ol/format/filter"; import { Stroke, Style, Fill } from "ol/style"; import { displayError } from "@/lib/errors"; import { uuid } from "@/lib/mixins"; +import layers from "@/components/layers/layers"; import "ol/ol.css"; /* for the sake of debugging */ @@ -61,7 +60,6 @@ ...mapState("map", [ "initialLoad", "extent", - "layers", "openLayersMap", "lineTool", "polygonTool", @@ -79,60 +77,18 @@ } }, methods: { - buildVectorLoader( - featureRequestOptions, - vectorSource, - bboxStrategyDisabled, - featurePostProcessor - ) { - // build a function to be used for VectorSource.setLoader() - // make use of WFS().writeGetFeature to build the request - // and use our HTTP library to actually do it - // NOTE: the geometryName has to be given in featureRequestOptions if - // bboxStrategy (default) is used - featureRequestOptions.featureNS = "gemma"; - featureRequestOptions.featurePrefix = "gemma"; - featureRequestOptions.outputFormat = "application/json"; - return (extent, resolution, projection) => { - if (!bboxStrategyDisabled) { - featureRequestOptions.bbox = extent; - } - featureRequestOptions.srsName = projection.getCode(); - HTTP.post( - "/internal/wfs", - new XMLSerializer().serializeToString( - new WFS().writeGetFeature(featureRequestOptions) - ), - { - headers: { - "X-Gemma-Auth": localStorage.getItem("token"), - "Content-type": "text/xml; charset=UTF-8" - } - } - ) - .then(response => { - const features = new GeoJSON().readFeatures( - JSON.stringify(response.data) - ); - if (featurePostProcessor) { - features.map(f => featurePostProcessor(f)); - } - vectorSource.addFeatures(features); - }) - .catch(() => { - vectorSource.removeLoadedExtent(extent); - }); - }; - }, updateBottleneckFilter(bottleneck_id, datestr) { const exists = bottleneck_id != "does_not_exist"; if (exists) { - this.layers.BOTTLENECKISOLINE.getSource().updateParams({ - cql_filter: `date_info='${datestr}' AND bottleneck_id='${bottleneck_id}'` - }); + layers + .get("BOTTLENECKISOLINE") + .getSource() + .updateParams({ + cql_filter: `date_info='${datestr}' AND bottleneck_id='${bottleneck_id}'` + }); } - this.layers.BOTTLENECKISOLINE.setVisible(exists); + layers.get("BOTTLENECKISOLINE").setVisible(exists); } }, watch: { @@ -162,7 +118,9 @@ } }, selectedStretchId(id) { - this.layers.STRETCHES.getSource() + layers + .get("STRETCHES") + .getSource() .getFeatures() .forEach(f => { f.set("highlighted", false); @@ -173,8 +131,8 @@ } }, mounted() { - let map = new Map({ - layers: [...Object.values(this.layers)], + const map = new Map({ + layers: layers.config, target: "map-" + this.uuid, controls: [], view: new View({ @@ -184,6 +142,10 @@ projection: "EPSG:3857" }) }); + map.getLayer = id => layers.get(id); + + // store map position on every move + // will be obsolete once we abandoned the separated admin context map.on("moveend", event => { const center = event.map.getView().getCenter(); this.$store.commit("map/extent", { @@ -194,6 +156,8 @@ }); this.$store.dispatch("map/openLayersMap", map); + // move to user specific default extent if map loads for the first timeout + // checking initialLoad will be obsolete once we abandoned the separated admin context if (this.initialLoad) { this.$store.commit("map/initialLoad", false); var currentUser = this.$store.state.user.user; @@ -224,137 +188,7 @@ }); } - // TODO make display of layers more dynamic, e.g. from a list - - this.layers.FAIRWAYDIMENSIONSLOS1.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["fairway_dimensions"], - filter: equalTo("level_of_service", 1) - }, - this.layers.FAIRWAYDIMENSIONSLOS1.getSource(), - true - ) - ); - - this.layers.FAIRWAYDIMENSIONSLOS2.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["fairway_dimensions"], - filter: equalTo("level_of_service", 2) - }, - this.layers.FAIRWAYDIMENSIONSLOS2.getSource(), - true - ) - ); - - this.layers.FAIRWAYDIMENSIONSLOS3.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["fairway_dimensions"], - filter: equalTo("level_of_service", 3) - }, - this.layers.FAIRWAYDIMENSIONSLOS3.getSource(), - true - ) - ); - - // load following layers with bboxStrategy (using our request builder) - this.layers.WATERWAYAREA.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["waterway_area"], - geometryName: "area" - }, - this.layers.WATERWAYAREA.getSource() - ) - ); - - this.layers.WATERWAYAXIS.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["waterway_axis"], - geometryName: "wtwaxs" - }, - this.layers.WATERWAYAXIS.getSource() - ) - ); - - this.layers.WATERWAYPROFILES.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["waterway_profiles"], - geometryName: "geom" - }, - this.layers.WATERWAYPROFILES.getSource() - ) - ); - - this.layers.DISTANCEMARKS.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["distance_marks_ashore_geoserver"], - geometryName: "geom" - }, - this.layers.DISTANCEMARKS.getSource() - ) - ); - - this.layers.DISTANCEMARKSAXIS.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["distance_marks_geoserver"], - geometryName: "geom" - }, - this.layers.DISTANCEMARKSAXIS.getSource() - ) - ); - - this.layers.GAUGES.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["gauges_geoserver"], - geometryName: "geom" - }, - this.layers.GAUGES.getSource() - ) - ); - - this.layers.STRETCHES.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["stretches_geoserver"], - geometryName: "area" - }, - this.layers.STRETCHES.getSource(), - f => { - if (f.getId() === this.selectedStretchId) { - f.set("highlighted", true); - } - return f; - } - ) - ); - - this.layers.BOTTLENECKSTATUS.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["bottlenecks_geoserver"], - geometryName: "area" - }, - this.layers.BOTTLENECKSTATUS.getSource() - ) - ); - - this.layers.BOTTLENECKS.getSource().setLoader( - this.buildVectorLoader( - { - featureTypes: ["bottlenecks_geoserver"], - geometryName: "area" - }, - this.layers.BOTTLENECKS.getSource() - ) - ); + // load configured bottleneck colors HTTP.get("/system/style/Bottlenecks/stroke", { headers: { "X-Gemma-Auth": localStorage.getItem("token") } }) @@ -374,7 +208,7 @@ color: btlnFillC }) }); - this.layers.BOTTLENECKS.setStyle(newStyle); + layers.get("BOTTLENECKS").setStyle(newStyle); }) .catch(error => { console.log(error); diff -r 870d2a0e866b -r 44493664d40e client/src/components/Pdftool.vue --- a/client/src/components/Pdftool.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/Pdftool.vue Thu Apr 11 11:44:11 2019 +0200 @@ -165,7 +165,7 @@ computed: { ...mapState("application", ["showPdfTool", "logoForPDF"]), ...mapState("bottlenecks", ["selectedBottleneck", "selectedSurvey"]), - ...mapState("map", ["openLayersMap", "isolinesLegendImgDataURL", "layers"]), + ...mapState("map", ["openLayersMap", "isolinesLegendImgDataURL"]), ...mapState("user", ["user"]), generatePdfLable() { return this.$gettext("Generate PDF"); @@ -752,7 +752,7 @@ if ( this.selectedBottleneck && this.selectedSurvey && - this.layers.BOTTLENECKISOLINE.getVisible() + this.openLayersMap.getLayer("BOTTLENECKISOLINE").getVisible() ) { // transforming into an HTMLImageElement only to find out // the width x height of the legend image @@ -791,7 +791,7 @@ if ( this.selectedBottleneck && this.selectedSurvey && - this.layers.BOTTLENECKISOLINE.getVisible() + this.openLayersMap.getLayer("BOTTLENECKISOLINE").getVisible() ) { let survey = this.selectedSurvey; diff -r 870d2a0e866b -r 44493664d40e client/src/components/fairway/Profiles.vue --- a/client/src/components/fairway/Profiles.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/fairway/Profiles.vue Thu Apr 11 11:44:11 2019 +0200 @@ -264,7 +264,7 @@ }, computed: { ...mapState("application", ["showProfiles"]), - ...mapState("map", ["layers", "lineTool", "polygonTool", "cutTool"]), + ...mapState("map", ["openLayersMap", "lineTool", "polygonTool", "cutTool"]), ...mapState("bottlenecks", [ "bottlenecksList", "surveys", @@ -348,7 +348,10 @@ if (!cut) { this.$store.commit("fairwayprofile/clearCurrentProfile"); this.$store.commit("application/showSplitscreen", false); - this.layers.CUTTOOL.getSource().clear(); + this.openLayersMap + .getLayer("CUTTOOL") + .getSource() + .clear(); } } }, @@ -409,19 +412,22 @@ } ) .then(() => { - this.layers.DIFFERENCES.getSource().updateParams({ - cql_filter: - "objnam='" + - this.selectedBottleneck + - "' AND " + - "minuend='" + - this.selectedSurvey.date_info + - "' AND subtrahend='" + - this.additionalSurvey.date_info + - "'" - }); - this.layers.BOTTLENECKISOLINE.setVisible(false); - this.layers.DIFFERENCES.setVisible(true); + this.openLayersMap + .getLayer("DIFFERENCES") + .getSource() + .updateParams({ + cql_filter: + "objnam='" + + this.selectedBottleneck + + "' AND " + + "minuend='" + + this.selectedSurvey.date_info + + "' AND subtrahend='" + + this.additionalSurvey.date_info + + "'" + }); + this.openLayersMap.getLayer("BOTTLENECKISOLINE").setVisible(false); + this.openLayersMap.getLayer("DIFFERENCES").setVisible(true); }) .catch(error => { const { status, data } = error.response; @@ -478,14 +484,20 @@ coordinates = coordinates.filter(c => Number(c) === c); if (coordinates.length === 4) { // draw line on map - this.layers.CUTTOOL.getSource().clear(); + this.openLayersMap + .getLayer("CUTTOOL") + .getSource() + .clear(); const cut = new Feature({ geometry: new LineString([ [coordinates[0], coordinates[1]], [coordinates[2], coordinates[3]] ]).transform("EPSG:4326", "EPSG:3857") }); - this.layers.CUTTOOL.getSource().addFeature(cut); + this.openLayersMap + .getLayer("CUTTOOL") + .getSource() + .addFeature(cut); // draw diagram this.$store.dispatch("fairwayprofile/cut", cut); diff -r 870d2a0e866b -r 44493664d40e client/src/components/importoverview/BottleneckDetail.vue --- a/client/src/components/importoverview/BottleneckDetail.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/importoverview/BottleneckDetail.vue Thu Apr 11 11:44:11 2019 +0200 @@ -101,7 +101,7 @@ }, computed: { ...mapState("imports", ["showLogs", "details"]), - ...mapState("map", ["layers"]) + ...mapState("map", ["openLayersMap"]) }, methods: { loadBottlenecks() { @@ -147,7 +147,7 @@ }); }, moveToBottleneck(index) { - this.layers.BOTTLENECKS.setVisible(true); + this.openLayersMap.getLayer("BOTTLENECKS").setVisible(true); this.moveToExtent(this.bottlenecks[index]); }, moveToExtent(feature) { diff -r 870d2a0e866b -r 44493664d40e client/src/components/importoverview/StretchDetails.vue --- a/client/src/components/importoverview/StretchDetails.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/importoverview/StretchDetails.vue Thu Apr 11 11:44:11 2019 +0200 @@ -31,7 +31,7 @@ }, computed: { ...mapState("imports", ["showAdditional", "details"]), - ...mapState("map", ["layers"]) + ...mapState("map", ["openLayersMap"]) }, methods: { moveToExtent(feature) { @@ -43,7 +43,7 @@ }, zoomToStretch() { const name = this.details.summary.stretch; - this.layers.STRETCHES.setVisible(true); + this.openLayersMap.getLayer("STRETCHES").setVisible(true); this.$store .dispatch("imports/loadStretch", name) .then(response => { diff -r 870d2a0e866b -r 44493664d40e client/src/components/layers/Layers.vue --- a/client/src/components/layers/Layers.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/layers/Layers.vue Thu Apr 11 11:44:11 2019 +0200 @@ -11,23 +11,23 @@ :title="layersLabel" :closeCallback="close" /> -
- - - - - - - - - - - - - - - - +
+ + + + + + + + + + + + + + + +
@@ -55,7 +55,7 @@ Layerselect: () => import("./Layerselect") }, computed: { - ...mapState("map", ["layers"]), + ...mapState("map", ["openLayersMap"]), ...mapState("application", ["showLayers"]), layersLabel() { return this.$gettext("Layers"); diff -r 870d2a0e866b -r 44493664d40e client/src/components/layers/Layerselect.vue --- a/client/src/components/layers/Layerselect.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/layers/Layerselect.vue Thu Apr 11 11:44:11 2019 +0200 @@ -15,10 +15,10 @@ {{ label }} -
+
-
+
@@ -89,13 +89,13 @@ } }, created() { - if (this.layer === this.layers.BOTTLENECKISOLINE) { + if (this.layer.get("id") === "BOTTLENECKISOLINE") { this.loadLegendImage( "sounding_results_contour_lines_geoserver", "isolinesLegendImgDataURL" ); } - if (this.layer === this.layers.DIFFERENCES) { + if (this.layer.get("id") === "DIFFERENCES") { this.loadLegendImage( "sounding_differences", "differencesLegendImgDataURL" diff -r 870d2a0e866b -r 44493664d40e client/src/components/layers/layers.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/layers/layers.js Thu Apr 11 11:44:11 2019 +0200 @@ -0,0 +1,494 @@ +import TileWMS from "ol/source/TileWMS"; +import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer"; +import OSM from "ol/source/OSM"; +import { Icon, Stroke, Style } from "ol/style"; +import VectorSource from "ol/source/Vector"; +import Point from "ol/geom/Point"; +import { bbox as bboxStrategy } from "ol/loadingstrategy"; +import { WFS, GeoJSON } from "ol/format"; +import { equalTo } from "ol/format/filter"; +import { HTTP } from "@/lib/http"; +import styles from "./styles"; + +const buildVectorLoader = ( + featureRequestOptions, + vectorSource, + bboxStrategyDisabled, + featurePostProcessor +) => { + // build a function to be used for VectorSource.setLoader() + // make use of WFS().writeGetFeature to build the request + // and use our HTTP library to actually do it + // NOTE: the geometryName has to be given in featureRequestOptions if + // bboxStrategy (default) is used + featureRequestOptions.featureNS = "gemma"; + featureRequestOptions.featurePrefix = "gemma"; + featureRequestOptions.outputFormat = "application/json"; + return (extent, resolution, projection) => { + if (!bboxStrategyDisabled) { + featureRequestOptions.bbox = extent; + } + featureRequestOptions.srsName = projection.getCode(); + HTTP.post( + "/internal/wfs", + new XMLSerializer().serializeToString( + new WFS().writeGetFeature(featureRequestOptions) + ), + { + headers: { + "X-Gemma-Auth": localStorage.getItem("token"), + "Content-type": "text/xml; charset=UTF-8" + } + } + ) + .then(response => { + const features = new GeoJSON().readFeatures( + JSON.stringify(response.data) + ); + if (featurePostProcessor) { + features.map(f => featurePostProcessor(f)); + } + vectorSource.addFeatures(features); + }) + .catch(() => { + vectorSource.removeLoadedExtent(extent); + }); + }; +}; + +export default (function() { + 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 TileLayer({ + id: "INLANDECDIS", + label: "Inland ECDIS chart Danube", + visible: true, + source: new TileWMS({ + preload: 1, + url: "https://service.d4d-portal.info/wms/", + crossOrigin: "anonymous", + params: { LAYERS: "d4d", VERSION: "1.1.1", TILED: true } + }) + }), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["waterway_area"], + geometryName: "area" + }, + source + ) + ); + return new VectorLayer({ + id: "WATERWAYAREA", + label: "Waterway Area", + visible: true, + style: new Style({ + stroke: new Stroke({ + color: "rgba(0, 102, 0, 1)", + width: 2 + }) + }), + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["stretches_geoserver"], + geometryName: "area" + }, + source, + f => { + if (f.getId() === this.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(); + 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, + 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, + 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", + visible: true, + style: styles.fwd3, + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["waterway_axis"], + geometryName: "wtwaxs" + }, + source + ) + ); + return new VectorLayer({ + id: "WATERWAYAXIS", + label: "Waterway Axis", + visible: true, + style: new Style({ + stroke: new Stroke({ + color: "rgba(0, 0, 255, .5)", + lineDash: [5, 5], + width: 2 + }) + }), + // TODO: Set layer in layertree active/inactive depending on + // resolution. + maxResolution: 5, + minResolution: 0, + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["waterway_profiles"], + geometryName: "geom" + }, + 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() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["bottlenecks_geoserver"], + geometryName: "area" + }, + source + ) + ); + return new VectorLayer({ + id: "BOTTLENECKS", + label: "Bottlenecks", + visible: true, + style: styles.bottleneck, + source + }); + })(), + 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, + source: new TileWMS({ + preload: 0, + projection: "EPSG:4326", + 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") + }, + 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: ["bottlenecks_geoserver"], + geometryName: "area" + }, + source + ) + ); + return new VectorLayer({ + id: "BOTTLENECKSTATUS", + label: "Critical Bottlenecks", + forLegendStyle: { point: true, resolution: 16 }, + visible: true, + style: styles.bottleneckStatus, + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["distance_marks_ashore_geoserver"], + geometryName: "geom" + }, + source + ) + ); + return new VectorLayer({ + id: "DISTANCEMARKS", + label: "Distance marks", + forLegendStyle: { point: true, resolution: 8 }, + visible: false, + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["distance_marks_geoserver"], + geometryName: "geom" + }, + source + ) + ); + return new VectorLayer({ + id: "DISTANCEMARKSAXIS", + label: "Distance marks, Axis", + forLegendStyle: { point: true, resolution: 8 }, + visible: true, + style: styles.dma, + source + }); + })(), + (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 + }); + })(), + new VectorLayer({ + id: "DRAWTOOL", + label: "Draw Tool", + visible: true, + source: new VectorSource({ wrapX: false }), + style: function(feature) { + // adapted from OpenLayer's LineString Arrow Example + var geometry = feature.getGeometry(); + var styles = [ + // linestring + new Style({ + stroke: new Stroke({ + color: "#369aca", + width: 2 + }) + }) + ]; + + if (geometry.getType() === "LineString") { + geometry.forEachSegment(function(start, end) { + var dx = end[0] - start[0]; + var dy = end[1] - start[1]; + var rotation = Math.atan2(dy, dx); + // arrows + styles.push( + new Style({ + geometry: new Point(end), + image: new Icon({ + // we need to make sure the image is loaded by Vue Loader + src: require("@/assets/linestring_arrow.png"), + // fiddling with the anchor's y value does not help to + // position the image more centered on the line ending, as the + // default line style seems to be slightly uncentered in the + // anti-aliasing, but the image is not placed with subpixel + // precision + anchor: [0.75, 0.5], + rotateWithView: true, + rotation: -rotation + }) + }) + ); + }); + } + return styles; + } + }), + new VectorLayer({ + id: "CUTTOOL", + label: "Cut Tool", + visible: true, + source: new VectorSource({ wrapX: false }), + style: function(feature) { + // adapted from OpenLayer's LineString Arrow Example + var geometry = feature.getGeometry(); + var styles = [ + // linestring + new Style({ + stroke: new Stroke({ + color: "#333333", + width: 2, + lineDash: [7, 7] + }) + }) + ]; + + if (geometry.getType() === "LineString") { + geometry.forEachSegment(function(start, end) { + var dx = end[0] - start[0]; + var dy = end[1] - start[1]; + var rotation = Math.atan2(dy, dx); + // arrows + styles.push( + new Style({ + geometry: new Point(end), + image: new Icon({ + // we need to make sure the image is loaded by Vue Loader + src: require("@/assets/linestring_arrow_grey.png"), + // fiddling with the anchor's y value does not help to + // position the image more centered on the line ending, as the + // default line style seems to be slightly uncentered in the + // anti-aliasing, but the image is not placed with subpixel + // precision + anchor: [0.75, 0.5], + rotateWithView: true, + rotation: -rotation + }) + }) + ); + }); + } + return styles; + } + }) + ] + }; +})(); diff -r 870d2a0e866b -r 44493664d40e client/src/components/layers/styles.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/layers/styles.js Thu Apr 11 11:44:11 2019 +0200 @@ -0,0 +1,201 @@ +import { Icon, Stroke, Style, Fill, Text, Circle } from "ol/style"; +import Point from "ol/geom/Point"; +import { getCenter } from "ol/extent"; + +const styles = { + blue1: new Style({ + stroke: new Stroke({ + color: "rgba(0, 0, 255, 0.8)", + lineDash: [2, 4], + lineCap: "round", + width: 2 + }), + fill: new Fill({ + color: "rgba(240, 230, 0, 0.2)" + }) + }), + blue2: new Style({ + stroke: new Stroke({ + color: "rgba(0, 0, 255, 0.9)", + lineDash: [3, 6], + lineCap: "round", + width: 2 + }), + fill: new Fill({ + color: "rgba(240, 230, 0, 0.1)" + }) + }), + blue3: new Style({ + stroke: new Stroke({ + color: "rgba(0, 0, 255, 1.0)", + width: 2 + }), + fill: new Fill({ + color: "rgba(255, 255, 255, 0.4)" + }) + }), + yellow1: new Style({ + stroke: new Stroke({ + color: "rgba(230, 230, 10, .8)", + width: 4 + }), + fill: new Fill({ + color: "rgba(230, 230, 10, .3)" + }) + }), + yellow2: new Style({ + stroke: new Stroke({ + color: "rgba(250, 200, 0, .8)", + width: 2 + }), + fill: new Fill({ + color: "rgba(250, 200, 10, .3)" + }) + }), + yellow3: new Style({ + stroke: new Stroke({ + color: "rgba(250, 240, 10, .9)", + width: 5 + }), + fill: new Fill({ + color: "rgba(250, 240, 0, .7)" + }) + }), + red1: new Style({ + stroke: new Stroke({ + color: "rgba(255, 0, 0, 1)", + width: 4 + }) + }), + circleBlue: new Style({ + image: new Circle({ + radius: 5, + fill: new Fill({ color: "rgba(255, 0, 0, 0.1)" }), + stroke: new Stroke({ color: "blue", width: 1 }) + }) + }), + textFW1: new Style({ + text: new Text({ + font: 'bold 12px "Open Sans", "sans-serif"', + placement: "line", + fill: new Fill({ + color: "black" + }), + text: "LOS: 1" + //, zIndex: 10 + }) + }), + textFW2: new Style({ + text: new Text({ + font: 'bold 12px "Open Sans", "sans-serif"', + placement: "line", + fill: new Fill({ + color: "black" + }), + text: "LOS: 2" + //, zIndex: 10 + }) + }), + textFW3: new Style({ + text: new Text({ + font: 'bold 12px "Open Sans", "sans-serif"', + placement: "line", + fill: new Fill({ + color: "black" + }), + text: "LOS: 3" + //, zIndex: 10 + }) + }) +}; + +export default { + stretches(feature) { + let style = styles.yellow2; + if (feature.get("highlighted")) { + style = styles.yellow3; + } + return style; + }, + fwd1() { + return [styles.blue1, styles.textFW1]; + }, + fwd2() { + return [styles.blue2, styles.textFW2]; + }, + fwd3() { + return [styles.blue3, styles.textFW3]; + }, + bottleneck() { + return styles.yellow1; + }, + bottleneckStatus(feature, resolution, isLegend) { + let s = []; + if ((feature.get("fa_critical") && resolution > 15) || isLegend) { + let bnCenter = getCenter(feature.getGeometry().getExtent()); + s.push( + new Style({ + geometry: new Point(bnCenter), + image: new Icon({ + src: require("@/assets/marker-bottleneck-critical.png"), + anchor: [0.5, 0.5], + scale: isLegend ? 0.5 : 1 + }) + }) + ); + } + if (feature.get("fa_critical") && !isLegend) { + s.push(styles.red1); + } + return s; + }, + dma(feature, resolution) { + if (resolution < 10) { + var s = styles.circleBlue; + if (resolution < 6) { + s.setText( + new Text({ + offsetY: 12, + font: '10px "Open Sans", "sans-serif"', + fill: new Fill({ + color: "black" + }), + text: (feature.get("hectometre") / 10).toString() + }) + ); + } + return s; + } + return []; + }, + gauge(feature, resolution, isLegend) { + return [ + new Style({ + image: new Icon({ + src: require("@/assets/marker-gauge.png"), + anchor: [0.5, isLegend ? 0.5 : 1], + scale: isLegend ? 0.5 : 1 + }), + text: new Text({ + font: '10px "Open Sans", "sans-serif"', + offsetY: 8, + fill: new Fill({ + color: "white" + }), + text: feature.get("objname") + }) + }), + new Style({ + text: new Text({ + font: '10px "Open Sans", "sans-serif"', + offsetY: 7, + offsetX: -1, + fill: new Fill({ + color: "black" + }), + text: feature.get("objname") + }) + }) + ]; + } +}; diff -r 870d2a0e866b -r 44493664d40e client/src/components/toolbar/Linetool.vue --- a/client/src/components/toolbar/Linetool.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/toolbar/Linetool.vue Thu Apr 11 11:44:11 2019 +0200 @@ -26,7 +26,7 @@ export default { name: "linetool", computed: { - ...mapState("map", ["layers", "lineTool", "polygonTool", "cutTool"]), + ...mapState("map", ["openLayersMap", "lineTool", "polygonTool", "cutTool"]), label() { return this.$gettext("Measure Distance"); } @@ -37,7 +37,10 @@ this.polygonTool.setActive(false); this.cutTool.setActive(false); this.$store.commit("map/setCurrentMeasurement", null); - this.layers.DRAWTOOL.getSource().clear(); + this.openLayersMap + .getLayer("DRAWTOOL") + .getSource() + .clear(); } } }; diff -r 870d2a0e866b -r 44493664d40e client/src/components/toolbar/Polygontool.vue --- a/client/src/components/toolbar/Polygontool.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/toolbar/Polygontool.vue Thu Apr 11 11:44:11 2019 +0200 @@ -30,7 +30,7 @@ export default { name: "polygontool", computed: { - ...mapState("map", ["layers", "lineTool", "polygonTool", "cutTool"]), + ...mapState("map", ["openLayersMap", "lineTool", "polygonTool", "cutTool"]), label() { return this.$gettext("Measure Area"); } @@ -41,7 +41,10 @@ this.lineTool.setActive(false); this.cutTool.setActive(false); this.$store.commit("map/setCurrentMeasurement", null); - this.layers.DRAWTOOL.getSource().clear(); + this.openLayersMap + .getLayer("DRAWTOOL") + .getSource() + .clear(); } } }; diff -r 870d2a0e866b -r 44493664d40e client/src/components/toolbar/Toolbar.vue --- a/client/src/components/toolbar/Toolbar.vue Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/components/toolbar/Toolbar.vue Thu Apr 11 11:44:11 2019 +0200 @@ -125,7 +125,7 @@ Pdftool: () => import("./Pdftool") }, computed: { - ...mapState("map", ["layers", "lineTool", "polygonTool", "cutTool"]), + ...mapState("map", ["openLayersMap", "lineTool", "polygonTool", "cutTool"]), ...mapState("application", ["expandToolbar"]) }, mounted() { @@ -137,7 +137,10 @@ this.cutTool.setActive(false); this.$store.commit("map/setCurrentMeasurement", null); this.$store.dispatch("map/enableIdentifyTool"); - this.layers.DRAWTOOL.getSource().clear(); + this.openLayersMap + .getLayer("DRAWTOOL") + .getSource() + .clear(); } }); } diff -r 870d2a0e866b -r 44493664d40e client/src/store/bottlenecks.js --- a/client/src/store/bottlenecks.js Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/store/bottlenecks.js Thu Apr 11 11:44:11 2019 +0200 @@ -74,7 +74,10 @@ commit("application/splitscreenLoading", false, { root: true }); }, 350); rootState.map.cutTool.setActive(false); - rootState.map.layers.CUTTOOL.getSource().clear(); + rootState.map.openLayersMap + .getLayer("CUTTOOL") + .getSource() + .clear(); } if (name) { commit("application/showProfiles", true, { root: true }); diff -r 870d2a0e866b -r 44493664d40e client/src/store/fairway.js --- a/client/src/store/fairway.js Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/store/fairway.js Thu Apr 11 11:44:11 2019 +0200 @@ -137,7 +137,10 @@ dispatch("map/enableIdentifyTool", null, { root: true }); commit("clearCurrentProfile"); rootState.map.cutTool.setActive(false); - rootState.map.layers.CUTTOOL.getSource().clear(); + rootState.map.openLayersMap + .getLayer("CUTTOOL") + .getSource() + .clear(); }, loadProfile({ commit, state }, survey) { if (state.startPoint && state.endPoint) { @@ -216,7 +219,9 @@ Promise.all(profileLoaders) .then(() => { rootState.map.cutTool.setActive(false); - const los3 = rootState.map.layers.FAIRWAYDIMENSIONSLOS3; + const los3 = rootState.map.openLayersMap.getLayer( + "FAIRWAYDIMENSIONSLOS3" + ); los3.getSource().forEachFeatureIntersectingExtent( profileLine .clone() @@ -236,7 +241,9 @@ } } ); - const los2 = rootState.map.layers.FAIRWAYDIMENSIONSLOS2; + const los2 = rootState.map.openLayersMap.getLayer( + "FAIRWAYDIMENSIONSLOS2" + ); los2.getSource().forEachFeatureIntersectingExtent( profileLine .clone() @@ -256,7 +263,9 @@ } } ); - const los1 = rootState.map.layers.FAIRWAYDIMENSIONSLOS1; + const los1 = rootState.map.openLayersMap.getLayer( + "FAIRWAYDIMENSIONSLOS1" + ); los1.getSource().forEachFeatureIntersectingExtent( profileLine .clone() diff -r 870d2a0e866b -r 44493664d40e client/src/store/map.js --- a/client/src/store/map.js Thu Apr 11 10:11:59 2019 +0200 +++ b/client/src/store/map.js Thu Apr 11 11:44:11 2019 +0200 @@ -14,17 +14,8 @@ * * Thomas Junk */ -//import { HTTP } from "../lib/http"; - -import TileWMS from "ol/source/TileWMS"; -import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer"; -import OSM from "ol/source/OSM"; import Draw from "ol/interaction/Draw"; -import { Icon, Stroke, Style, Fill, Text, Circle } from "ol/style"; -import VectorSource from "ol/source/Vector"; -import Point from "ol/geom/Point"; -import { bbox as bboxStrategy } from "ol/loadingstrategy"; -import { HTTP } from "@/lib/http"; +import { Stroke, Style, Fill, Circle } from "ol/style"; import { fromLonLat } from "ol/proj"; import { getLength, getArea } from "ol/sphere"; import { unByKey } from "ol/Observable"; @@ -42,203 +33,6 @@ }); }; -const blue1 = new Style({ - stroke: new Stroke({ - color: "rgba(0, 0, 255, 0.8)", - lineDash: [2, 4], - lineCap: "round", - width: 2 - }), - fill: new Fill({ - color: "rgba(240, 230, 0, 0.2)" - }) -}); -const blue2 = new Style({ - stroke: new Stroke({ - color: "rgba(0, 0, 255, 0.9)", - lineDash: [3, 6], - lineCap: "round", - width: 2 - }), - fill: new Fill({ - color: "rgba(240, 230, 0, 0.1)" - }) -}); -const blue3 = new Style({ - stroke: new Stroke({ - color: "rgba(0, 0, 255, 1.0)", - width: 2 - }), - fill: new Fill({ - color: "rgba(255, 255, 255, 0.4)" - }) -}); -const yellow1 = new Style({ - stroke: new Stroke({ - color: "rgba(230, 230, 10, .8)", - width: 4 - }), - fill: new Fill({ - color: "rgba(230, 230, 10, .3)" - }) -}); -const yellow2 = new Style({ - stroke: new Stroke({ - color: "rgba(250, 200, 0, .8)", - width: 2 - }), - fill: new Fill({ - color: "rgba(250, 200, 10, .3)" - }) -}); -const yellow3 = new Style({ - stroke: new Stroke({ - color: "rgba(250, 240, 10, .9)", - width: 5 - }), - fill: new Fill({ - color: "rgba(250, 240, 0, .7)" - }) -}); -const red1 = new Style({ - stroke: new Stroke({ - color: "rgba(255, 0, 0, 1)", - width: 4 - }) -}); - -const circleBlue = new Style({ - image: new Circle({ - radius: 5, - fill: new Fill({ color: "rgba(255, 0, 0, 0.1)" }), - stroke: new Stroke({ color: "blue", width: 1 }) - }) -}); - -const textFW1 = new Style({ - text: new Text({ - font: 'bold 12px "Open Sans", "sans-serif"', - placement: "line", - fill: new Fill({ - color: "black" - }), - text: "LOS: 1" - //, zIndex: 10 - }) -}); -const textFW2 = new Style({ - text: new Text({ - font: 'bold 12px "Open Sans", "sans-serif"', - placement: "line", - fill: new Fill({ - color: "black" - }), - text: "LOS: 2" - //, zIndex: 10 - }) -}); -const textFW3 = new Style({ - text: new Text({ - font: 'bold 12px "Open Sans", "sans-serif"', - placement: "line", - fill: new Fill({ - color: "black" - }), - text: "LOS: 3" - //, zIndex: 10 - }) -}); - -const stretchesStyle = feature => { - let style = yellow2; - if (feature.get("highlighted")) { - style = yellow3; - } - return style; -}; -const fwd1Style = () => { - return [blue1, textFW1]; -}; -const fwd2Style = () => { - return [blue2, textFW2]; -}; -const fwd3Style = () => { - return [blue3, textFW3]; -}; -const bottleneckStyle = () => { - return yellow1; -}; -const bottleneckStatusStyle = (feature, resolution, isLegend) => { - let styles = []; - if ((feature.get("fa_critical") && resolution > 15) || isLegend) { - let bnCenter = getCenter(feature.getGeometry().getExtent()); - styles.push( - new Style({ - geometry: new Point(bnCenter), - image: new Icon({ - src: require("@/assets/marker-bottleneck-critical.png"), - anchor: [0.5, 0.5], - scale: isLegend ? 0.5 : 1 - }) - }) - ); - } - if (feature.get("fa_critical") && !isLegend) { - styles.push(red1); - } - return styles; -}; -const dmaStyle = (feature, resolution) => { - if (resolution < 10) { - var s = circleBlue; - if (resolution < 6) { - s.setText( - new Text({ - offsetY: 12, - font: '10px "Open Sans", "sans-serif"', - fill: new Fill({ - color: "black" - }), - text: (feature.get("hectometre") / 10).toString() - }) - ); - } - return s; - } else { - return []; - } -}; -const gaugeStyle = (feature, resolution, isLegend) => { - return [ - new Style({ - image: new Icon({ - src: require("@/assets/marker-gauge.png"), - anchor: [0.5, isLegend ? 0.5 : 1], - scale: isLegend ? 0.5 : 1 - }), - text: new Text({ - font: '10px "Open Sans", "sans-serif"', - offsetY: 8, - fill: new Fill({ - color: "white" - }), - text: feature.get("objname") - }) - }), - new Style({ - text: new Text({ - font: '10px "Open Sans", "sans-serif"', - offsetY: 7, - offsetX: -1, - fill: new Fill({ - color: "black" - }), - text: feature.get("objname") - }) - }) - ]; -}; - // initial state const init = () => { return { @@ -256,283 +50,7 @@ polygonTool: null, // open layers interaction object (Draw) cutTool: null, // open layers interaction object (Draw) isolinesLegendImgDataURL: "", - differencesLegendImgDataURL: "", - layers: { - OPENSTREETMAP: new TileLayer({ - label: "Open Streetmap", - visible: true, - source: new OSM() - }), - INLANDECDIS: new TileLayer({ - label: "Inland ECDIS chart Danube", - visible: true, - source: new TileWMS({ - preload: 1, - url: "https://service.d4d-portal.info/wms/", - crossOrigin: "anonymous", - params: { LAYERS: "d4d", VERSION: "1.1.1", TILED: true } - }) - }), - WATERWAYAREA: new VectorLayer({ - label: "Waterway Area", - visible: true, - source: new VectorSource({ - strategy: bboxStrategy - }), - style: new Style({ - stroke: new Stroke({ - color: "rgba(0, 102, 0, 1)", - width: 2 - }) - }) - }), - STRETCHES: new VectorLayer({ - label: "Stretches", - visible: false, - source: new VectorSource({ - strategy: bboxStrategy - }), - style: stretchesStyle - }), - FAIRWAYDIMENSIONSLOS1: new VectorLayer({ - label: "LOS 1 Fairway Dimensions", - visible: false, - source: new VectorSource(), - style: fwd1Style - }), - FAIRWAYDIMENSIONSLOS2: new VectorLayer({ - label: "LOS 2 Fairway Dimensions", - visible: false, - source: new VectorSource(), - style: fwd2Style - }), - FAIRWAYDIMENSIONSLOS3: new VectorLayer({ - label: "LOS 3 Fairway Dimensions", - visible: true, - source: new VectorSource(), - style: fwd3Style - }), - WATERWAYAXIS: new VectorLayer({ - label: "Waterway Axis", - visible: true, - source: new VectorSource({ - strategy: bboxStrategy - }), - style: new Style({ - stroke: new Stroke({ - color: "rgba(0, 0, 255, .5)", - lineDash: [5, 5], - width: 2 - }) - }), - // TODO: Set layer in layertree active/inactive depending on - // resolution. - maxResolution: 5, - minResolution: 0 - }), - WATERWAYPROFILES: new VectorLayer({ - label: "Waterway Profiles", - visible: true, - source: new VectorSource({ - strategy: bboxStrategy - }), - style: new Style({ - stroke: new Stroke({ - color: "rgba(0, 0, 255, .5)", - lineDash: [5, 5], - width: 2 - }) - }), - maxResolution: 2.5, - minResolution: 0 - }), - BOTTLENECKS: new VectorLayer({ - label: "Bottlenecks", - visible: true, - source: new VectorSource({ - strategy: bboxStrategy - }), - style: bottleneckStyle - }), - BOTTLENECKISOLINE: new TileLayer({ - 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); - }) - }), - DIFFERENCES: new TileLayer({ - label: "Bottleneck Differences", - visible: false, - source: new TileWMS({ - preload: 0, - projection: "EPSG:4326", - 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") - }, - responseType: "blob" - }).then(response => { - tile.getImage().src = URL.createObjectURL(response.data); - }); - } // TODO tile.setState(TileState.ERROR); - }) - }), - BOTTLENECKSTATUS: new VectorLayer({ - label: "Critical Bottlenecks", - forLegendStyle: { point: true, resolution: 16 }, - visible: true, - source: new VectorSource({ - strategy: bboxStrategy - }), - style: bottleneckStatusStyle - }), - DISTANCEMARKS: new VectorLayer({ - label: "Distance marks", - forLegendStyle: { point: true, resolution: 8 }, - visible: false, - source: new VectorSource({ - strategy: bboxStrategy - }) - }), - DISTANCEMARKSAXIS: new VectorLayer({ - label: "Distance marks, Axis", - forLegendStyle: { point: true, resolution: 8 }, - visible: true, - source: new VectorSource({ - strategy: bboxStrategy - }), - style: dmaStyle - }), - GAUGES: new VectorLayer({ - label: "Gauges", - forLegendStyle: { point: true, resolution: 8 }, - visible: true, - source: new VectorSource({ - strategy: bboxStrategy - }), - style: gaugeStyle, - maxResolution: 100, - minResolution: 0 - }), - DRAWTOOL: new VectorLayer({ - label: "Draw Tool", - visible: true, - source: new VectorSource({ wrapX: false }), - style: function(feature) { - // adapted from OpenLayer's LineString Arrow Example - var geometry = feature.getGeometry(); - var styles = [ - // linestring - new Style({ - stroke: new Stroke({ - color: "#369aca", - width: 2 - }) - }) - ]; - - if (geometry.getType() === "LineString") { - geometry.forEachSegment(function(start, end) { - var dx = end[0] - start[0]; - var dy = end[1] - start[1]; - var rotation = Math.atan2(dy, dx); - // arrows - styles.push( - new Style({ - geometry: new Point(end), - image: new Icon({ - // we need to make sure the image is loaded by Vue Loader - src: require("@/assets/linestring_arrow.png"), - // fiddling with the anchor's y value does not help to - // position the image more centered on the line ending, as the - // default line style seems to be slightly uncentered in the - // anti-aliasing, but the image is not placed with subpixel - // precision - anchor: [0.75, 0.5], - rotateWithView: true, - rotation: -rotation - }) - }) - ); - }); - } - return styles; - } - }), - CUTTOOL: new VectorLayer({ - label: "Cut Tool", - visible: true, - source: new VectorSource({ wrapX: false }), - style: function(feature) { - // adapted from OpenLayer's LineString Arrow Example - var geometry = feature.getGeometry(); - var styles = [ - // linestring - new Style({ - stroke: new Stroke({ - color: "#333333", - width: 2, - lineDash: [7, 7] - }) - }) - ]; - - if (geometry.getType() === "LineString") { - geometry.forEachSegment(function(start, end) { - var dx = end[0] - start[0]; - var dy = end[1] - start[1]; - var rotation = Math.atan2(dy, dx); - // arrows - styles.push( - new Style({ - geometry: new Point(end), - image: new Icon({ - // we need to make sure the image is loaded by Vue Loader - src: require("@/assets/linestring_arrow_grey.png"), - // fiddling with the anchor's y value does not help to - // position the image more centered on the line ending, as the - // default line style seems to be slightly uncentered in the - // anti-aliasing, but the image is not placed with subpixel - // precision - anchor: [0.75, 0.5], - rotateWithView: true, - rotation: -rotation - }) - }) - ); - }); - } - return styles; - } - }) - } + differencesLegendImgDataURL: "" }; }; @@ -602,9 +120,9 @@ } }, actions: { - openLayersMap({ commit, dispatch, state }, map) { - const drawVectorSrc = state.layers.DRAWTOOL.getSource(); - const cutVectorSrc = state.layers.CUTTOOL.getSource(); + openLayersMap({ commit, dispatch }, map) { + const drawVectorSrc = map.getLayer("DRAWTOOL").getSource(); + const cutVectorSrc = map.getLayer("CUTTOOL").getSource(); // init line tool const lineTool = new Draw({ @@ -814,7 +332,9 @@ */ // trying the GetFeatureInfo way for WMS - var wmsSource = state.layers.INLANDECDIS.getSource(); + var wmsSource = state.openLayersMap + .getLayer("INLANDECDIS") + .getSource(); var url = wmsSource.getGetFeatureInfoUrl( event.coordinate, 100 /* resolution */,