diff client/src/components/map/Maplayer.vue @ 1272:bc55ffaeb639

cleaned up client/src directory better organization of files and directories, better naming, separation of admin and map context
author Markus Kottlaender <markus@intevation.de>
date Thu, 22 Nov 2018 07:07:12 +0100
parents
children 99c039e86624
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/map/Maplayer.vue	Thu Nov 22 07:07:12 2018 +0100
@@ -0,0 +1,430 @@
+<template>
+    <div id="map" :class="mapStyle"></div>
+</template>
+
+<style lang="sass" scoped>
+.nocursor
+  cursor: none
+
+.mapsplit
+  height: 50vh
+
+.mapfull
+  height: 100vh
+
+@media print
+  .mapfull
+    width: 2000px
+    height: 2828px
+    
+  .mapsplit
+    width: 2000px
+    height: 2828px
+</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>
+ * * Bernhard E. Reiter <bernhard.reiter@intevation.de>
+ */
+import { HTTP } from "../../lib/http";
+import { mapGetters, mapState } from "vuex";
+import "ol/ol.css";
+import { Map, View } from "ol";
+import { WFS, GeoJSON } from "ol/format.js";
+import { Stroke, Style, Fill } from "ol/style.js";
+import { getCenter } from "ol/extent";
+
+/* for the sake of debugging */
+/* eslint-disable no-console */
+export default {
+  name: "maplayer",
+  props: ["lat", "long", "zoom", "split"],
+  data() {
+    return {
+      projection: "EPSG:3857"
+    };
+  },
+  computed: {
+    ...mapGetters("map", ["getLayerByName"]),
+    ...mapState("map", [
+      "layers",
+      "openLayersMap",
+      "lineTool",
+      "polygonTool",
+      "cutTool"
+    ]),
+    ...mapState("bottlenecks", ["selectedSurvey"]),
+    mapStyle() {
+      return {
+        mapfull: !this.split,
+        mapsplit: this.split,
+        nocursor: this.hasActiveInteractions
+      };
+    },
+    hasActiveInteractions() {
+      return (
+        (this.lineTool && this.lineTool.getActive()) ||
+        (this.polygonTool && this.polygonTool.getActive()) ||
+        (this.cutTool && this.cutTool.getActive())
+      );
+    }
+  },
+  methods: {
+    identify(coordinate, pixel) {
+      if (!this.hasActiveInteractions) {
+        this.$store.commit("map/setIdentifiedFeatures", []);
+        // checking our WFS layers
+        var features = this.openLayersMap.getFeaturesAtPixel(pixel);
+        if (features) {
+          this.$store.commit("map/setIdentifiedFeatures", features);
+
+          // get selected bottleneck from identified features
+          for (let feature of features) {
+            let id = feature.getId();
+            // RegExp.prototype.test() works with number, str and undefined
+            if (/^bottlenecks\./.test(id)) {
+              this.$store.dispatch(
+                "bottlenecks/setSelectedBottleneck",
+                feature.get("objnam")
+              );
+              this.$store.commit("map/moveMap", {
+                coordinates: getCenter(
+                  feature
+                    .getGeometry()
+                    .clone()
+                    .transform("EPSG:3857", "EPSG:4326")
+                    .getExtent()
+                ),
+                zoom: 17,
+                preventZoomOut: true
+              });
+            }
+          }
+        }
+
+        // DEBUG output and example how to remove the GeometryName
+        /*
+        for (let feature of features) {
+          console.log("Identified:", feature.getId());
+          for (let key of feature.getKeys()) {
+            if (key != feature.getGeometryName()) {
+              console.log(key, feature.get(key));
+            }
+          }
+        }
+        */
+
+        // trying the GetFeatureInfo way for WMS
+        var wmsSource = this.getLayerByName(
+          "Inland ECDIS chart Danube"
+        ).data.getSource();
+        var url = wmsSource.getGetFeatureInfoUrl(
+          coordinate,
+          100 /* resolution */,
+          "EPSG:3857",
+          // { INFO_FORMAT: "application/vnd.ogc.gml" } // not allowed by d4d
+          { INFO_FORMAT: "text/plain" }
+        );
+
+        if (url) {
+          // cannot directly query here because of SOP
+          console.log("GetFeatureInfo url:", url);
+        }
+      }
+    },
+    buildVectorLoader(featureRequestOptions, endpoint, vectorSource) {
+      // 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: a) the geometryName has to be given in featureRequestOptions,
+      //          because we want to load depending on the bbox
+      //  b) the VectorSource has to have the option strategy: bbox
+      featureRequestOptions["outputFormat"] = "application/json";
+      var loader = function(extent, resolution, projection) {
+        featureRequestOptions["bbox"] = extent;
+        featureRequestOptions["srsName"] = projection.getCode();
+        var featureRequest = new WFS().writeGetFeature(featureRequestOptions);
+        // DEBUG console.log(featureRequest);
+        HTTP.post(
+          endpoint,
+          new XMLSerializer().serializeToString(featureRequest),
+          {
+            headers: {
+              "X-Gemma-Auth": localStorage.getItem("token"),
+              "Content-type": "text/xml; charset=UTF-8"
+            }
+          }
+        )
+          .then(response => {
+            var features = new GeoJSON().readFeatures(
+              JSON.stringify(response.data)
+            );
+            vectorSource.addFeatures(features);
+            // console.log(
+            //   "loaded",
+            //   features.length,
+            //   featureRequestOptions.featureTypes,
+            //   "features"
+            // );
+            // DEBUG console.log("loaded ", features, "for", vectorSource);
+            // eslint-disable-next-line
+          })
+          .catch(() => {
+            vectorSource.removeLoadedExtent(extent);
+          });
+      };
+      return loader;
+    },
+    updateBottleneckFilter(bottleneck_id, datestr) {
+      console.log("updating filter with", bottleneck_id, datestr);
+      var layer = this.getLayerByName("Bottleneck isolines");
+      var wmsSrc = layer.data.getSource();
+
+      if (bottleneck_id != "does_not_exist") {
+        wmsSrc.updateParams({
+          cql_filter:
+            "date_info='" +
+            datestr +
+            "' AND bottleneck_id='" +
+            bottleneck_id +
+            "'"
+        });
+        layer.isVisible = true;
+        layer.data.setVisible(true);
+      } else {
+        layer.isVisible = false;
+        layer.data.setVisible(false);
+      }
+    },
+    onBeforePrint(/* evt */) {
+      // console.log("onBeforePrint(", evt ,")");
+      //
+      // the following code shows how to get the current map canvas
+      // and change it, however this does not work well enough, as
+      // another mechanism seems to update the size again before the rendering
+      // for printing is done:
+      // console.log(this.openLayersMap.getViewport());
+      // var canvas = this.openLayersMap.getViewport().getElementsByTagName("canvas")[0];
+      // console.log(canvas);
+      // canvas.width=1000;
+      // canvas.height=1414;
+      //
+      // An experiment which also did not work:
+      // this.openLayersMap.setSize([1000, 1414]); // estimate portait DIN A4
+      //
+      // according to documentation
+      // http://openlayers.org/en/latest/apidoc/module-ol_PluggableMap-PluggableMap.html#updateSize
+      // "Force a recalculation of the map viewport size. This should be called when third-party code changes the size of the map viewport."
+      // but did not help
+      // this.openLayersMap.updateSize();
+    },
+    onAfterPrint(/* evt */) {
+      // could be used to undo changes that have been done for printing
+      // though https://www.tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/
+      // reported that this was not feasable (back then).
+      // console.log("onAfterPrint(", evt, ")");
+    }
+  },
+  watch: {
+    split() {
+      const map = this.openLayersMap;
+      this.$nextTick(() => {
+        map.updateSize();
+      });
+    },
+    selectedSurvey(newSelectedSurvey) {
+      if (newSelectedSurvey) {
+        this.updateBottleneckFilter(
+          newSelectedSurvey.bottleneck_id,
+          newSelectedSurvey.date_info
+        );
+      } else {
+        this.updateBottleneckFilter("does_not_exist", "1999-10-01");
+      }
+    }
+  },
+  mounted() {
+    let map = new Map({
+      layers: [...this.layers.map(x => x.data)],
+      target: "map",
+      controls: [],
+      view: new View({
+        center: [this.long, this.lat],
+        zoom: this.zoom,
+        projection: this.projection
+      })
+    });
+    this.$store.commit("map/setOpenLayersMap", map);
+
+    // TODO make display of layers more dynamic, e.g. from a list
+
+    // loading the full WFS layer, by not setting the loader function
+    // and without bboxStrategy
+    var featureRequest = new WFS().writeGetFeature({
+      srsName: "EPSG:3857",
+      featureNS: "gemma",
+      featurePrefix: "gemma",
+      featureTypes: ["fairway_dimensions"],
+      outputFormat: "application/json"
+    });
+
+    // NOTE: loading the full fairway_dimensions makes sure
+    //       that all are available for the intersection with the profile
+    HTTP.post(
+      "/internal/wfs",
+      new XMLSerializer().serializeToString(featureRequest),
+      {
+        headers: {
+          "X-Gemma-Auth": localStorage.getItem("token"),
+          "Content-type": "text/xml; charset=UTF-8"
+        }
+      }
+    ).then(response => {
+      var features = new GeoJSON().readFeatures(JSON.stringify(response.data));
+      var vectorSrc = this.getLayerByName(
+        "Fairway Dimensions"
+      ).data.getSource();
+      vectorSrc.addFeatures(features);
+      // would scale to the extend of all resulting features
+      // this.openLayersMap.getView().fit(vectorSrc.getExtent());
+    });
+
+    // load following layers with bboxStrategy (using our request builder)
+    var layer = null;
+
+    layer = this.getLayerByName("Waterway Area");
+    layer.data.getSource().setLoader(
+      this.buildVectorLoader(
+        {
+          featurePrefix: "ws-wamos",
+          featureTypes: ["ienc_wtware"],
+          geometryName: "geom"
+        },
+        "/external/d4d",
+        layer.data.getSource()
+      )
+    );
+
+    layer = this.getLayerByName("Waterway Axis");
+    layer.data.getSource().setLoader(
+      this.buildVectorLoader(
+        {
+          featurePrefix: "ws-wamos",
+          featureTypes: ["ienc_wtwaxs"],
+          geometryName: "geom"
+        },
+        "/external/d4d",
+        layer.data.getSource()
+      )
+    );
+
+    layer = this.getLayerByName("Distance marks");
+    layer.data.getSource().setLoader(
+      this.buildVectorLoader(
+        {
+          featurePrefix: "ws-wamos",
+          featureTypes: ["ienc_dismar"],
+          geometryName: "geom" //,
+          /* restrict loading approximately to extend of danube in Austria */
+          // filter: bboxFilter("geom", [13.3, 48.0, 17.1, 48.6], "EPSG:4326")
+        },
+        "/external/d4d",
+        layer.data.getSource()
+      )
+    );
+    layer.data.setVisible(layer.isVisible);
+
+    layer = this.getLayerByName("Distance marks, Axis");
+    layer.data.getSource().setLoader(
+      this.buildVectorLoader(
+        {
+          featureNS: "gemma",
+          featurePrefix: "gemma",
+          featureTypes: ["distance_marks_geoserver"],
+          geometryName: "geom"
+        },
+        "/internal/wfs",
+        layer.data.getSource()
+      )
+    );
+
+    layer = this.getLayerByName("Waterway Area, named");
+    layer.data.getSource().setLoader(
+      this.buildVectorLoader(
+        {
+          featureNS: "gemma",
+          featurePrefix: "gemma",
+          featureTypes: ["hydro_seaare"],
+          geometryName: "geom"
+        },
+        "/external/d4d",
+        layer.data.getSource()
+      )
+    );
+    layer.data.setVisible(layer.isVisible);
+
+    layer = this.getLayerByName("Bottlenecks");
+    layer.data.getSource().setLoader(
+      this.buildVectorLoader(
+        {
+          featureNS: "gemma",
+          featurePrefix: "gemma",
+          featureTypes: ["bottlenecks"],
+          geometryName: "area"
+        },
+        "/internal/wfs",
+        layer.data.getSource()
+      )
+    );
+    HTTP.get("/system/style/Bottlenecks/stroke", {
+      headers: { "X-Gemma-Auth": localStorage.getItem("token") }
+    })
+      .then(response => {
+        this.btlnStrokeC = response.data.code;
+        HTTP.get("/system/style/Bottlenecks/fill", {
+          headers: { "X-Gemma-Auth": localStorage.getItem("token") }
+        })
+          .then(response => {
+            this.btlnFillC = response.data.code;
+            var newstyle = new Style({
+              stroke: new Stroke({
+                color: this.btlnStrokeC,
+                width: 4
+              }),
+              fill: new Fill({
+                color: this.btlnFillC
+              })
+            });
+            layer.data.setStyle(newstyle);
+          })
+          .catch(error => {
+            console.log(error);
+          });
+      })
+      .catch(error => {
+        console.log(error);
+      });
+
+    window.addEventListener("beforeprint", this.onBeforePrint);
+    window.addEventListener("afterprint", this.onAfterPrint);
+
+    // so none is shown
+    this.updateBottleneckFilter("does_not_exist", "1999-10-01");
+    this.openLayersMap.on(["singleclick", "dblclick"], event => {
+      this.identify(event.coordinate, event.pixel);
+    });
+  }
+};
+</script>