changeset 3016:083cd270bdfd

client: splitview: implemented rotation mechanism
author Markus Kottlaender <markus@intevation.de>
date Thu, 11 Apr 2019 16:44:27 +0200
parents fe88a9b151ca
children 9a408a8b74b8
files client/src/components/Main.vue client/src/components/map/Map.vue
diffstat 2 files changed, 99 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/Main.vue	Thu Apr 11 16:43:14 2019 +0200
+++ b/client/src/components/Main.vue	Thu Apr 11 16:44:27 2019 +0200
@@ -6,6 +6,19 @@
       { 'flex-column': ['left', 'right'].includes(paneMode) }
     ]"
   >
+    <div
+      v-if="panes.length !== 1"
+      id="pane-controls"
+      class="position-absolute wh-100 d-flex justify-content-center align-items-center"
+    >
+      <div
+        class="box-control bg-white ui-element small shadow-sm"
+        @click="togglePaneMode"
+      >
+        <font-awesome-icon icon="redo" fixed-width />
+      </div>
+    </div>
+
     <template v-if="panes.length === 1">
       <div id="pane1" class="pane wh-100"><component :is="panes[0]" /></div>
     </template>
@@ -34,34 +47,34 @@
         <div id="pane1" class="pane w-100 h-50">
           <component :is="panes[0]" />
         </div>
+        <div id="pane3" class="pane w-50 h-50">
+          <component :is="panes[2]" />
+        </div>
+        <div id="pane2" class="pane w-50 h-50">
+          <component :is="panes[1]" />
+        </div>
+      </template>
+      <template v-if="paneMode === 'right'">
+        <div id="pane3" class="pane w-50 h-50">
+          <component :is="panes[2]" />
+        </div>
+        <div id="pane2" class="pane w-50 h-50">
+          <component :is="panes[1]" />
+        </div>
+        <div id="pane1" class="pane w-50 h-100">
+          <component :is="panes[0]" />
+        </div>
+      </template>
+      <template v-if="paneMode === 'bottom'">
         <div id="pane2" class="pane w-50 h-50">
           <component :is="panes[1]" />
         </div>
         <div id="pane3" class="pane w-50 h-50">
           <component :is="panes[2]" />
         </div>
-      </template>
-      <template v-if="paneMode === 'right'">
-        <div id="pane1" class="pane w-50 h-50">
+        <div id="pane1" class="pane w-100 h-50">
           <component :is="panes[0]" />
         </div>
-        <div id="pane2" class="pane w-50 h-50">
-          <component :is="panes[1]" />
-        </div>
-        <div id="pane3" class="pane w-50 h-100">
-          <component :is="panes[2]" />
-        </div>
-      </template>
-      <template v-if="paneMode === 'bottom'">
-        <div id="pane1" class="pane w-50 h-50">
-          <component :is="panes[0]" />
-        </div>
-        <div id="pane2" class="pane w-50 h-50">
-          <component :is="panes[1]" />
-        </div>
-        <div id="pane3" class="pane w-100 h-50">
-          <component :is="panes[2]" />
-        </div>
       </template>
       <template v-if="paneMode === 'left'">
         <div id="pane1" class="pane w-50 h-100">
@@ -79,8 +92,8 @@
     <template v-if="panes.length === 4">
       <div id="pane1" class="pane w-50 h-50"><component :is="panes[0]" /></div>
       <div id="pane2" class="pane w-50 h-50"><component :is="panes[1]" /></div>
+      <div id="pane4" class="pane w-50 h-50"><component :is="panes[3]" /></div>
       <div id="pane3" class="pane w-50 h-50"><component :is="panes[2]" /></div>
-      <div id="pane4" class="pane w-50 h-50"><component :is="panes[3]" /></div>
     </template>
   </div>
 </template>
@@ -92,6 +105,9 @@
   bottom: -1.5px
   left: -1.5px
   z-index: 1
+  #pane-controls
+    z-index: 1
+    pointer-events: none
   .pane
     border: solid 1.5px #fff
     background-color: #eee
@@ -123,8 +139,57 @@
     // all components that are supposed to be displayed in a pane must be registered here
     Map: () => import("./map/Map")
   },
+  data() {
+    return {
+      // This is needed to accomplish a true rotation of components/panes with
+      // two panes. On every second "rotation" the components are fliped. This way
+      // toggling between horizontal and vertical mode feels like the components
+      // are actually rotating. See: togglePaneMode()
+      rotations: 0
+    };
+  },
   computed: {
     ...mapState("application", ["panes", "paneMode"])
+  },
+  watch: {
+    panes(panes) {
+      if (panes.length !== 2) this.rotations = 0;
+    }
+  },
+  methods: {
+    rotateComponents() {
+      this.panes.unshift(this.panes.pop());
+    },
+    togglePaneMode() {
+      if (this.panes.length === 2) {
+        this.$store.commit(
+          "application/paneMode",
+          this.paneMode === "horizontal" ? "vertical" : "horizontal"
+        );
+        if (++this.rotations % 2) {
+          this.rotateComponents();
+        }
+      }
+      if (this.panes.length === 3) {
+        let next;
+        if (this.paneMode === "top") {
+          next = "right";
+        }
+        if (this.paneMode === "right") {
+          next = "bottom";
+        }
+        if (this.paneMode === "bottom") {
+          next = "left";
+        }
+        if (this.paneMode === "left") {
+          next = "top";
+        }
+        this.$store.commit("application/paneMode", next);
+      }
+      if (this.panes.length === 4) {
+        this.rotateComponents();
+      }
+    }
   }
 };
 </script>
--- a/client/src/components/map/Map.vue	Thu Apr 11 16:43:14 2019 +0200
+++ b/client/src/components/map/Map.vue	Thu Apr 11 16:44:27 2019 +0200
@@ -53,6 +53,7 @@
   mixins: [uuid],
   data() {
     return {
+      map: null,
       splitscreen: false
     };
   },
@@ -66,7 +67,7 @@
       "cutTool"
     ]),
     ...mapState("bottlenecks", ["selectedSurvey"]),
-    ...mapState("application", ["showSplitscreen"]),
+    ...mapState("application", ["showSplitscreen", "panes", "paneMode"]),
     ...mapState("imports", ["selectedStretchId"]),
     hasActiveInteractions() {
       return (
@@ -101,11 +102,14 @@
         this.splitscreen = false;
       }
     },
+    panes() {
+      this.$nextTick(() => this.map.updateSize());
+    },
+    paneMode() {
+      this.$nextTick(() => this.map.updateSize());
+    },
     splitscreen() {
-      const map = this.openLayersMap;
-      this.$nextTick(() => {
-        map && map.updateSize();
-      });
+      this.$nextTick(() => this.map.updateSize());
     },
     selectedSurvey(newSelectedSurvey) {
       if (newSelectedSurvey) {
@@ -131,7 +135,7 @@
     }
   },
   mounted() {
-    const map = new Map({
+    this.map = new Map({
       layers: layers.config,
       target: "map-" + this.uuid,
       controls: [],
@@ -142,11 +146,11 @@
         projection: "EPSG:3857"
       })
     });
-    map.getLayer = id => layers.get(id);
+    this.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 => {
+    this.map.on("moveend", event => {
       const center = event.map.getView().getCenter();
       this.$store.commit("map/extent", {
         lat: center[1],
@@ -154,7 +158,7 @@
         zoom: event.map.getView().getZoom()
       });
     });
-    this.$store.dispatch("map/openLayersMap", map);
+    this.$store.dispatch("map/openLayersMap", this.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