Mercurial > gemma
view client/src/store/map.js @ 3044:c71373594719
client: map: prepared store to hold multiple map objects
This will be necessary to sync maps, toggle layers per map, etc. Therefore the methods to move the map
(moveToExtent, etc.) became actions instead of mutations.
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Sat, 13 Apr 2019 16:02:06 +0200 |
parents | de75404cb5fc |
children | e0b77d7463e7 |
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)); } } } */ // trying the GetFeatureInfo way for WMS 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 }); } } };