changeset 3062:87e0422cffa7

client: draw/cut tools work now with multiple maps
author Markus Kottlaender <markus@intevation.de>
date Tue, 16 Apr 2019 12:49:29 +0200
parents 563176194d74
children 333aff79197d
files client/src/components/fairway/Profiles.vue client/src/components/map/Map.vue client/src/components/toolbar/Linetool.vue client/src/components/toolbar/Polygontool.vue client/src/components/toolbar/Toolbar.vue client/src/store/bottlenecks.js client/src/store/fairway.js client/src/store/map.js
diffstat 8 files changed, 190 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/fairway/Profiles.vue	Tue Apr 16 12:39:55 2019 +0200
+++ b/client/src/components/fairway/Profiles.vue	Tue Apr 16 12:49:29 2019 +0200
@@ -185,10 +185,8 @@
               :class="startPoint && endPoint && !selectedCut ? 'w-50' : 'w-100'"
             >
               <button class="btn btn-info btn-sm w-100" @click="toggleCutTool">
-                <font-awesome-icon
-                  :icon="cutTool && cutTool.getActive() ? 'times' : 'plus'"
-                />
-                {{ cutTool && cutTool.getActive() ? "Cancel" : "New" }}
+                <font-awesome-icon :icon="cutToolEnabled ? 'times' : 'plus'" />
+                {{ cutToolEnabled ? "Cancel" : "New" }}
               </button>
             </div>
           </div>
@@ -264,7 +262,7 @@
   },
   computed: {
     ...mapState("application", ["showProfiles"]),
-    ...mapState("map", ["lineTool", "polygonTool", "cutTool"]),
+    ...mapState("map", ["openLayersMaps", "cutToolEnabled"]),
     ...mapState("bottlenecks", [
       "bottlenecksList",
       "surveys",
@@ -349,10 +347,11 @@
         if (!cut) {
           this.$store.commit("fairwayprofile/clearCurrentProfile");
           this.$store.commit("application/showSplitscreen", false);
-          this.openLayersMap
-            .getLayer("CUTTOOL")
-            .getSource()
-            .clear();
+          this.openLayersMaps.forEach(m => {
+            m.getLayer("CUTTOOL")
+              .getSource()
+              .clear();
+          });
         }
       }
     },
@@ -457,9 +456,9 @@
       }
     },
     toggleCutTool() {
-      this.cutTool.setActive(!this.cutTool.getActive());
-      this.lineTool.setActive(false);
-      this.polygonTool.setActive(false);
+      this.$store.commit("map/cutToolEnabled", !this.cutToolEnabled);
+      this.$store.commit("map/lineToolEnabled", false);
+      this.$store.commit("map/polygonToolEnabled", false);
       this.$store.commit("map/setCurrentMeasurement", null);
     },
     onCopyCoordinates() {
@@ -485,20 +484,22 @@
       coordinates = coordinates.filter(c => Number(c) === c);
       if (coordinates.length === 4) {
         // draw line on map
-        this.openLayersMap
-          .getLayer("CUTTOOL")
-          .getSource()
-          .clear();
+        this.openLayersMaps.forEach(m => {
+          m.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.openLayersMap
-          .getLayer("CUTTOOL")
-          .getSource()
-          .addFeature(cut);
+        this.openLayersMaps.forEach(m => {
+          m.getLayer("CUTTOOL")
+            .getSource()
+            .addFeature(cut);
+        });
 
         // draw diagram
         this.$store.dispatch("fairwayprofile/cut", cut);
--- a/client/src/components/map/Map.vue	Tue Apr 16 12:39:55 2019 +0200
+++ b/client/src/components/map/Map.vue	Tue Apr 16 12:49:29 2019 +0200
@@ -72,11 +72,21 @@
       return layers();
     },
     hasActiveInteractions() {
-      return (
-        (this.lineTool && this.lineTool.getActive()) ||
-        (this.polygonTool && this.polygonTool.getActive()) ||
-        (this.cutTool && this.cutTool.getActive())
-      );
+      let active = false;
+      if (this.map) {
+        this.map
+          .getInteractions()
+          .getArray()
+          .filter(i =>
+            ["linetool", "polygontool", "cuttool"].includes(i.get("id"))
+          )
+          .forEach(i => {
+            if (i.getActive()) {
+              active = true;
+            }
+          });
+      }
+      return active;
     }
   },
   methods: {
--- a/client/src/components/toolbar/Linetool.vue	Tue Apr 16 12:39:55 2019 +0200
+++ b/client/src/components/toolbar/Linetool.vue	Tue Apr 16 12:49:29 2019 +0200
@@ -1,9 +1,6 @@
 <template>
-  <div @click="toggleLineTool" class="toolbar-button" v-tooltip.right="label">
-    <font-awesome-icon
-      icon="ruler"
-      :class="{ 'text-info': lineTool && lineTool.getActive() }"
-    />
+  <div @click="toggle" class="toolbar-button" v-tooltip.right="label">
+    <font-awesome-icon icon="ruler" :class="{ 'text-info': lineToolEnabled }" />
   </div>
 </template>
 
@@ -21,27 +18,27 @@
  * Author(s):
  * Markus Kottländer <markus.kottlaender@intevation.de>
  */
-import { mapState, mapGetters } from "vuex";
+import { mapState } from "vuex";
 
 export default {
   name: "linetool",
   computed: {
-    ...mapState("map", ["lineTool", "polygonTool", "cutTool"]),
-    ...mapGetters("map", ["openLayersMap"]),
+    ...mapState("map", ["openLayersMaps", "lineToolEnabled"]),
     label() {
       return this.$gettext("Measure Distance");
     }
   },
   methods: {
-    toggleLineTool() {
-      this.lineTool.setActive(!this.lineTool.getActive());
-      this.polygonTool.setActive(false);
-      this.cutTool.setActive(false);
+    toggle() {
+      this.$store.commit("map/lineToolEnabled", !this.lineToolEnabled);
+      this.$store.commit("map/polygonToolEnabled", false);
+      this.$store.commit("map/cutToolEnabled", false);
       this.$store.commit("map/setCurrentMeasurement", null);
-      this.openLayersMap
-        .getLayer("DRAWTOOL")
-        .getSource()
-        .clear();
+      this.openLayersMaps.forEach(m => {
+        m.getLayer("DRAWTOOL")
+          .getSource()
+          .clear();
+      });
     }
   }
 };
--- a/client/src/components/toolbar/Polygontool.vue	Tue Apr 16 12:39:55 2019 +0200
+++ b/client/src/components/toolbar/Polygontool.vue	Tue Apr 16 12:49:29 2019 +0200
@@ -1,12 +1,8 @@
 <template>
-  <div
-    @click="togglePolygonTool"
-    class="toolbar-button"
-    v-tooltip.right="label"
-  >
+  <div @click="toggle" class="toolbar-button" v-tooltip.right="label">
     <font-awesome-icon
       icon="draw-polygon"
-      :class="{ 'text-info': polygonTool && polygonTool.getActive() }"
+      :class="{ 'text-info': polygonToolEnabled }"
     />
   </div>
 </template>
@@ -25,27 +21,27 @@
  * Author(s):
  * Markus Kottländer <markus.kottlaender@intevation.de>
  */
-import { mapState, mapGetters } from "vuex";
+import { mapState } from "vuex";
 
 export default {
   name: "polygontool",
   computed: {
-    ...mapState("map", ["lineTool", "polygonTool", "cutTool"]),
-    ...mapGetters("map", ["openLayersMap"]),
+    ...mapState("map", ["openLayersMaps", "polygonToolEnabled"]),
     label() {
       return this.$gettext("Measure Area");
     }
   },
   methods: {
-    togglePolygonTool() {
-      this.polygonTool.setActive(!this.polygonTool.getActive());
-      this.lineTool.setActive(false);
-      this.cutTool.setActive(false);
+    toggle() {
+      this.$store.commit("map/polygonToolEnabled", !this.polygonToolEnabled);
+      this.$store.commit("map/lineToolEnabled", false);
+      this.$store.commit("map/cutToolEnabled", false);
       this.$store.commit("map/setCurrentMeasurement", null);
-      this.openLayersMap
-        .getLayer("DRAWTOOL")
-        .getSource()
-        .clear();
+      this.openLayersMaps.forEach(m => {
+        m.getLayer("DRAWTOOL")
+          .getSource()
+          .clear();
+      });
     }
   }
 };
--- a/client/src/components/toolbar/Toolbar.vue	Tue Apr 16 12:39:55 2019 +0200
+++ b/client/src/components/toolbar/Toolbar.vue	Tue Apr 16 12:49:29 2019 +0200
@@ -116,7 +116,7 @@
  * Author(s):
  * Markus Kottländer <markus.kottlaender@intevation.de>
  */
-import { mapState, mapGetters } from "vuex";
+import { mapState } from "vuex";
 
 export default {
   name: "toolbar",
@@ -131,23 +131,23 @@
     Pdftool: () => import("./Pdftool")
   },
   computed: {
-    ...mapState("map", ["lineTool", "polygonTool", "cutTool"]),
-    ...mapState("application", ["expandToolbar", "panes"]),
-    ...mapGetters("map", ["openLayersMap"])
+    ...mapState("map", ["openLayersMaps"]),
+    ...mapState("application", ["expandToolbar"])
   },
   mounted() {
     window.addEventListener("keydown", e => {
       // Escape
       if (e.keyCode === 27) {
-        this.lineTool.setActive(false);
-        this.polygonTool.setActive(false);
-        this.cutTool.setActive(false);
+        this.$store.commit("map/lineToolEnabled", false);
+        this.$store.commit("map/polygonToolEnabled", false);
+        this.$store.commit("map/cutToolEnabled", false);
         this.$store.commit("map/setCurrentMeasurement", null);
         this.$store.commit("map/identifyToolEnabled", true);
-        this.openLayersMap
-          .getLayer("DRAWTOOL")
-          .getSource()
-          .clear();
+        this.openLayersMaps.forEach(m => {
+          m.getLayer("DRAWTOOL")
+            .getSource()
+            .clear();
+        });
       }
     });
   }
--- a/client/src/store/bottlenecks.js	Tue Apr 16 12:39:55 2019 +0200
+++ b/client/src/store/bottlenecks.js	Tue Apr 16 12:49:29 2019 +0200
@@ -60,7 +60,7 @@
     }
   },
   actions: {
-    setSelectedBottleneck({ state, commit, rootState, rootGetters }, name) {
+    setSelectedBottleneck({ state, commit, rootState }, name) {
       return new Promise((resolve, reject) => {
         if (name !== state.selectedBottleneck) {
           commit("selectedSurvey", null);
@@ -73,11 +73,12 @@
             commit("fairwayprofile/clearCurrentProfile", null, { root: true });
             commit("application/splitscreenLoading", false, { root: true });
           }, 350);
-          rootState.map.cutTool.setActive(false);
-          rootGetters["map/openLayersMap"]
-            .getLayer("CUTTOOL")
-            .getSource()
-            .clear();
+          commit("map/cutToolEnabled", false, { root: true });
+          rootState.map.openLayersMaps.forEach(m => {
+            m.getLayer("CUTTOOL")
+              .getSource()
+              .clear();
+          });
         }
         if (name) {
           commit("application/showProfiles", true, { root: true });
--- a/client/src/store/fairway.js	Tue Apr 16 12:39:55 2019 +0200
+++ b/client/src/store/fairway.js	Tue Apr 16 12:49:29 2019 +0200
@@ -132,15 +132,16 @@
     }
   },
   actions: {
-    clearSelection({ commit, dispatch, rootState, rootGetters }) {
+    clearSelection({ commit, dispatch, rootState }) {
       dispatch("bottlenecks/setSelectedBottleneck", null, { root: true });
       commit("map/identifyToolEnabled", true, { root: true });
       commit("clearCurrentProfile");
-      rootState.map.cutTool.setActive(false);
-      rootGetters["map/openLayersMap"]
-        .getLayer("CUTTOOL")
-        .getSource()
-        .clear();
+      commit("map/cutToolEnabled", false, { root: true });
+      rootState.map.openLayersMaps.forEach(m => {
+        m.getLayer("CUTTOOL")
+          .getSource()
+          .clear();
+      });
     },
     loadProfile({ commit, state }, survey) {
       if (state.startPoint && state.endPoint) {
@@ -218,7 +219,7 @@
           commit("profileLoading", true);
           Promise.all(profileLoaders)
             .then(() => {
-              rootState.map.cutTool.setActive(false);
+              commit("map/cutToolEnabled", false, { root: true });
               const los3 = rootGetters["map/openLayersMap"].getLayer(
                 "FAIRWAYDIMENSIONSLOS3"
               );
--- a/client/src/store/map.js	Tue Apr 16 12:39:55 2019 +0200
+++ b/client/src/store/map.js	Tue Apr 16 12:49:29 2019 +0200
@@ -39,9 +39,9 @@
     identifyToolEnabled: true, // event binding (singleclick, dblclick)
     identifiedFeatures: [], // map features identified by clicking on the map
     currentMeasurement: null, // distance or area from line-/polygon-/cutTool
-    lineTool: null, // open layers interaction object (Draw)
-    polygonTool: null, // open layers interaction object (Draw)
-    cutTool: null, // open layers interaction object (Draw)
+    lineToolEnabled: false,
+    polygonToolEnabled: false,
+    cutToolEnabled: false,
     isolinesLegendImgDataURL: "",
     differencesLegendImgDataURL: ""
   };
@@ -91,14 +91,41 @@
     setCurrentMeasurement: (state, measurement) => {
       state.currentMeasurement = measurement;
     },
-    lineTool: (state, lineTool) => {
-      state.lineTool = lineTool;
+    lineToolEnabled: (state, enabled) => {
+      state.lineToolEnabled = enabled;
+      state.openLayersMaps.forEach(m => {
+        let tool = m
+          .getInteractions()
+          .getArray()
+          .find(i => i.get("id") === "linetool");
+        if (tool) {
+          tool.setActive(enabled);
+        }
+      });
     },
-    polygonTool: (state, polygonTool) => {
-      state.polygonTool = polygonTool;
+    polygonToolEnabled: (state, enabled) => {
+      state.polygonToolEnabled = enabled;
+      state.openLayersMaps.forEach(m => {
+        let tool = m
+          .getInteractions()
+          .getArray()
+          .find(i => i.get("id") === "polygontool");
+        if (tool) {
+          tool.setActive(enabled);
+        }
+      });
     },
-    cutTool: (state, cutTool) => {
-      state.cutTool = cutTool;
+    cutToolEnabled: (state, enabled) => {
+      state.cutToolEnabled = enabled;
+      state.openLayersMaps.forEach(m => {
+        let tool = m
+          .getInteractions()
+          .getArray()
+          .find(i => i.get("id") === "cuttool");
+        if (tool) {
+          tool.setActive(enabled);
+        }
+      });
     },
     isolinesLegendImgDataURL: (state, isolinesLegendImgDataURL) => {
       state.isolinesLegendImgDataURL = isolinesLegendImgDataURL;
@@ -108,7 +135,7 @@
     }
   },
   actions: {
-    openLayersMap({ commit, dispatch }, map) {
+    openLayersMap({ state, commit, dispatch }, map) {
       const drawVectorSrc = map.getLayer("DRAWTOOL").getSource();
       const cutVectorSrc = map.getLayer("CUTTOOL").getSource();
 
@@ -118,9 +145,14 @@
         type: "LineString",
         maxPoints: 2
       });
+      lineTool.set("id", "linetool");
       lineTool.setActive(false);
       lineTool.on("drawstart", () => {
-        drawVectorSrc.clear();
+        state.openLayersMaps.forEach(m => {
+          m.getLayer("DRAWTOOL")
+            .getSource()
+            .clear();
+        });
         commit("setCurrentMeasurement", null);
       });
       lineTool.on("drawend", event => {
@@ -138,9 +170,14 @@
         type: "Polygon",
         maxPoints: 50
       });
+      polygonTool.set("id", "polygontool");
       polygonTool.setActive(false);
       polygonTool.on("drawstart", () => {
-        drawVectorSrc.clear();
+        state.openLayersMaps.forEach(m => {
+          m.getLayer("DRAWTOOL")
+            .getSource()
+            .clear();
+        });
         commit("setCurrentMeasurement", null);
       });
       polygonTool.on("drawend", event => {
@@ -174,10 +211,15 @@
           })
         })
       });
+      cutTool.set("id", "cuttool");
       cutTool.setActive(false);
       cutTool.on("drawstart", () => {
         commit("identifyToolEnabled", false);
-        cutVectorSrc.clear();
+        state.openLayersMaps.forEach(m => {
+          m.getLayer("CUTTOOL")
+            .getSource()
+            .clear();
+        });
       });
       cutTool.on("drawend", event => {
         commit("fairwayprofile/selectedCut", null, { root: true });
@@ -193,9 +235,53 @@
       map.addInteraction(cutTool);
       map.addInteraction(polygonTool);
 
-      commit("lineTool", lineTool);
-      commit("polygonTool", polygonTool);
-      commit("cutTool", cutTool);
+      // If there are multiple maps and you enable one of the draw tools, when
+      // moving the mouse to another map, the cursor for the draw tool stays
+      // visible in the first map, right next to the edge where the cursor left
+      // the map. So here we disable all draw layers except the ones in the map
+      // that the user currently hovering with the mouse.
+      map.getTargetElement().addEventListener("mouseenter", () => {
+        if (
+          state.lineToolEnabled ||
+          state.polygonToolEnabled ||
+          state.cutToolEnabled
+        ) {
+          state.openLayersMaps.forEach(m => {
+            let lineTool = m
+              .getInteractions()
+              .getArray()
+              .find(i => i.get("id") === "linetool");
+            let polygonTool = m
+              .getInteractions()
+              .getArray()
+              .find(i => i.get("id") === "polygontool");
+            let cutTool = m
+              .getInteractions()
+              .getArray()
+              .find(i => i.get("id") === "cuttool");
+            if (lineTool) lineTool.setActive(false);
+            if (polygonTool) polygonTool.setActive(false);
+            if (cutTool) cutTool.setActive(false);
+          });
+          let lineTool = map
+            .getInteractions()
+            .getArray()
+            .find(i => i.get("id") === "linetool");
+          let polygonTool = map
+            .getInteractions()
+            .getArray()
+            .find(i => i.get("id") === "polygontool");
+          let cutTool = map
+            .getInteractions()
+            .getArray()
+            .find(i => i.get("id") === "cuttool");
+          if (lineTool && state.lineToolEnabled) lineTool.setActive(true);
+          if (polygonTool && state.polygonToolEnabled)
+            polygonTool.setActive(true);
+          if (cutTool && state.cutToolEnabled) cutTool.setActive(true);
+        }
+      });
+
       commit("addOpenLayersMap", map);
     },
     initIdentifyTool({ state, rootState, commit, dispatch }, map) {