view client/src/map/Maplayer.vue @ 734:1581ba78a360

client: prepare for fairway intersection for profile * Add calculation of features which intersect the extend of the profileLine as preparation for the more expensive detailed intersect operation.
author Bernhard Reiter <bernhard@intevation.de>
date Mon, 24 Sep 2018 09:56:51 +0200
parents e57955c1996f
children d7530644dde3
line wrap: on
line source

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

<style lang="scss">
.mapsplit {
  height: 50vh;
}

.mapfull {
  height: 100vh;
}
</style>

<script>
import { HTTP } from "../application/lib/http";
import { mapGetters } from "vuex";
import "ol/ol.css";
// openlayers imports, sorted by module name
import { Map, View } from "ol";
import Feature from "ol/Feature";
// import { bbox as bboxFilter } from "ol/format/filter.js";
import { WFS, GeoJSON } from "ol/format.js";
import GeometryType from "ol/geom/GeometryType.js";
import LineString from "ol/geom/LineString.js";
import Draw from "ol/interaction/Draw.js";
import { Vector as VectorLayer } from "ol/layer.js";
import { Vector as VectorSource } from "ol/source.js";

export default {
  name: "maplayer",
  props: ["drawMode", "lat", "long", "zoom", "split"],
  data() {
    return {
      projection: "EPSG:3857",
      openLayersMap: null,
      interaction: null,
      vectorLayer: null,
      vectorSource: null
    };
  },
  computed: {
    ...mapGetters("mapstore", ["layers"]),
    mapStyle() {
      return {
        mapfull: !this.split,
        mapsplit: this.split
      };
    },
    layerData() {
      const l = this.layers.map(x => {
        return x.data;
      });
      return [...l, this.vectorLayer];
    }
  },
  methods: {
    createVectorSource() {
      this.vectorSource = new VectorSource({ wrapX: false });
    },
    createVectorLayer() {
      this.vectorLayer = new VectorLayer({
        source: this.vectorSource
      });
    },
    removeCurrentInteraction() {
      this.openLayersMap.removeInteraction(this.interaction);
      this.interaction = null;
    },
    createInteraction() {
      var that = this;
      this.vectorSource.clear(); // start empty
      var draw = new Draw({
        source: this.vectorSource,
        type: this.drawMode
      });
      draw.on("drawstart", function(event) {
        console.log(event);
        that.vectorSource.clear(); // remove old features when draw starts
      });
      draw.on("drawend", this.drawEnd);
      return draw;
    },
    drawEnd(event) {
      console.log(event);
      var inputLineString = event.feature.getGeometry().clone();
      if (inputLineString.getType() == GeometryType.LINE_STRING) {
        // prepare to send the first line seqment to the server as GeoJSON
        inputLineString.transform("EPSG:3857", "EPSG:4326");
        var coords = inputLineString.getCoordinates();
        if (coords.length >= 2) {
          var profileLine = new LineString([coords[0], coords[1]]);
          var feature = new Feature({
            geometry: profileLine,
            // FIXME: hardcoded bottleneck and survey date
            bottleneck: "AT_Bottleneck_44",
            date: "2017-11-20"
          });
          var gStr = new GeoJSON({ geometryName: "geometry" }).writeFeature(
            feature
          );
          console.log("Ready to start profile view with: ", feature, gStr);

          // FIXME: assuming that we have the fairway dimensions loaded
          var vectorSource = this.getLayerByName(
            "Fairway Dimensions"
          ).data.getSource();
          console.log(vectorSource);

          var diagStack = [];
          vectorSource.forEachFeatureIntersectingExtent(
            // need to use EPSG:3857 which is the proj of vectorSource
            profileLine
              .clone()
              .transform("EPSG:4326", "EPSG:3857")
              .getExtent(),
            feature => {
              // transform back to prepare for usage
              var g = feature
                .getGeometry()
                .clone()
                .transform("EPSG:3857", "EPSG:4326");
              // console.log("intersecting:", g);
              this.addToFairwayRectangle(profileLine, g, diagStack);
            }
          );
        }
      }
    },
    addToFairwayRectangle(profileLine, fairwayGeometry, diagStack) {
      // both geometries have to be in EPSG:4326
      console.log(
        "addToFairwayRectangle(",
        profileLine,
        fairwayGeometry,
        diagStack,
        ")"
      );
    },
    activateInteraction() {
      const interaction = this.createInteraction(this.drawMode);
      this.interaction = interaction;
      this.openLayersMap.addInteraction(interaction);
    },
    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;
    },
    getLayerByName(name) {
      for (let layer of this.layers) {
        if (layer.name === name) {
          return layer;
        }
      }
    }
  },
  watch: {
    drawMode() {
      if (this.interaction) {
        this.removeCurrentInteraction();
      } else {
        this.activateInteraction();
      }
    },
    split() {
      const map = this.openLayersMap;
      this.$nextTick(() => {
        map.updateSize();
      });
    }
  },
  mounted() {
    this.createVectorSource();
    this.createVectorLayer();
    this.openLayersMap = new Map({
      layers: this.layerData,
      target: "map",
      controls: [],
      view: new View({
        center: [this.long, this.lat],
        zoom: this.zoom,
        projection: this.projection
      })
    });

    // 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 featureRequest2 = 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(featureRequest2),
      {
        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()
      )
    );
  }
};
</script>