view client/src/store/map.js @ 3047:e0b77d7463e7

Changed Waterway axis and area layer to WMS.
author Raimund Renkert <raimund.renkert@intevation.de>
date Mon, 15 Apr 2019 15:15:16 +0200
parents c71373594719
children 051a3f446ac2
line wrap: on
line source

/* 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):
 * * Bernhard Reiter <bernhard.reiter@intevation.de>
 * * Markus Kottländer <markus@intevation.de>
 * * Thomas Junk <thomas.junk@intevation.de>
 */

import Draw from "ol/interaction/Draw";
import { Stroke, Style, Fill, Circle } from "ol/style";
import { fromLonLat } from "ol/proj";
import { getLength, getArea } from "ol/sphere";
import { unByKey } from "ol/Observable";
import { getCenter } from "ol/extent";
import { transformExtent } from "ol/proj";
import bbox from "@turf/bbox";
import app from "@/main";
import { HTTP } from "@/lib/http";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";

const moveMap = ({ view, extent, zoom, preventZoomOut }) => {
  const currentZoom = view.getZoom();
  zoom = zoom || currentZoom;
  view.fit(extent, {
    maxZoom: preventZoomOut ? Math.max(zoom, currentZoom) : zoom,
    duration: 700
  });
};

// initial state
const init = () => {
  return {
    openLayersMaps: [],
    initialLoad: true,
    extent: {
      lat: 6155376,
      lon: 1819178,
      zoom: 11
    },
    identifyTool: null, // event binding (singleclick, dblclick)
    identifiedFeatures: [], // map features identified by clicking on the map
    currentMeasurement: null, // distance or area from line-/polygon-/cutTool
    lineTool: null, // open layers interaction object (Draw)
    polygonTool: null, // open layers interaction object (Draw)
    cutTool: null, // open layers interaction object (Draw)
    isolinesLegendImgDataURL: "",
    differencesLegendImgDataURL: ""
  };
};

export default {
  init,
  namespaced: true,
  state: init(),
  getters: {
    openLayersMap: state => {
      return state.openLayersMaps.length ? state.openLayersMaps[0] : null;
    },
    filteredIdentifiedFeatures: state => {
      return state.identifiedFeatures.filter(f => f.getId());
    }
  },
  mutations: {
    initialLoad: (state, initialLoad) => {
      state.initialLoad = initialLoad;
    },
    extent: (state, extent) => {
      state.extent = extent;
    },
    addOpenLayersMap: (state, map) => {
      state.openLayersMaps.push(map);
    },
    identifyTool: (state, events) => {
      state.identifyTool = events;
    },
    setIdentifiedFeatures: (state, identifiedFeatures) => {
      state.identifiedFeatures = identifiedFeatures;
    },
    addIdentifiedFeatures: (state, identifiedFeatures) => {
      state.identifiedFeatures = state.identifiedFeatures.concat(
        identifiedFeatures
      );
    },
    setCurrentMeasurement: (state, measurement) => {
      state.currentMeasurement = measurement;
    },
    lineTool: (state, lineTool) => {
      state.lineTool = lineTool;
    },
    polygonTool: (state, polygonTool) => {
      state.polygonTool = polygonTool;
    },
    cutTool: (state, cutTool) => {
      state.cutTool = cutTool;
    },
    isolinesLegendImgDataURL: (state, isolinesLegendImgDataURL) => {
      state.isolinesLegendImgDataURL = isolinesLegendImgDataURL;
    },
    differencesLegendImgDataURL: (state, differencesLegendImgDataURL) => {
      state.differencesLegendImgDataURL = differencesLegendImgDataURL;
    }
  },
  actions: {
    openLayersMap({ commit, dispatch }, map) {
      const drawVectorSrc = map.getLayer("DRAWTOOL").getSource();
      const cutVectorSrc = map.getLayer("CUTTOOL").getSource();

      // init line tool
      const lineTool = new Draw({
        source: drawVectorSrc,
        type: "LineString",
        maxPoints: 2
      });
      lineTool.setActive(false);
      lineTool.on("drawstart", () => {
        drawVectorSrc.clear();
        commit("setCurrentMeasurement", null);
      });
      lineTool.on("drawend", event => {
        commit("setCurrentMeasurement", {
          quantity: app.$gettext("Length"),
          unitSymbol: "m",
          value: Math.round(getLength(event.feature.getGeometry()) * 10) / 10
        });
        commit("application/showIdentify", true, { root: true });
      });

      // init polygon tool
      const polygonTool = new Draw({
        source: drawVectorSrc,
        type: "Polygon",
        maxPoints: 50
      });
      polygonTool.setActive(false);
      polygonTool.on("drawstart", () => {
        drawVectorSrc.clear();
        commit("setCurrentMeasurement", null);
      });
      polygonTool.on("drawend", event => {
        const areaSize = getArea(event.feature.getGeometry());
        commit("setCurrentMeasurement", {
          quantity: app.$gettext("Area"),
          unitSymbol: areaSize > 100000 ? "km²" : "m²",
          value:
            areaSize > 100000
              ? Math.round(areaSize / 1000) / 1000 // convert into 1 km² == 1000*1000 m² and round to 1000 m²
              : Math.round(areaSize)
        });
        commit("application/showIdentify", true, { root: true });
      });

      // init cut tool
      const cutTool = new Draw({
        source: cutVectorSrc,
        type: "LineString",
        maxPoints: 2,
        style: new Style({
          stroke: new Stroke({
            color: "#444",
            width: 2,
            lineDash: [7, 7]
          }),
          image: new Circle({
            fill: new Fill({ color: "#333" }),
            stroke: new Stroke({ color: "#fff", width: 1.5 }),
            radius: 6
          })
        })
      });
      cutTool.setActive(false);
      cutTool.on("drawstart", () => {
        dispatch("disableIdentifyTool");
        cutVectorSrc.clear();
      });
      cutTool.on("drawend", event => {
        commit("fairwayprofile/selectedCut", null, { root: true });
        dispatch("fairwayprofile/cut", event.feature, { root: true }).then(() =>
          // This setTimeout is an ugly workaround. If we would enable the
          // identifyTool here immediately then the click event from ending the
          // cut will trigger it. We don't want that.
          setTimeout(() => dispatch("enableIdentifyTool"), 1000)
        );
      });

      map.addInteraction(lineTool);
      map.addInteraction(cutTool);
      map.addInteraction(polygonTool);

      commit("lineTool", lineTool);
      commit("polygonTool", polygonTool);
      commit("cutTool", cutTool);
      commit("addOpenLayersMap", map);
    },
    disableIdentifyTool({ state }) {
      unByKey(state.identifyTool);
      state.identifyTool = null;
    },
    enableIdentifyTool({ state, rootState, getters, commit, dispatch }) {
      if (!state.identifyTool) {
        state.identifyTool = getters.openLayersMap.on(
          ["singleclick", "dblclick"],
          event => {
            commit("setIdentifiedFeatures", []);
            // checking our WFS layers
            var features = getters.openLayersMap.getFeaturesAtPixel(
              event.pixel,
              {
                hitTolerance: 7
              }
            );
            if (features) {
              let identifiedFeatures = [];

              for (let feature of features) {
                let id = feature.getId();
                // avoid identifying the same feature twice
                if (
                  identifiedFeatures.findIndex(
                    f => f.getId() === feature.getId()
                  ) === -1
                ) {
                  identifiedFeatures.push(feature);
                }

                // get selected bottleneck
                // RegExp.prototype.test() works with number, str and undefined
                if (/^bottlenecks/.test(id)) {
                  if (
                    rootState.bottlenecks.selectedBottleneck !=
                    feature.get("objnam")
                  ) {
                    dispatch(
                      "bottlenecks/setSelectedBottleneck",
                      feature.get("objnam"),
                      { root: true }
                    ).then(() => {
                      this.commit("bottlenecks/setFirstSurveySelected");
                    });
                    dispatch("moveMap", {
                      coordinates: getCenter(
                        feature
                          .getGeometry()
                          .clone()
                          .transform("EPSG:3857", "EPSG:4326")
                          .getExtent()
                      ),
                      zoom: 17,
                      preventZoomOut: true
                    });
                  }
                }

                // get selected gauge
                if (/^gauges/.test(id)) {
                  if (
                    rootState.gauges.selectedGaugeISRS !==
                    feature.get("isrs_code")
                  ) {
                    dispatch(
                      "gauges/selectedGaugeISRS",
                      feature.get("isrs_code"),
                      {
                        root: true
                      }
                    );
                    dispatch("moveMap", {
                      coordinates: getCenter(
                        feature
                          .getGeometry()
                          .clone()
                          .transform("EPSG:3857", "EPSG:4326")
                          .getExtent()
                      ),
                      zoom: null,
                      preventZoomOut: true
                    });
                  }
                }

                // get selected stretch
                if (/^stretches/.test(id)) {
                  if (rootState.imports.selectedStretchId === feature.getId()) {
                    commit("imports/selectedStretchId", null, { root: true });
                  } else {
                    commit("imports/selectedStretchId", feature.getId(), {
                      root: true
                    });
                    dispatch("moveMap", {
                      coordinates: getCenter(
                        feature
                          .getGeometry()
                          .clone()
                          .transform("EPSG:3857", "EPSG:4326")
                          .getExtent()
                      ),
                      zoom: null,
                      preventZoomOut: true
                    });
                  }
                }
              }

              commit("setIdentifiedFeatures", identifiedFeatures);
            }

            // 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));
                }
              }
            }
            */

            var waterwayAxisSource = getters.openLayersMap
              .getLayer("WATERWAYAXIS")
              .getSource();
            var waxisUrl = waterwayAxisSource.getGetFeatureInfoUrl(
              event.coordinate,
              100 /* resolution */,
              "EPSG:3857",
              // { INFO_FORMAT: "application/vnd.ogc.gml" } // not allowed by d4d
              { INFO_FORMAT: "application/json" }
            );

            if (waxisUrl) {
              // cannot directly query here because of SOP
              HTTP.get(waxisUrl, {
                headers: {
                  "X-Gemma-Auth": localStorage.getItem("token")
                }
              }).then(response => {
                let features = response.data.features.map(f => {
                  let feat = new Feature({
                    geometry: new Point(f.geometry.coordinates)
                  });
                  feat.setId(f.id);
                  feat.setProperties(f.properties);
                  return feat;
                });
                commit("addIdentifiedFeatures", features);
              });
            }
            var waterwayAreaSource = getters.openLayersMap
              .getLayer("WATERWAYAREA")
              .getSource();
            var wareaUrl = waterwayAreaSource.getGetFeatureInfoUrl(
              event.coordinate,
              100 /* resolution */,
              "EPSG:3857",
              // { INFO_FORMAT: "application/vnd.ogc.gml" } // not allowed by d4d
              { INFO_FORMAT: "application/json" }
            );

            if (wareaUrl) {
              // cannot directly query here because of SOP
              HTTP.get(wareaUrl, {
                headers: {
                  "X-Gemma-Auth": localStorage.getItem("token")
                }
              }).then(response => {
                let features = response.data.features.map(f => {
                  let feat = new Feature({
                    geometry: new Point(f.geometry.coordinates)
                  });
                  feat.setId(f.id);
                  feat.setProperties(f.properties);
                  return feat;
                });
                commit("addIdentifiedFeatures", features);
              });
            }
            var dmaSource = getters.openLayersMap
              .getLayer("DISTANCEMARKSAXIS")
              .getSource();
            var dmaUrl = dmaSource.getGetFeatureInfoUrl(
              event.coordinate,
              100 /* resolution */,
              "EPSG:3857",
              // { INFO_FORMAT: "application/vnd.ogc.gml" } // not allowed by d4d
              { INFO_FORMAT: "application/json" }
            );

            if (dmaUrl) {
              HTTP.get(dmaUrl, {
                headers: {
                  "X-Gemma-Auth": localStorage.getItem("token")
                }
              }).then(response => {
                let features = response.data.features.map(f => {
                  let feat = new Feature({
                    geometry: new Point(f.geometry.coordinates)
                  });
                  feat.setId(f.id);
                  feat.setProperties(f.properties);
                  return feat;
                });
                commit("addIdentifiedFeatures", features);
              });
            }
            // trying the GetFeatureInfo way for WMS
            var iecdisSource = getters.openLayersMap
              .getLayer("INLANDECDIS")
              .getSource();
            var iecdisUrl = iecdisSource.getGetFeatureInfoUrl(
              event.coordinate,
              100 /* resolution */,
              "EPSG:3857",
              // { INFO_FORMAT: "application/vnd.ogc.gml" } // not allowed by d4d
              { INFO_FORMAT: "text/plain" }
            );

            if (iecdisUrl) {
              // cannot directly query here because of SOP
              console.log("GetFeatureInfo url:", iecdisUrl);
            }
          }
        );
      }
    },
    moveToBoundingBox({ getters }, { boundingBox, zoom, preventZoomOut }) {
      const extent = transformExtent(boundingBox, "EPSG:4326", "EPSG:3857");
      let view = getters.openLayersMap.getView();
      moveMap({ view, extent, zoom, preventZoomOut });
    },
    moveToExtent({ getters }, { feature, zoom, preventZoomOut }) {
      const boundingBox = bbox(feature.geometry);
      const extent = transformExtent(boundingBox, "EPSG:4326", "EPSG:3857");
      let view = getters.openLayersMap.getView();
      moveMap({ view, extent, zoom, preventZoomOut });
    },
    moveMap({ getters }, { coordinates, zoom, preventZoomOut }) {
      let view = getters.openLayersMap.getView();
      const currentZoom = view.getZoom();
      zoom = zoom || currentZoom;
      view.animate({
        zoom: preventZoomOut ? Math.max(zoom, currentZoom) : zoom,
        center: fromLonLat(coordinates, view.getProjection()),
        duration: 700
      });
    }
  }
};