Mercurial > gemma
view client/src/components/map/fairway/Profiles.vue @ 1391:801ae5f4bc5b
fixed bug when changing additional survey in profile dialog
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Wed, 28 Nov 2018 08:11:23 +0100 |
parents | 8b85032ed3cd |
children | b350b0b5cb6c |
line wrap: on
line source
<template> <div :class="['box ui-element rounded bg-white text-nowrap', { expanded: showProfiles }]"> <div style="width: 20rem"> <h6 class="mb-0 py-2 px-3 border-bottom d-flex align-items-center"> <font-awesome-icon icon="chart-area" class="mr-2"></font-awesome-icon> Profiles <font-awesome-icon icon="times" class="ml-auto text-muted" @click="$store.commit('application/showProfiles', false)" ></font-awesome-icon> </h6> <div class="d-flex flex-column p-3 flex-grow-1 text-left position-relative"> <div class="loading d-flex justify-content-center align-items-center" v-if="surveysLoading || profileLoading"> <font-awesome-icon icon="spinner" spin /> </div> <small class="text-muted">Bottleneck:</small> <select @click="moveToBottleneck" v-model="selectedBottleneck" class="form-control form-control-sm"> <option :value="null">Select Bottleneck</option> <option v-for="bn in bottlenecks" :key="bn.properties.name" :value="bn.properties.name" >{{ bn.properties.name }}</option> </select> <div v-if="selectedBottleneck"> <div class="d-flex mt-2"> <div class="flex-fill"> <small class="text-muted">Sounding Result:</small> <select v-model="selectedSurvey" class="form-control form-control-sm"> <option v-for="survey in surveys" :key="survey.date_info" :value="survey" >{{ survey.date_info }}</option> </select> </div> <div class="flex-fill ml-3" v-if="selectedSurvey && surveys.length > 1"> <small class="text-muted mt-1">Compare with:</small> <select v-model="additionalSurvey" class="form-control form-control-sm"> <option :value="null">None</option> <option v-for="survey in additionalSurveys" :key="survey.date_info" :value="survey" >{{ survey.date_info }}</option> </select> </div> </div> <hr class="w-100"> <small class="d-flex text-left my-2" v-if="startPoint && endPoint"> <div class="text-nowrap mr-3"> <b>Start:</b> <br> Lat: {{ startPoint[1] }} <br> Lon: {{ startPoint[0] }} </div> <div class="text-nowrap"> <b>End:</b> <br> Lat: {{ endPoint[1] }} <br> Lon: {{ endPoint[0] }} </div> <button v-clipboard:copy="coordinatesForClipboard" v-clipboard:success="onCopyCoordinates" class="btn btn-info btn-sm ml-auto mt-auto" ><font-awesome-icon icon="copy" /></button> </small> <div class="d-flex"> <div class="pr-3 w-50" v-if="startPoint && endPoint"> <button class="btn btn-info btn-sm w-100" @click="showLabelInput = !showLabelInput" > <font-awesome-icon :icon="showLabelInput ? 'times' : 'check'" /> {{ showLabelInput ? "Cancel" : "Save" }} </button> </div> <div :class="startPoint && endPoint ? 'w-50' : 'w-100'"> <button class="btn btn-info btn-sm w-100" @click="toggleCutTool" > <font-awesome-icon :icon="cutTool && cutTool.getActive() ? 'times' : 'plus'"></font-awesome-icon> {{ cutTool && cutTool.getActive() ? "Cancel" : "New" }} </button> </div> </div> <div v-if="showLabelInput" class="mt-2"> <small class="text-muted">Enter label for cross profile:</small> <div class="position-relative"> <input class="form-control form-control-sm pr-5" v-model="cutLabel" /> <button class="btn btn-sm btn-info position-absolute input-button-right" @click="saveCut" v-if="cutLabel" style="top: 0; right: 0;" ><font-awesome-icon icon="check" /></button> </div> </div> <small class="text-muted d-block mt-2">Saved cross profiles:</small> <select class="form-control form-control-sm" v-model="coordinatesSelect"> <option></option> <option v-for="(cut, index) in previousCuts" :value="cut.coordinates" :key="index"> {{ cut.label }} </option> </select> <small class="text-muted d-block mt-2">Enter coordinates manually:</small> <div class="position-relative"> <input class="form-control form-control-sm pr-5" placeholder="Lat,Lon,Lat,Lon" v-model="coordinatesInput" /> <button class="btn btn-sm btn-info position-absolute input-button-right" @click="applyManualCoordinates" style="top: 0; right: 0;" v-if="coordinatesInputIsValid" ><font-awesome-icon icon="check" /></button> </div> </div> </div> </div> </div> </template> <style lang="sass" scoped> .loading background: rgba(255, 255, 255, 0.96) position: absolute z-index: 99 top: 0 right: 0 bottom: 0 left: 0 .input-button-right border-top-right-radius: $border-radius border-bottom-right-radius: $border-radius border-top-left-radius: 0 !important border-bottom-left-radius: 0 !important </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): * Markus Kottländer <markus.kottlaender@intevation.de> */ import { mapState, mapGetters } from "vuex"; import Feature from "ol/Feature"; import LineString from "ol/geom/LineString"; import { displayError, displayInfo } from "../../../lib/errors.js"; export default { name: "profiles", data() { return { coordinatesInput: "", coordinatesSelect: null, cutLabel: "", showLabelInput: false }; }, computed: { ...mapGetters("map", ["getVSourceByName"]), ...mapState("application", ["showProfiles"]), ...mapState("map", ["lineTool", "polygonTool", "cutTool"]), ...mapState("bottlenecks", ["bottlenecks", "surveys", "surveysLoading"]), ...mapState("fairwayprofile", [ "previousCuts", "startPoint", "endPoint", "profileLoading" ]), selectedBottleneck: { get() { return this.$store.state.bottlenecks.selectedBottleneck; }, set(name) { this.loading = true; this.$store.dispatch("bottlenecks/setSelectedBottleneck", name); } }, selectedSurvey: { get() { return this.$store.state.bottlenecks.selectedSurvey; }, set(survey) { this.$store.commit("bottlenecks/setSelectedSurvey", survey); } }, additionalSurvey: { get() { return this.$store.state.fairwayprofile.additionalSurvey; }, set(survey) { this.$store.commit("fairwayprofile/additionalSurvey", survey); } }, additionalSurveys() { return this.surveys.filter(survey => survey !== this.selectedSurvey); }, coordinatesForClipboard() { return ( this.startPoint[1] + "," + this.startPoint[0] + "," + this.endPoint[1] + "," + this.endPoint[0] ); }, coordinatesInputIsValid() { const coordinates = this.coordinatesInput .split(",") .map(coord => parseFloat(coord.trim())) .filter(c => Number(c) === c); return coordinates.length === 4; } }, watch: { selectedBottleneck() { this.$store.dispatch("fairwayprofile/previousCuts"); this.cutLabel = this.selectedBottleneck + " (" + new Date().toISOString() + ")"; }, selectedSurvey(survey) { this.$store.commit("fairwayprofile/additionalSurvey", null); if (survey) { this.$store.dispatch("fairwayprofile/loadProfile", survey); } }, additionalSurvey(survey) { if (survey) this.$store.dispatch("fairwayprofile/loadProfile", survey); }, coordinatesSelect(newValue) { if (newValue) { this.applyCoordinates(newValue); this.coordinatesSelect = null; } } }, methods: { toggleCutTool() { if (this.selectedSurvey) { this.cutTool.setActive(!this.cutTool.getActive()); this.lineTool.setActive(false); this.polygonTool.setActive(false); this.$store.commit("map/setCurrentMeasurement", null); } }, onCopyCoordinates() { displayInfo({ title: "Success", message: "Coordinates copied to clipboard!" }); }, applyManualCoordinates() { const coordinates = this.coordinatesInput .split(",") .map(coord => parseFloat(coord.trim())); this.coordinatesSelect = null; this.coordinatesInput = ""; this.applyCoordinates([ coordinates[1], coordinates[0], coordinates[3], coordinates[2] ]); }, applyCoordinates(coordinates) { // allow only numbers coordinates = coordinates.filter(c => Number(c) === c); if (coordinates.length === 4) { // draw line on map this.getVSourceByName("Cut Tool").clear(); const cut = new Feature({ geometry: new LineString([ [coordinates[0], coordinates[1]], [coordinates[2], coordinates[3]] ]).transform("EPSG:4326", "EPSG:3857") }); this.getVSourceByName("Cut Tool").addFeature(cut); // draw diagram this.$store.dispatch("fairwayprofile/cut", cut); } else { displayError({ title: "Invalid input", message: "Please enter correct coordinates in the format: Lat,Lon,Lat,Lon" }); } }, saveCut() { const previousCuts = JSON.parse(localStorage.getItem("previousCuts")) || []; const newEntry = { label: this.cutLabel, bottleneckName: this.selectedBottleneck, coordinates: [...this.startPoint, ...this.endPoint], timestamp: new Date().getTime() }; const existingEntry = previousCuts.find(cut => { return JSON.stringify(cut) === JSON.stringify(newEntry); }); if (!existingEntry) previousCuts.push(newEntry); if (previousCuts.length > 100) previousCuts.shift(); localStorage.setItem("previousCuts", JSON.stringify(previousCuts)); this.$store.dispatch("fairwayprofile/previousCuts"); this.showLabelInput = false; this.cutLabel = ""; displayInfo({ title: "Coordinates saved!", message: 'You can now select these coordinates from the "Saved cross profiles" menu to restore this cross profile.' }); }, moveToBottleneck() { const bottleneck = this.bottlenecks.find( bn => bn.properties.name === this.selectedBottleneck ); if (!bottleneck) return; this.$store.commit("map/moveMap", { coordinates: bottleneck.geometry.coordinates, zoom: 17, preventZoomOut: true }); } } }; </script>