view client/src/map/Maplayer.vue @ 1143:846e336d8ee5

merge
author Thomas Junk <thomas.junk@intevation.de>
date Mon, 12 Nov 2018 15:00:45 +0100
parents dc3f0277628a 2e06bc53b002
children 5f98d0c9d738
line wrap: on
line source

<template>
    <div id="map" :class="mapStyle"></div>
</template>

<style lang="scss" scoped>
.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 "../application/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";

/* 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", "drawMode"]),
    ...mapState("bottlenecks", ["selectedSurvey"]),
    mapStyle() {
      return {
        mapfull: !this.split,
        mapsplit: this.split
      };
    }
  },
  methods: {
    identify(coordinate, pixel) {
      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"));
          }
        }
      }

      // 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>