view client/src/components/Maplayer.vue @ 2966:4bc2cc6364bc

client: inlined component property
author Markus Kottlaender <markus@intevation.de>
date Mon, 08 Apr 2019 17:44:49 +0200
parents 8acd0a235a94
children 61f69e8919d3
line wrap: on
line source

<template>
  <div
    id="map"
    :class="{
      splitscreen: this.splitscreen,
      nocursor: this.hasActiveInteractions
    }"
  ></div>
</template>

<style lang="sass" scoped>
#map
  height: 100vh

  &.splitscreen
    height: 50vh

  &.nocursor
    cursor: none
</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, 2019 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 { mapState } from "vuex";
import "ol/ol.css";
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";

/* for the sake of debugging */
/* eslint-disable no-console */
export default {
  name: "maplayer",
  data() {
    return {
      splitscreen: false
    };
  },
  computed: {
    ...mapState("map", [
      "initialLoad",
      "extent",
      "layers",
      "openLayersMap",
      "lineTool",
      "polygonTool",
      "cutTool"
    ]),
    ...mapState("bottlenecks", ["selectedSurvey"]),
    ...mapState("application", ["showSplitscreen"]),
    ...mapState("imports", ["selectedStretchId"]),
    hasActiveInteractions() {
      return (
        (this.lineTool && this.lineTool.getActive()) ||
        (this.polygonTool && this.polygonTool.getActive()) ||
        (this.cutTool && this.cutTool.getActive())
      );
    }
  },
  methods: {
    buildVectorLoader(
      featureRequestOptions,
      vectorSource,
      bboxStrategyDisabled,
      featurePostProcessor
    ) {
      // 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: the geometryName has to be given in featureRequestOptions if
      // bboxStrategy (default) is used
      featureRequestOptions.featureNS = "gemma";
      featureRequestOptions.featurePrefix = "gemma";
      featureRequestOptions.outputFormat = "application/json";
      return (extent, resolution, projection) => {
        if (!bboxStrategyDisabled) {
          featureRequestOptions.bbox = extent;
        }
        featureRequestOptions.srsName = projection.getCode();
        HTTP.post(
          "/internal/wfs",
          new XMLSerializer().serializeToString(
            new WFS().writeGetFeature(featureRequestOptions)
          ),
          {
            headers: {
              "X-Gemma-Auth": localStorage.getItem("token"),
              "Content-type": "text/xml; charset=UTF-8"
            }
          }
        )
          .then(response => {
            const features = new GeoJSON().readFeatures(
              JSON.stringify(response.data)
            );
            if (featurePostProcessor) {
              features.map(f => featurePostProcessor(f));
            }
            vectorSource.addFeatures(features);
          })
          .catch(() => {
            vectorSource.removeLoadedExtent(extent);
          });
      };
    },
    updateBottleneckFilter(bottleneck_id, datestr) {
      const exists = bottleneck_id != "does_not_exist";

      if (exists) {
        this.layers.BOTTLENECKISOLINE.getSource().updateParams({
          cql_filter: `date_info='${datestr}' AND bottleneck_id='${bottleneck_id}'`
        });
      }
      this.layers.BOTTLENECKISOLINE.setVisible(exists);
    }
  },
  watch: {
    showSplitscreen(show) {
      if (show) {
        setTimeout(() => {
          this.splitscreen = true;
        }, 350);
      } else {
        this.splitscreen = false;
      }
    },
    splitscreen() {
      const map = this.openLayersMap;
      this.$nextTick(() => {
        map && map.updateSize();
      });
    },
    selectedSurvey(newSelectedSurvey) {
      if (newSelectedSurvey) {
        this.updateBottleneckFilter(
          newSelectedSurvey.bottleneck_id,
          newSelectedSurvey.date_info
        );
      } else {
        this.updateBottleneckFilter("does_not_exist", "1999-10-01");
      }
    },
    selectedStretchId(id) {
      this.layers.STRETCHES.getSource()
        .getFeatures()
        .forEach(f => {
          f.set("highlighted", false);
          if (id === f.getId()) {
            f.set("highlighted", true);
          }
        });
    }
  },
  mounted() {
    let map = new Map({
      layers: [...Object.values(this.layers)],
      target: "map",
      controls: [],
      view: new View({
        center: [this.extent.lon, this.extent.lat],
        minZoom: 5, // restrict zooming out to ~size of Europe for width 1000px
        zoom: this.extent.zoom,
        projection: "EPSG:3857"
      })
    });
    map.on("moveend", event => {
      const center = event.map.getView().getCenter();
      this.$store.commit("map/extent", {
        lat: center[1],
        lon: center[0],
        zoom: event.map.getView().getZoom()
      });
    });
    this.$store.dispatch("map/openLayersMap", map);

    if (this.initialLoad) {
      this.$store.commit("map/initialLoad", false);
      var currentUser = this.$store.state.user.user;
      HTTP.get("/users/" + currentUser, {
        headers: {
          "X-Gemma-Auth": localStorage.getItem("token"),
          "Content-type": "text/xml; charset=UTF-8"
        }
      })
        .then(response => {
          this.$store.commit("map/moveToBoundingBox", {
            boundingBox: [
              response.data.extent.x1,
              response.data.extent.y1,
              response.data.extent.x2,
              response.data.extent.y2
            ],
            zoom: 17,
            preventZoomOut: true
          });
        })
        .catch(error => {
          const { status, data } = error.response;
          displayError({
            title: this.$gettext("Backend Error"),
            message: `${status}: ${data.message || data}`
          });
        });
    }

    // TODO make display of layers more dynamic, e.g. from a list

    this.layers.FAIRWAYDIMENSIONSLOS1.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["fairway_dimensions"],
          filter: equalTo("level_of_service", 1)
        },
        this.layers.FAIRWAYDIMENSIONSLOS1.getSource(),
        true
      )
    );

    this.layers.FAIRWAYDIMENSIONSLOS2.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["fairway_dimensions"],
          filter: equalTo("level_of_service", 2)
        },
        this.layers.FAIRWAYDIMENSIONSLOS2.getSource(),
        true
      )
    );

    this.layers.FAIRWAYDIMENSIONSLOS3.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["fairway_dimensions"],
          filter: equalTo("level_of_service", 3)
        },
        this.layers.FAIRWAYDIMENSIONSLOS3.getSource(),
        true
      )
    );

    // load following layers with bboxStrategy (using our request builder)
    this.layers.WATERWAYAREA.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["waterway_area"],
          geometryName: "area"
        },
        this.layers.WATERWAYAREA.getSource()
      )
    );

    this.layers.WATERWAYAXIS.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["waterway_axis"],
          geometryName: "wtwaxs"
        },
        this.layers.WATERWAYAXIS.getSource()
      )
    );

    this.layers.WATERWAYPROFILES.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["waterway_profiles"],
          geometryName: "geom"
        },
        this.layers.WATERWAYPROFILES.getSource()
      )
    );

    this.layers.DISTANCEMARKS.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["distance_marks_ashore_geoserver"],
          geometryName: "geom"
        },
        this.layers.DISTANCEMARKS.getSource()
      )
    );

    this.layers.DISTANCEMARKSAXIS.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["distance_marks_geoserver"],
          geometryName: "geom"
        },
        this.layers.DISTANCEMARKSAXIS.getSource()
      )
    );

    this.layers.GAUGES.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["gauges_geoserver"],
          geometryName: "geom"
        },
        this.layers.GAUGES.getSource()
      )
    );

    this.layers.STRETCHES.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["stretches_geoserver"],
          geometryName: "area"
        },
        this.layers.STRETCHES.getSource(),
        f => {
          if (f.getId() === this.selectedStretchId) {
            f.set("highlighted", true);
          }
          return f;
        }
      )
    );

    this.layers.BOTTLENECKSTATUS.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["bottlenecks_geoserver"],
          geometryName: "area"
        },
        this.layers.BOTTLENECKSTATUS.getSource()
      )
    );

    this.layers.BOTTLENECKS.getSource().setLoader(
      this.buildVectorLoader(
        {
          featureTypes: ["bottlenecks_geoserver"],
          geometryName: "area"
        },
        this.layers.BOTTLENECKS.getSource()
      )
    );
    HTTP.get("/system/style/Bottlenecks/stroke", {
      headers: { "X-Gemma-Auth": localStorage.getItem("token") }
    })
      .then(response => {
        let btlnStrokeC = response.data.code;
        HTTP.get("/system/style/Bottlenecks/fill", {
          headers: { "X-Gemma-Auth": localStorage.getItem("token") }
        })
          .then(response => {
            let btlnFillC = response.data.code;
            var newStyle = new Style({
              stroke: new Stroke({
                color: btlnStrokeC,
                width: 4
              }),
              fill: new Fill({
                color: btlnFillC
              })
            });
            this.layers.BOTTLENECKS.setStyle(newStyle);
          })
          .catch(error => {
            console.log(error);
          });
      })
      .catch(error => {
        console.log(error);
      });

    this.$store.dispatch("map/disableIdentifyTool");
    this.$store.dispatch("map/enableIdentifyTool");
  }
};
</script>