Mercurial > gemma
diff client/src/components/map/Maplayer.vue @ 1272:bc55ffaeb639
cleaned up client/src directory
better organization of files and directories, better naming, separation of admin and map context
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Thu, 22 Nov 2018 07:07:12 +0100 |
parents | |
children | 99c039e86624 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/map/Maplayer.vue Thu Nov 22 07:07:12 2018 +0100 @@ -0,0 +1,430 @@ +<template> + <div id="map" :class="mapStyle"></div> +</template> + +<style lang="sass" scoped> +.nocursor + cursor: none + +.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 "../../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"; +import { getCenter } from "ol/extent"; + +/* 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", + "lineTool", + "polygonTool", + "cutTool" + ]), + ...mapState("bottlenecks", ["selectedSurvey"]), + mapStyle() { + return { + mapfull: !this.split, + mapsplit: this.split, + nocursor: this.hasActiveInteractions + }; + }, + hasActiveInteractions() { + return ( + (this.lineTool && this.lineTool.getActive()) || + (this.polygonTool && this.polygonTool.getActive()) || + (this.cutTool && this.cutTool.getActive()) + ); + } + }, + methods: { + identify(coordinate, pixel) { + if (!this.hasActiveInteractions) { + 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") + ); + this.$store.commit("map/moveMap", { + coordinates: getCenter( + feature + .getGeometry() + .clone() + .transform("EPSG:3857", "EPSG:4326") + .getExtent() + ), + zoom: 17, + preventZoomOut: true + }); + } + } + } + + // 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>