Mercurial > gemma
changeset 1374:353d36dd2571
Merged.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 27 Nov 2018 13:03:03 +0100 |
parents | 84e78d2e2d95 (current diff) 553aadd97087 (diff) |
children | e27176811d2f |
files | client/src/components/map/toolbar/Cuttool.vue |
diffstat | 13 files changed, 461 insertions(+), 318 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/App.vue Tue Nov 27 13:02:28 2018 +0100 +++ b/client/src/components/App.vue Tue Nov 27 13:03:03 2018 +0100 @@ -11,18 +11,18 @@ </div> <div class="ml-auto d-flex"> <div class="d-flex flex-column align-items-end"> - <Layers v-if="routeName == 'mainview'"></Layers> + <Profiles v-if="routeName == 'mainview'"></Profiles> + <Pdftool v-if="routeName == 'mainview'"></Pdftool> </div> <div class="d-flex flex-column align-items-end"> <Identify v-if="routeName == 'mainview'"></Identify> - <Pdftool v-if="routeName == 'mainview'"></Pdftool> + <Layers v-if="routeName == 'mainview'"></Layers> </div> <Toolbar v-if="routeName == 'mainview'"></Toolbar> </div> </div> <div class="flex-fill"></div> <div class="d-flex flex-row align-items-end"> - <Surveys v-if="routeName == 'mainview'"></Surveys> <Infobar v-if="routeName == 'mainview'"></Infobar> </div> <Zoom v-if="routeName == 'mainview'"></Zoom> @@ -86,7 +86,7 @@ } }, components: { - Surveys: () => import("./map/fairway/Surveys"), + Profiles: () => import("./map/fairway/Profiles"), Infobar: () => import("./map/fairway/Infobar"), Pdftool: () => import("./map/Pdftool"), Zoom: () => import("./map/Zoom"),
--- a/client/src/components/map/Main.vue Tue Nov 27 13:02:28 2018 +0100 +++ b/client/src/components/map/Main.vue Tue Nov 27 13:03:03 2018 +0100 @@ -2,11 +2,9 @@ <div class="main d-flex flex-column"> <Maplayer :split="showSplitscreen"></Maplayer> <FairwayProfile - :additionalSurveys="additionalSurveys" :xScale="xAxis" :yScaleLeft="yAxisLeft" :yScaleRight="yAxisRight" - :margin="margins" ></FairwayProfile> </div> </template> @@ -36,37 +34,15 @@ Maplayer, FairwayProfile }, - data() { - return { - width: null, - height: null, - margin: { - top: 20, - right: 40, - bottom: 30, - left: 40 - } - }; - }, computed: { ...mapState("application", ["showSplitscreen"]), ...mapState("fairwayprofile", [ - "currentProfile", "minAlt", "maxAlt", "totalLength", - "waterLevels", - "fairwayCoordinates", "selectedWaterLevel" ]), ...mapState("bottlenecks", ["surveys", "selectedSurvey"]), - additionalSurveys() { - if (!this.surveys) return []; - if (!this.selectedSurvey) return this.surveys; - return this.surveys.filter(survey => { - return survey.date_info !== this.selectedSurvey.date_info; - }); - }, xAxis() { return [this.xScale.x, this.xScale.y]; }, @@ -78,9 +54,6 @@ const DELTA = this.maxAlt * 1.1 - this.maxAlt; return [this.maxAlt * 1 + DELTA, -DELTA]; }, - margins() { - return this.margin; - }, yScaleLeft() { return { lo: this.minAlt,
--- a/client/src/components/map/Maplayer.vue Tue Nov 27 13:02:28 2018 +0100 +++ b/client/src/components/map/Maplayer.vue Tue Nov 27 13:03:03 2018 +0100 @@ -433,6 +433,7 @@ this.openLayersMap.on(["singleclick", "dblclick"], event => { this.identify(event.coordinate, event.pixel); }); + this.$store.dispatch("bottlenecks/loadBottlenecks"); } }; </script>
--- a/client/src/components/map/fairway/Fairwayprofile.vue Tue Nov 27 13:02:28 2018 +0100 +++ b/client/src/components/map/fairway/Fairwayprofile.vue Tue Nov 27 13:03:03 2018 +0100 @@ -23,94 +23,6 @@ >{{ selectedBottleneck }} ({{ selectedSurvey.date_info }})</h5> <div class="d-flex flex-fill"> <div class="fairwayprofile m-3 mt-0 bg-white flex-grow-1"></div> - <div class="additionalsurveys d-flex flex-column"> - <small> - Additional Surveys - <select - v-model="additionalSurvey" - class="form-control form-control-sm" - > - <option value>None</option> - <option - v-for="survey in additionalSurveys" - :key="survey.date_info" - :value="survey" - >{{survey.date_info}}</option> - </select> - <hr> - <div class="d-flex text-left mb-2"> - <div class="text-nowrap mr-1"> - <b>Start:</b> - <br> - Lat: {{ startPoint[1] }} - <br> - Lon: {{ startPoint[0] }} - </div> - <div class="text-nowrap ml-1"> - <b>End:</b> - <br> - Lat: {{ endPoint[1] }} - <br> - Lon: {{ endPoint[0] }} - </div> - <button - class="btn btn-outline-secondary btn-sm ml-2 mt-auto" - @click="showLabelInput = !showLabelInput" - > - <font-awesome-icon :icon="showLabelInput ? 'times' : 'folder-plus'" size="lg"/> - </button> - <button - v-clipboard:copy="coordinatesForClipboard" - v-clipboard:success="onCopyCoordinates" - class="btn btn-outline-secondary btn-sm ml-2 mt-auto" - > - <font-awesome-icon icon="copy"/> - </button> - </div> - <div v-if="showLabelInput">Enter label for cross profile: - <div class="position-relative"> - <input class="form-control form-control-sm pr-5" v-model="cutLabel"> - <br> - <button - class="btn btn-sm btn-outline-secondary position-absolute" - @click="saveCut" - v-if="cutLabel" - style="top: 0; right: 0;" - > - <font-awesome-icon icon="check"/> - </button> - </div> - </div>Saved cross profiles: - <select - class="form-control form-control-sm mb-2" - v-model="coordinatesSelect" - > - <option></option> - <option - v-for="(cut, index) in previousCuts" - :value="cut.coordinates" - :key="index" - >{{ cut.label }}</option> - </select> - Enter coordinates manually: - <div class="position-relative"> - <input - class="form-control form-control-sm pr-5" - placeholder="Lat,Lon,Lat,Lon" - v-model="coordinatesInput" - > - <br> - <button - class="btn btn-sm btn-outline-secondary position-absolute" - @click="applyManualCoordinates" - style="top: 0; right: 0;" - v-if="coordinatesInput" - > - <font-awesome-icon icon="check"/> - </button> - </div> - </small> - </div> </div> </div> </div> @@ -144,20 +56,6 @@ .show .profile height: 50vh - -.waterlevelselection - margin-top: $large-offset - margin-right: $large-offset - -.additionalsurveys - margin-top: $large-offset - margin-bottom: auto - margin-right: $large-offset - margin-left: auto - max-width: 300px - -.additionalsurveys input - margin-right: $small-offset </style> <script> @@ -176,16 +74,14 @@ */ import * as d3 from "d3"; import { mapState, mapGetters } from "vuex"; -import { displayError, displayInfo } from "../../../lib/errors.js"; -import Feature from "ol/Feature"; -import LineString from "ol/geom/LineString"; +import { displayError } from "../../../lib/errors.js"; import debounce from "debounce"; const GROUND_COLOR = "#4A2F06"; export default { name: "fairwayprofile", - props: ["xScale", "yScaleLeft", "yScaleRight", "margin", "additionalSurveys"], + props: ["xScale", "yScaleLeft", "yScaleRight"], data() { return { wait: false, @@ -194,7 +90,13 @@ cutLabel: "", showLabelInput: false, width: null, - height: null + height: null, + margin: { + top: 20, + right: 40, + bottom: 30, + left: 40 + } }; }, computed: { @@ -243,23 +145,9 @@ x => x.level === this.selectedWaterLevel ); return result.color; - }, - coordinatesForClipboard() { - return ( - this.startPoint[1] + - "," + - this.startPoint[0] + - "," + - this.endPoint[1] + - "," + - this.endPoint[0] - ); } }, watch: { - showSplitscreen() { - this.drawDiagram(); - }, currentData() { this.drawDiagram(); }, @@ -277,16 +165,6 @@ }, fairwayCoordinates() { this.drawDiagram(); - }, - selectedBottleneck() { - this.$store.dispatch("fairwayprofile/previousCuts"); - this.cutLabel = - this.selectedBottleneck + " (" + new Date().toISOString() + ")"; - }, - coordinatesSelect(newValue) { - if (newValue) { - this.applyCoordinates(newValue); - } } }, methods: { @@ -542,71 +420,6 @@ if (!clientHeight || !clientWidth) return; this.height = clientHeight; this.width = clientWidth; - }, - onCopyCoordinates() { - displayInfo({ - title: "Success", - message: "Coordinates copied to clipboard!" - }); - }, - applyManualCoordinates() { - const coordinates = this.coordinatesInput - .split(",") - .map(coord => parseFloat(coord.trim())); - 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 - const cutLayer = this.getLayerByName("Cut Tool"); - cutLayer.data.getSource().clear(); - const cut = new Feature({ - geometry: new LineString([ - [coordinates[0], coordinates[1]], - [coordinates[2], coordinates[3]] - ]).transform("EPSG:4326", "EPSG:3857") - }); - cutLayer.data.getSource().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] - }; - 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; - displayInfo({ - title: "Coordinates saved!", - message: - 'You can now select these coordinates from the "Saved cross profiles" menu to restore this cross profile.' - }); } }, created() {
--- a/client/src/components/map/fairway/Infobar.vue Tue Nov 27 13:02:28 2018 +0100 +++ b/client/src/components/map/fairway/Infobar.vue Tue Nov 27 13:03:03 2018 +0100 @@ -1,6 +1,6 @@ <template> <div - v-if="selectedSurvey && !showSplitscreen" + v-if="Object.keys(currentProfile).length && !showSplitscreen" class="ui-element shadow-xs infobar rounded bg-white ml-auto mb-3 mr-3" > <div class="d-flex flex-row justify-content-between"> @@ -11,7 +11,6 @@ <span class="p-2 border-left d-flex align-items-center" @click="$store.commit('application/showSplitscreen', true)" - v-if="Object.keys(currentProfile).length" > <font-awesome-icon icon="angle-up"></font-awesome-icon> </span>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/map/fairway/Profiles.vue Tue Nov 27 13:03:03 2018 +0100 @@ -0,0 +1,336 @@ +<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/setAdditionalSurvey", 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) { + 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); + } + } + }, + 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] + }; + 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>
--- a/client/src/components/map/toolbar/Cuttool.vue Tue Nov 27 13:02:28 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -<template> - <div @click="toggleCutTool" class="toolbar-button"> - <font-awesome-icon icon="chart-area" :class="{ 'text-info': cutTool && cutTool.getActive(), grey: !selectedSurvey }"></font-awesome-icon> - </div> -</template> - -<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 } from "vuex"; - -export default { - name: "cuttool", - computed: { - ...mapState("map", ["lineTool", "polygonTool", "cutTool"]), - ...mapState("bottlenecks", ["selectedSurvey"]) - }, - 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); - } - } - } -}; -</script>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/map/toolbar/Profiles.vue Tue Nov 27 13:03:03 2018 +0100 @@ -0,0 +1,29 @@ +<template> + <div @click="$store.commit('application/showProfiles', !showProfiles)" class="toolbar-button"> + <font-awesome-icon icon="chart-area" :class="{ 'text-info': showProfiles }"></font-awesome-icon> + </div> +</template> + +<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 } from "vuex"; + +export default { + name: "profiles", + computed: { + ...mapState("application", ["showProfiles"]) + } +}; +</script>
--- a/client/src/components/map/toolbar/Toolbar.vue Tue Nov 27 13:02:28 2018 +0100 +++ b/client/src/components/map/toolbar/Toolbar.vue Tue Nov 27 13:03:03 2018 +0100 @@ -3,7 +3,7 @@ <div :class="'toolbar toolbar-' + (expandToolbar ? 'expanded' : 'collapsed')"> <Identify></Identify> <Layers></Layers> - <Cuttool></Cuttool> + <Profiles></Profiles> <Linetool></Linetool> <Polygontool></Polygontool> <Pdftool></Pdftool> @@ -70,7 +70,7 @@ Layers: () => import("./Layers.vue"), Linetool: () => import("./Linetool.vue"), Polygontool: () => import("./Polygontool.vue"), - Cuttool: () => import("./Cuttool.vue"), + Profiles: () => import("./Profiles.vue"), Pdftool: () => import("./Pdftool.vue") }, computed: {
--- a/client/src/main.js Tue Nov 27 13:02:28 2018 +0100 +++ b/client/src/main.js Tue Nov 27 13:03:03 2018 +0100 @@ -64,7 +64,8 @@ faPlus, faMinus, faSortAmountUp, - faSortAmountDown + faSortAmountDown, + faSpinner } from "@fortawesome/free-solid-svg-icons"; import { faAdn } from "@fortawesome/free-brands-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; @@ -107,7 +108,8 @@ faPlus, faMinus, faSortAmountUp, - faSortAmountDown + faSortAmountDown, + faSpinner ); Vue.component("font-awesome-icon", FontAwesomeIcon);
--- a/client/src/store/application.js Tue Nov 27 13:02:28 2018 +0100 +++ b/client/src/store/application.js Tue Nov 27 13:03:03 2018 +0100 @@ -30,6 +30,7 @@ showLayers: true, showPdfTool: false, showContextBox: false, + showProfiles: false, contextBoxContent: null, // bottlenecks, imports, staging expandToolbar: false, countries: ["AT", "SK", "HU", "HR", "RS", "BiH", "BG", "RO", "UA"], @@ -84,6 +85,9 @@ showContextBox: (state, show) => { state.showContextBox = show; }, + showProfiles: (state, show) => { + state.showProfiles = show; + }, contextBoxContent: (state, context) => { state.contextBoxContent = context; if (context) {
--- a/client/src/store/bottlenecks.js Tue Nov 27 13:02:28 2018 +0100 +++ b/client/src/store/bottlenecks.js Tue Nov 27 13:03:03 2018 +0100 @@ -22,7 +22,8 @@ bottlenecks: [], selectedBottleneck: null, surveys: [], - selectedSurvey: null + selectedSurvey: null, + surveysLoading: false }; }; @@ -42,6 +43,9 @@ }, setSelectedSurvey(state, survey) { state.selectedSurvey = survey; + }, + surveysLoading: (state, loading) => { + state.surveysLoading = loading; } }, actions: { @@ -50,6 +54,9 @@ commit("setSelectedSurvey", null); commit("fairwayprofile/clearCurrentProfile", null, { root: true }); } + if (name) { + commit("application/showProfiles", true, { root: true }); + } commit("setSelectedBottleneck", name); dispatch("querySurveys", name); }, @@ -79,6 +86,7 @@ }, querySurveys({ commit }, name) { if (name) { + commit("surveysLoading", true); HTTP.get("/surveys/" + name, { headers: { "X-Gemma-Auth": localStorage.getItem("token"), @@ -86,16 +94,22 @@ } }) .then(response => { - commit("setSurveys", response.data.surveys); + const surveys = response.data.surveys.sort( + (a, b) => (a.date_info < b.date_info ? 1 : -1) + ); + commit("setSelectedSurvey", surveys[0]); + commit("setSurveys", surveys); }) .catch(error => { commit("setSurveys", []); + commit("setSelectedSurvey", null); const { status, data } = error.response; displayError({ title: "Backend Error", message: `${status}: ${data.message || data}` }); - }); + }) + .finally(() => commit("surveysLoading", false)); } else { commit("setSurveys", []); }
--- a/client/src/store/fairway.js Tue Nov 27 13:02:28 2018 +0100 +++ b/client/src/store/fairway.js Tue Nov 27 13:03:03 2018 +0100 @@ -37,7 +37,8 @@ fairwayCoordinates: [], startPoint: null, endPoint: null, - previousCuts: [] + previousCuts: [], + profileLoading: false }; }; @@ -103,6 +104,9 @@ }, previousCuts: (state, previousCuts) => { state.previousCuts = previousCuts; + }, + profileLoading: (state, loading) => { + state.profileLoading = loading; } }, actions: { @@ -116,27 +120,34 @@ .clear(); }, loadProfile({ commit, state }, survey) { - return new Promise((resolve, reject) => { - const profileLine = new LineString([state.startPoint, state.endPoint]); - const geoJSON = generateFeatureRequest( - profileLine, - survey.bottleneck_id, - survey.date_info - ); - HTTP.post("/cross", geoJSON, { - headers: { "X-Gemma-Auth": localStorage.getItem("token") } - }) - .then(response => { - commit("profileLoaded", { - response: response, - surveyDate: survey.date_info - }); - resolve(response); + if (state.startPoint && state.endPoint) { + return new Promise((resolve, reject) => { + commit("profileLoading", true); + const profileLine = new LineString([ + state.startPoint, + state.endPoint + ]); + const geoJSON = generateFeatureRequest( + profileLine, + survey.bottleneck_id, + survey.date_info + ); + HTTP.post("/cross", geoJSON, { + headers: { "X-Gemma-Auth": localStorage.getItem("token") } }) - .catch(error => { - reject(error); - }); - }); + .then(response => { + commit("profileLoaded", { + response: response, + surveyDate: survey.date_info + }); + resolve(response); + }) + .catch(error => { + reject(error); + }) + .finally(() => commit("profileLoading", false)); + }); + } }, cut({ commit, dispatch, rootState, rootGetters }, cut) { const length = getLength(cut.getGeometry()); @@ -165,28 +176,29 @@ const profileLine = new LineString([start, end]); dispatch("loadProfile", rootState.bottlenecks.selectedSurvey) .then(() => { - rootGetters["map/getLayerByName"]("Fairway Dimensions") - .data.getSource() - .forEachFeatureIntersectingExtent( - // need to use EPSG:3857 which is the proj of vectorSource - profileLine + rootState.map.cutTool.setActive(false); + rootGetters["map/getVSourceByName"]( + "Fairway Dimensions" + ).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 intersectingPolygon = feature + .getGeometry() .clone() - .transform("EPSG:4326", "EPSG:3857") - .getExtent(), - feature => { - // transform back to prepare for usage - var intersectingPolygon = feature - .getGeometry() - .clone() - .transform("EPSG:3857", "EPSG:4326"); - const fairwayCoordinates = calculateFairwayCoordinates( - profileLine, - intersectingPolygon, - DEMODATA - ); - commit("setFairwayCoordinates", fairwayCoordinates); - } - ); + .transform("EPSG:3857", "EPSG:4326"); + const fairwayCoordinates = calculateFairwayCoordinates( + profileLine, + intersectingPolygon, + DEMODATA + ); + commit("setFairwayCoordinates", fairwayCoordinates); + } + ); }) .then(() => { commit("application/showSplitscreen", true, { root: true });