changeset 2984:61f69e8919d3

client: prepared splitview Up to four panes can be used to display different components. Currently hardcoded to one pane with the map component. Two panes can be oriented vertically or horizontally and three panes can be set to left, right, top and bottom, which is the position of the one full-width or -height pane.
author Markus Kottlaender <markus@intevation.de>
date Tue, 09 Apr 2019 18:23:07 +0200
parents 2e7c0f9cff24
children 1b8bb4f89227
files client/src/assets/application.scss client/src/components/Main.vue client/src/components/Maplayer.vue client/src/router.js client/src/store/application.js
diffstat 5 files changed, 167 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/assets/application.scss	Tue Apr 09 16:42:58 2019 +0200
+++ b/client/src/assets/application.scss	Tue Apr 09 18:23:07 2019 +0200
@@ -209,3 +209,8 @@
   overflow: hidden;
   text-overflow: ellipsis;
 }
+
+.wh-100 {
+  width: 100% !important;
+  height: 100% !important;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/Main.vue	Tue Apr 09 18:23:07 2019 +0200
@@ -0,0 +1,130 @@
+<template>
+  <div
+    id="panes"
+    :class="[
+      'd-flex flex-wrap position-absolute',
+      { 'flex-column': ['left', 'right'].includes(paneMode) }
+    ]"
+  >
+    <template v-if="panes.length === 1">
+      <div id="pane1" class="pane wh-100"><component :is="panes[0]" /></div>
+    </template>
+
+    <template v-if="panes.length === 2">
+      <template v-if="paneMode === 'horizontal'">
+        <div id="pane1" class="pane w-100 h-50">
+          <component :is="panes[0]" />
+        </div>
+        <div id="pane2" class="pane w-100 h-50">
+          <component :is="panes[1]" />
+        </div>
+      </template>
+      <template v-if="paneMode === 'vertical'">
+        <div id="pane1" class="pane w-50 h-100">
+          <component :is="panes[0]" />
+        </div>
+        <div id="pane2" class="pane w-50 h-100">
+          <component :is="panes[1]" />
+        </div>
+      </template>
+    </template>
+
+    <template v-if="panes.length === 3">
+      <template v-if="paneMode === 'top'">
+        <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-50">
+          <component :is="panes[2]" />
+        </div>
+      </template>
+      <template v-if="paneMode === 'right'">
+        <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-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">
+          <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-50">
+          <component :is="panes[2]" />
+        </div>
+      </template>
+    </template>
+
+    <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="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>
+
+<style lang="sass" scoped>
+#panes
+  top: -1.5px
+  right: -1.5px
+  bottom: -1.5px
+  left: -1.5px
+  z-index: 1
+  .pane
+    border: solid 1.5px #fff
+    background-color: #eee
+    background-image: linear-gradient(45deg, #e8e8e8 25%, transparent 25%, transparent 75%, #e8e8e8 75%, #e8e8e8), linear-gradient(45deg, #e8e8e8 25%, transparent 25%, transparent 75%, #e8e8e8 75%, #e8e8e8)
+    background-size: 20px 20px
+    background-position: 0 0, 10px 10px
+</style>
+
+<script>
+/* This is Free Software under GNU Affero General Public License v >= 3.0
+ * without warranty, see README.md and license for details.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ * License-Filename: LICENSES/AGPL-3.0.txt
+ *
+ * Copyright (C) 2018 by via donau
+ *   – Österreichische Wasserstraßen-Gesellschaft mbH
+ * Software engineering by Intevation GmbH
+ *
+ * Author(s):
+ * Thomas Junk <thomas.junk@intevation.de>
+ * Markus Kottländer <markus.kottlaender@intevation.de>
+ */
+
+import { mapState } from "vuex";
+
+export default {
+  components: {
+    // all components that are supposed to be displayed in a pane must be registered here
+    Maplayer: () => import("./Maplayer")
+  },
+  computed: {
+    ...mapState("application", ["panes", "paneMode"])
+  }
+};
+</script>
--- a/client/src/components/Maplayer.vue	Tue Apr 09 16:42:58 2019 +0200
+++ b/client/src/components/Maplayer.vue	Tue Apr 09 18:23:07 2019 +0200
@@ -1,19 +1,23 @@
 <template>
   <div
-    id="map"
-    :class="{
-      splitscreen: this.splitscreen,
-      nocursor: this.hasActiveInteractions
-    }"
+    :id="'map-' + uuid"
+    :class="[
+      'map',
+      {
+        splitscreen: this.splitscreen,
+        nocursor: this.hasActiveInteractions
+      }
+    ]"
   ></div>
 </template>
 
 <style lang="sass" scoped>
-#map
-  height: 100vh
+.map
+  width: 100%
+  height: 100%
 
   &.splitscreen
-    height: 50vh
+    height: 50%
 
   &.nocursor
     cursor: none
@@ -36,17 +40,17 @@
  */
 import { HTTP } from "@/lib/http";
 import { mapState } from "vuex";
-import "ol/ol.css";
+import uuid from "uuid";
 import { Map, View } from "ol";
 import { WFS, GeoJSON } from "ol/format.js";
 import { equalTo } from "ol/format/filter.js";
 import { Stroke, Style, Fill } from "ol/style.js";
 import { displayError } from "@/lib/errors.js";
+import "ol/ol.css";
 
 /* for the sake of debugging */
 /* eslint-disable no-console */
 export default {
-  name: "maplayer",
   data() {
     return {
       splitscreen: false
@@ -65,6 +69,9 @@
     ...mapState("bottlenecks", ["selectedSurvey"]),
     ...mapState("application", ["showSplitscreen"]),
     ...mapState("imports", ["selectedStretchId"]),
+    uuid() {
+      return uuid.v4();
+    },
     hasActiveInteractions() {
       return (
         (this.lineTool && this.lineTool.getActive()) ||
@@ -170,7 +177,7 @@
   mounted() {
     let map = new Map({
       layers: [...Object.values(this.layers)],
-      target: "map",
+      target: "map-" + this.uuid,
       controls: [],
       view: new View({
         center: [this.extent.lon, this.extent.lat],
--- a/client/src/router.js	Tue Apr 09 16:42:58 2019 +0200
+++ b/client/src/router.js	Tue Apr 09 18:23:07 2019 +0200
@@ -20,7 +20,7 @@
 
 /*  facilitate codesplitting */
 const Login = () => import("./components/Login.vue");
-const Maplayer = () => import("./components/Maplayer.vue");
+const Main = () => import("./components/Main.vue");
 
 Vue.use(Router);
 
@@ -83,7 +83,7 @@
     {
       path: "/",
       name: "mainview",
-      component: Maplayer,
+      component: Main,
       meta: {
         requiresAuth: true
       },
@@ -98,7 +98,7 @@
     {
       path: "/bottlenecks",
       name: "bottlenecks",
-      component: Maplayer,
+      component: Main,
       meta: {
         requiresAuth: true
       },
@@ -113,7 +113,7 @@
     {
       path: "/imports/configuration",
       name: "importconfiguration",
-      component: Maplayer,
+      component: Main,
       meta: {
         requiresAuth: true
       },
@@ -133,7 +133,7 @@
     {
       path: "/imports/overview/:id?",
       name: "importoverview",
-      component: Maplayer,
+      component: Main,
       meta: {
         requiresAuth: true
       },
@@ -152,7 +152,7 @@
     {
       path: "/stretches",
       name: "stretches",
-      component: Maplayer,
+      component: Main,
       meta: {
         requiresAuth: true
       },
--- a/client/src/store/application.js	Tue Apr 09 16:42:58 2019 +0200
+++ b/client/src/store/application.js	Tue Apr 09 18:23:07 2019 +0200
@@ -24,6 +24,8 @@
     secondaryLogo: process.env.VUE_APP_SECONDARY_LOGO_URL,
     logoForPDF: process.env.VUE_APP_LOGO_FOR_PDF_URL,
     popup: null,
+    panes: ["Maplayer"],
+    paneMode: null,
     splitscreens: [],
     splitscreenLoading: false,
     activeSplitscreenId: null,
@@ -81,6 +83,12 @@
     popup: (state, popup) => {
       state.popup = popup;
     },
+    panes: (state, panes) => {
+      state.panes = panes;
+    },
+    paneMode: (state, mode) => {
+      state.paneMode = mode;
+    },
     showSidebar: (state, show) => {
       state.showSidebar = show;
     },