# HG changeset patch # User Tom Gottfried # Date 1568986516 -7200 # Node ID 0f2c3cb139cc1c999f19d76a28cb8ded066c0536 # Parent ae840f9eb4c8767f7adf097e0f02bd8d2a4bdf51# Parent 5e62c467e145073114cb1f42aeeebced4621037b Merge default into geoserver_sql_views diff -r ae840f9eb4c8 -r 0f2c3cb139cc .hgignore --- a/.hgignore Mon Sep 16 16:56:11 2019 +0200 +++ b/.hgignore Fri Sep 20 15:35:16 2019 +0200 @@ -97,7 +97,6 @@ .buildbase session.data gemma -cmd/tokenserver/tokenserver web gemma.toml CHROME* diff -r ae840f9eb4c8 -r 0f2c3cb139cc .hgtags --- a/.hgtags Mon Sep 16 16:56:11 2019 +0200 +++ b/.hgtags Fri Sep 20 15:35:16 2019 +0200 @@ -13,3 +13,4 @@ d78af8354b95cea86744459f350edb16662dadd0 v3.1 5396581cf20334cbc5e69280e5d9b192640d96b9 v4-preview20190717 aececbc3d04798d905e65196ac0870d081776ca2 v4-preview20190726 +b5619087e3e909645eeab9e3f198667692895382 v4-preview20190918 diff -r ae840f9eb4c8 -r 0f2c3cb139cc 3rdpartylibs.sh --- a/3rdpartylibs.sh Mon Sep 16 16:56:11 2019 +0200 +++ b/3rdpartylibs.sh Fri Sep 20 15:35:16 2019 +0200 @@ -1,5 +1,14 @@ #!/bin/sh -go get -u -v github.com/jackc/pgx + +# pgx hase undergone some major incompatible changes in v4, +# we need to stick to v3 for now... +# Unfortunatly using gopkg.in does not work as expected here, so lets +# get hackisch... +go get -u -v gopkg.in/jackc/pgx.v3 +oldcwd="$CWD" +cd "$GOPATH"/src/github.com/jackc/pgx +git checkout v3.6.0 +cd "$oldcwd" # MIT go get -u -v github.com/etcd-io/bbolt/... @@ -32,7 +41,7 @@ go get -u -v github.com/jonas-p/go-shp # MIT -go get -u -v github.com/robfig/cron +go get -u -v gopkg.in/robfig/cron.v1 # MIT go get -u -v github.com/tidwall/rtree diff -r ae840f9eb4c8 -r 0f2c3cb139cc Makefile --- a/Makefile Mon Sep 16 16:56:11 2019 +0200 +++ b/Makefile Fri Sep 20 15:35:16 2019 +0200 @@ -50,7 +50,7 @@ v="gemma-$$(hg id -i)" ;\ tar --transform "s@^@$${v}/@" \ -cJf "../$${v}.tar.xz" \ - cmd/gemma/gemma schema web example_conf.toml + cmd/gemma/gemma schema web misc example_conf.toml clean: $(MAKE) -f Makefile.build -C client $@ diff -r ae840f9eb4c8 -r 0f2c3cb139cc README.md --- a/README.md Mon Sep 16 16:56:11 2019 +0200 +++ b/README.md Fri Sep 20 15:35:16 2019 +0200 @@ -1,6 +1,6 @@ # Workingtitle "gemma" -//"gemma" is just a temporary title and is likely to be changed.// +//"gemma" is a working title and is likely to be changed.// # Quick Start @@ -18,7 +18,7 @@ - To only build the SPA-Client in demo mode you can use `make clientdemo`. -For further details see [docs/DEVELOPMENT](docs/DEVELOPMENT.md), +For further details see [docs/DEVELOPMENT](docs/DEVELOPMENT.md). ## Running Tests @@ -106,8 +106,8 @@ # License -//gemma// source code itself licenses as Free Software -under GNU Affero GPL v>=3. See the particular source files +//gemma// source code itself is licensed as Free Software +under GNU Affero GPL v>=3. See the specific source files for details, the license itself can be found in the directory `LICENSES`. To build a complete product, a number of other Free Software components diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/README.md --- a/client/README.md Mon Sep 16 16:56:11 2019 +0200 +++ b/client/README.md Fri Sep 20 15:35:16 2019 +0200 @@ -1,5 +1,8 @@ * Install dependencies + * [Yarn](https://yarnpkg.com/) and a compatible nodejs version (>=8.10.0) + is needed. + * Install (`xgettext`) tool (e.g. for Debian xgettext (GNU gettext-tools) 0.19.8.1) * Javascript diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/docs/dev-translations.md --- a/client/docs/dev-translations.md Mon Sep 16 16:56:11 2019 +0200 +++ b/client/docs/dev-translations.md Fri Sep 20 15:35:16 2019 +0200 @@ -26,7 +26,13 @@ - `gettext` must be called only in javascript part. For html part we use `` and `` to make sure that `makemessages` marks the strings correctly - passing a value with \`\` to `gettext` leads to break up the translation process (e.g. gettext(\` text to translate ${value} \`)) - passing html element (e.g. `
`) to gettext is interpreted as string. -- The strings to translate have to be included in the source code and not directly in `.po` files. +- The strings to translate have to be included in the source code and not directly in `.po` files. +- Use the central defined class ` text` to fix leading and trailing whitespace problem.see:[https://github.com/Polyconseil/vue-gettext/issues/80](https://github.com/Polyconseil/vue-gettext/issues/80). +- Check if the development work does not ruin the translation process: + Call `make makemessages` --> if `.po` files were generated --> everything is ok. + **Notice**: To avoid merge conflicts we push `.po` files into the repository after we synchronize it with the new translations on `weblate`. + We do this one time weekly, so you do not have to do this yourself. + If it is required to merge the new strings instantly please contact one of the translation managers. ## Why was gettext chosen? diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/Contextbox.vue --- a/client/src/components/Contextbox.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/Contextbox.vue Fri Sep 20 15:35:16 2019 +0200 @@ -59,6 +59,7 @@ this.$store.commit("map/mapPopupEnabled", true); this.$store.commit("application/searchQuery", ""); this.$store.commit("application/showContextBox", false); + this.$store.commit("map/reviewActive", false); this.$store.commit( "application/showSearchbar", this.showSearchbarLastState diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/Pdftool.vue --- a/client/src/components/Pdftool.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/Pdftool.vue Fri Sep 20 15:35:16 2019 +0200 @@ -206,14 +206,7 @@ } } - filename = - filename - .replace(/[^\w-]/gi, "") // remove everything but wordchars and dash - .toLowerCase() + - "-exported" + - date + - ".pdf"; - + filename = filename.toLowerCase() + "-exported" + date + ".pdf"; return filename; } }, @@ -462,15 +455,18 @@ ); }, cancel() { - this.openLayersMap().un( - this.rendercompleteListener.type, - this.rendercompleteListener.listener - ); - this.openLayersMap().setSize(this.mapSize); - this.openLayersMap() - .getView() - .fit(this.resolution, { size: this.mapSize }); - this.readyToGenerate = true; + try { + this.openLayersMap().un( + this.rendercompleteListener.type, + this.rendercompleteListener.listener + ); + this.openLayersMap().setSize(this.mapSize); + this.openLayersMap() + .getView() + .fit(this.resolution, { size: this.mapSize }); + } finally { + this.readyToGenerate = true; + } }, // add the used map scale and papersize addScale(scaleDenominator, position, width, offset, fontSize, color) { diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/fairway/AvailableFairwayDepth.vue --- a/client/src/components/fairway/AvailableFairwayDepth.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/fairway/AvailableFairwayDepth.vue Fri Sep 20 15:35:16 2019 +0200 @@ -100,6 +100,14 @@ }, data() { return { + frequencyD: null, + selectedFairwayAvailabilityFeatureD: null, + fromDate: null, + toDate: null, + depthlimit1D: null, + depthlimit2D: null, + widthlimit1D: null, + widthlimit2D: null, containerId: "availablefairwaydepth-diagram-container", resizeListenerFunction: null, loading: false, @@ -136,7 +144,7 @@ // not guarantee that the DOM is not only updated but also re-painted on the // screen. setTimeout(this.drawDiagram, 150); - + this.initDiagramValues(); this.templates[0] = this.defaultTemplate; this.form.template = this.templates[0]; this.templateData = this.form.template; @@ -176,20 +184,20 @@ "widthlimit2" ]), legend() { - const d = [this.depthlimit1, this.depthlimit2].sort(); - const w = [this.widthlimit1, this.widthlimit2].sort(); - const lowerBound = [d[0], w[0]].filter(x => x).join(", "); - const upperBound = [d[1], w[1]].filter(x => x).join(", "); + const d = [this.depthlimit1D, this.depthlimit2D].sort(); + const w = [this.widthlimit1D, this.widthlimit2D].sort(); + const lowerBound = [d[0] / 100, w[0]].filter(x => x).join(", "); + const upperBound = [d[1] / 100, w[1]].filter(x => x).join(", "); let result; - if (this.depthlimit1 !== this.depthlimit2) { + if (this.depthlimit1D !== this.depthlimit2D) { result = [ `> LDC`, - `>= ${upperBound}`, - `< ${upperBound}`, - `< ${lowerBound}` + `>= ${upperBound} [m]`, + `< ${upperBound} [m]`, + `< ${lowerBound} [m]` ]; } else { - result = [`> LDC`, `>= ${upperBound}`, `< ${upperBound}`]; + result = [`> LDC`, `>= ${upperBound} [m]`, `< ${upperBound} [m]`]; } return result; }, @@ -197,42 +205,49 @@ return `data:text/csv;charset=utf-8, ${encodeURIComponent(this.csv)}`; }, csvFileName() { + if (!this.frequencyD) return; return `${this.$gettext("fairwayavailability")}-${ this.featureName }-${filters.surveyDate(this.fromDate)}-${filters.surveyDate( this.toDate - )}-${this.$gettext(this.frequency)}-.csv`; + )}-${this.$gettext(this.frequencyD)}-.csv`; }, frequencyToRange() { + if (!this.frequencyD) return; const frequencies = { [FREQUENCIES.MONTHLY]: [-33, 33], [FREQUENCIES.QUARTERLY]: [-93, 93], [FREQUENCIES.YEARLY]: [-370, 370] }; - return frequencies[this.frequency]; - }, - fromDate() { - return this.from; - }, - toDate() { - return this.to; + return frequencies[this.frequencyD]; }, availability() { return this.plainAvailability; }, title() { + if (!this.frequencyD) return; return `Available Fairway Depth: ${ this.featureName } (${filters.surveyDate(this.fromDate)} - ${filters.surveyDate( this.toDate - )}) ${this.$gettext(this.frequency)}`; + )}) ${this.$gettext(this.frequencyD)}`; }, featureName() { - if (this.selectedFairwayAvailabilityFeature == null) return ""; - return this.selectedFairwayAvailabilityFeature.properties.name; + if (this.selectedFairwayAvailabilityFeatureD == null) return ""; + return this.selectedFairwayAvailabilityFeatureD.properties.name; } }, methods: { + initDiagramValues() { + this.selectedFairwayAvailabilityFeatureD = this.selectedFairwayAvailabilityFeature; + this.fromDate = this.from; + this.toDate = this.to; + this.depthlimit1D = this.depthlimit1; + this.depthlimit2D = this.depthlimit2; + this.widthlimit1D = this.widthlimit1; + this.widthlimit2D = this.widthlimit2; + this.frequencyD = this.frequency; + }, applyChange() { if (this.form.template.hasOwnProperty("properties")) { this.templateData = this.defaultTemplate; @@ -702,6 +717,7 @@ }, watch: { fwData() { + this.initDiagramValues(); this.drawDiagram(); }, showNumbers() { diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/fairway/AvailableFairwayDepthDialogue.vue --- a/client/src/components/fairway/AvailableFairwayDepthDialogue.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/fairway/AvailableFairwayDepthDialogue.vue Fri Sep 20 15:35:16 2019 +0200 @@ -162,7 +162,7 @@
- Depthlimit 1 (in cm) + Depthlimit 1 [m]
- Depthlimit 2 ( in cm) + Depthlimit 2 [m]
- Widthlimit 1 + Widthlimit 1 [m] - Widthlimit 2 + Widthlimit 2 [m] x).join(", "); - const upperBound = [d[1], w[1]].filter(x => x).join(", "); + const d = [this.depthlimit1D, this.depthlimit2D].sort(); + const w = [this.widthlimit1D, this.widthlimit2D].sort(); + const lowerBound = [d[0] / 100, w[0]].filter(x => x).join(", "); + const upperBound = [d[1] / 100, w[1]].filter(x => x).join(", "); let result; - if (this.depthlimit1 !== this.depthlimit2) { + if (this.depthlimit1D !== this.depthlimit2D) { result = [ `> LDC`, - `< ${lowerBound}`, - `< ${upperBound}`, - `>= ${upperBound}` + `< ${lowerBound} [m]`, + `< ${upperBound} [m]`, + `>= ${upperBound} [m]` ]; } else { - result = [`> LDC`, `< ${upperBound}`, `>= ${upperBound}`]; + result = [`> LDC`, `< ${upperBound} [m]`, `>= ${upperBound} [m]`]; } return result; }, @@ -196,34 +204,40 @@ return `data:text/csv;charset=utf-8, ${encodeURIComponent(this.csv)}`; }, csvFileName() { + if (!this.frequencyD) return; return `${this.$gettext("fairwayavailabilityLNWL")}-${ this.featureName }-${filters.surveyDate(this.fromDate)}-${filters.surveyDate( this.toDate - )}-${this.$gettext(this.frequency)}-.csv`; - }, - fromDate() { - return this.from; - }, - toDate() { - return this.to; + )}-${this.$gettext(this.frequencyD)}-.csv`; }, availability() { return this.plainAvailability; }, title() { + if (!this.frequencyD) return; return `Available Fairway Depth vs LNWL: ${ this.featureName } (${filters.surveyDate(this.fromDate)} - ${filters.surveyDate( this.toDate - )}) ${this.$gettext(this.frequency)}`; + )}) ${this.$gettext(this.frequencyD)}`; }, featureName() { - if (this.selectedFairwayAvailabilityFeature == null) return ""; - return this.selectedFairwayAvailabilityFeature.properties.name; + if (this.selectedFairwayAvailabilityFeatureD == null) return ""; + return this.selectedFairwayAvailabilityFeatureD.properties.name; } }, methods: { + initDiagramValues() { + this.selectedFairwayAvailabilityFeatureD = this.selectedFairwayAvailabilityFeature; + this.fromDate = this.from; + this.toDate = this.to; + this.depthlimit1D = this.depthlimit1; + this.depthlimit2D = this.depthlimit2; + this.widthlimit1D = this.widthlimit1; + this.widthlimit2D = this.widthlimit2; + this.frequencyD = this.frequency; + }, legendStyle(index) { let style; if (this.depthlimit1 !== this.depthlimit2) { @@ -645,6 +659,7 @@ }, watch: { fwLNWLData() { + this.initDiagramValues(); this.drawDiagram(); }, showNumbers() { diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/fairway/BottleneckDialogue.vue --- a/client/src/components/fairway/BottleneckDialogue.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/fairway/BottleneckDialogue.vue Fri Sep 20 15:35:16 2019 +0200 @@ -306,7 +306,6 @@ import { displayError, displayInfo } from "@/lib/errors"; import { HTTP } from "@/lib/http"; import { COMPARESURVEYS } from "@/components/paneSetups"; -import lib from "@/lib/filters"; export default { name: "profiles", @@ -634,29 +633,31 @@ }); }, deleteSelectedSurvey() { - const surveyText = `${this.selectedBottleneck}: ${lib.surveyDate( - this.selectedSurvey.date_info - )}`; - this.$store.commit("application/popup", { - icon: "trash", - title: this.$gettext("Delete survey"), - content: - `` + - this.$gettext("Do you really want to delete the survey:") + - `
- ${surveyText}
`, - confirm: { - label: this.$gettext("Delete"), - icon: "trash", - callback: () => { - displayInfo({ title: this.$gettext("Not implemented") }); - } + HTTP.post( + "/imports/dsr", + { + "bottleneck-id": this.selectedSurvey.bottleneck_id, + "date-info": this.selectedSurvey.date_info }, - cancel: { - label: this.$gettext("Cancel"), - icon: "times" + { + headers: { "X-Gemma-Auth": localStorage.getItem("token") } } - }); + ) + .then(() => { + displayInfo({ + title: this.$gettext("Survey"), + message: + this.$gettext("Deleting ") + + `${this.selectedBottleneck}: ${this.selectedSurvey.date_info}` + }); + }) + .catch(error => { + const { status, data } = error.response; + displayError({ + title: this.$gettext("Backend Error"), + message: `${status}: ${data.message || data}` + }); + }); }, deleteSelectedCut(cut) { this.$store.commit("application/popup", { diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/gauge/Gauges.vue --- a/client/src/components/gauge/Gauges.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/gauge/Gauges.vue Fri Sep 20 15:35:16 2019 +0200 @@ -109,6 +109,7 @@ * Author(s): * Markus Kottländer */ +/*eslint no-unused-vars: ["error", { "varsIgnorePattern": "_" }]*/ import { mapState, mapGetters } from "vuex"; import { displayError } from "@/lib/errors"; @@ -245,17 +246,24 @@ return `${gauge.properties.objname} (${this.isrsInfo(gauge).orc})`; }, isrsInfo(gauge) { - let isrsInfo = gauge.id - .split(".")[1] - .replace(/[()]/g, "") - .split(","); + // See https://www.elwis.de/DE/Service/Daten-und-Fakten/RIS-Index/RIS-Index-node.html + const [ + _, + countryCode, + loCode, + fairwaySection, + orc, + hectometre + ] = gauge.properties.isrs_code.match( + /(\w{2})(\w{3})(\w{5})(\w{5})(\w{5})/ + ); return { - countryCode: isrsInfo[0], - loCode: isrsInfo[1], - fairwaySection: isrsInfo[2], - orc: isrsInfo[3], - hectometre: isrsInfo[4] + countryCode: countryCode, + loCode: loCode, + fairwaySection: fairwaySection, + orc: orc, + hectometre: hectometre }; } }, diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/gauge/HydrologicalConditions.vue --- a/client/src/components/gauge/HydrologicalConditions.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/gauge/HydrologicalConditions.vue Fri Sep 20 15:35:16 2019 +0200 @@ -12,7 +12,7 @@ - {{ yearCompare }} + {{ yearCompareD }}
{ return d.date.getTime() === y.date.getTime(); }); - d[this.yearCompare] = yearData ? yearData.mean : ""; + d[this.yearCompareD] = yearData ? yearData.mean : ""; return `${d.date.getMonth() + 1}-${d.date.getDate()};${d.min};${ d.max - };${d.mean};${d.median};${d.q25};${d.q75};${d[this.yearCompare]}`; + };${d.mean};${d.median};${d.q25};${d.q75};${d[this.yearCompareD]}`; }) .join("\n"); - return `#Interval: ${this.longtermInterval.join( + return `#Interval: ${this.longtermIntervalD.join( " - " )}\n#date;#min;#max;#mean;#median;#q25;#q75;#${ - this.yearCompare + this.yearCompareD }\n${merged}`; } }, watch: { paneSetup() { - this.$nextTick(() => this.drawDiagram()); + this.$nextTick(() => { + this.initialDiagramValues(); + this.drawDiagram(); + }); }, longtermWaterlevels() { + this.initialDiagramValues(); this.drawDiagram(); }, yearWaterlevels() { + this.initialDiagramValues(); this.drawDiagram(); } }, methods: { + initialDiagramValues() { + this.selectedGaugeD = this.selectedGauge; + this.longtermIntervalD = this.longtermInterval; + this.yearCompareD = this.yearCompare; + }, close() { this.$store.commit( "application/paneSetup", @@ -200,9 +216,9 @@ }, downloadPDF() { let diagramTitle = - this.gaugeInfo(this.selectedGauge) + + this.gaugeInfo(this.selectedGaugeD) + ": Hydrological Conditions " + - this.longtermInterval.join(" - "); + this.longtermIntervalD.join(" - "); this.generatePDF({ templateData: this.templateData, @@ -210,7 +226,7 @@ }); this.pdf.doc.save( - this.selectedGauge.properties.objname + + this.selectedGaugeD.properties.objname + " Hydrological-condition Diagram.pdf" ); }, @@ -242,6 +258,7 @@ }, // Diagram legend addDiagramLegend(position, offset, color) { + if (!this.yearCompareD) return; let x = offset.x + 2, // 2 is the radius of the circle y = offset.y, padding = 3; @@ -263,7 +280,7 @@ this.pdf.doc.setDrawColor("white"); this.pdf.doc.setFillColor("red"); this.pdf.doc.circle(x, y, 2, "FD"); - this.pdf.doc.text(x + padding, y + 1, "" + this.yearCompare); + this.pdf.doc.text(x + padding, y + 1, "" + this.yearCompareD); this.pdf.doc.setFillColor("orange"); this.pdf.doc.circle(x, y + 5, 2, "FD"); this.pdf.doc.text(x + padding, y + 6, "Q25%"); @@ -297,7 +314,7 @@ // remove old diagram d3.select("#" + this.containerId + " svg").remove(); const el = document.querySelector("#" + this.containerId); - if (!this.selectedGauge || !this.longtermWaterlevels.length || !el) + if (!this.selectedGaugeD || !this.longtermWaterlevels.length || !el) return; const svgWidth = el.clientWidth; const svgHeight = el.clientHeight; @@ -316,7 +333,7 @@ // HDC/LDC/MW for the selected gauge const refWaterLevels = JSON.parse( - this.selectedGauge.properties.reference_water_levels + this.selectedGaugeD.properties.reference_water_levels ); // dimensions (widths, heights, margins) @@ -962,6 +979,7 @@ ywl => ywl.date.getTime() === d.date.getTime() ); if (dYear) { + if (!this.yearCompareD) return; tooltipText .append("tspan") .attr("x", 0) @@ -969,7 +987,7 @@ .attr("dy", "7.4em") .attr("dominant-baseline", "hanging") .attr("text-anchor", "middle") - .text(`${this.yearCompare}: ${dYear.mean.toFixed(1)} cm`); + .text(`${this.yearCompareD}: ${dYear.mean.toFixed(1)} cm`); } // get text dimensions @@ -1016,7 +1034,7 @@ // not guarantee that the DOM is not only updated but also re-painted on the // screen. setTimeout(this.drawDiagram, 150); - + this.initialDiagramValues(); this.templates[0] = this.defaultTemplate; this.form.template = this.templates[0]; this.templateData = this.form.template; diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/gauge/Waterlevel.vue --- a/client/src/components/gauge/Waterlevel.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/gauge/Waterlevel.vue Fri Sep 20 15:35:16 2019 +0200 @@ -70,6 +70,17 @@ -->
+
+ +
this.drawDiagram()); }, waterlevels() { + this.initialDiagramValues(); this.drawDiagram(); } }, methods: { + initialDiagramValues() { + this.dateFromD = this.dateFrom; + this.dateToD = this.dateTo; + this.selectedGaugeD = this.selectedGauge; + }, close() { this.$store.commit( "application/paneSetup", @@ -206,9 +225,9 @@ let diagramTitle = this.gaugeInfo(this.selectedGauge) + ": Waterlevel " + - this.dateFrom.toLocaleDateString() + + this.dateFromD.toLocaleDateString() + " - " + - this.dateTo.toLocaleDateString(); + this.dateToD.toLocaleDateString(); this.generatePDF({ templateData: this.templateData, diagramTitle: diagramTitle @@ -291,7 +310,7 @@ } }; }, - drawDiagram() { + drawDiagram(zoom) { // remove old diagram and exit if necessary data is missing d3.select("#" + this.containerId + " svg").remove(); const elem = document.querySelector("#" + this.containerId); @@ -305,7 +324,8 @@ svgWidth: svgWidth, svgHeight: svgHeight, ...layout - }) + }), + zoomLevel: zoom ? zoom : null }); }, renderTo({ element, dimensions, zoomLevel }) { @@ -398,16 +418,17 @@ // static, don't need updater this.drawNavigationChart({ scale, navigation }); this.drawRefLines({ refWaterLevels, diagram, scale, dimensions, extent }); - - updaters.push( - this.drawNashSutcliffe({ hours: 72, diagram, scale, dimensions }) - ); - updaters.push( - this.drawNashSutcliffe({ hours: 48, diagram, scale, dimensions }) - ); - updaters.push( - this.drawNashSutcliffe({ hours: 24, diagram, scale, dimensions }) - ); + if (this.showNSC) { + updaters.push( + this.drawNashSutcliffe({ hours: 72, diagram, scale, dimensions }) + ); + updaters.push( + this.drawNashSutcliffe({ hours: 48, diagram, scale, dimensions }) + ); + updaters.push( + this.drawNashSutcliffe({ hours: 24, diagram, scale, dimensions }) + ); + } // INTERACTIONS @@ -955,14 +976,19 @@ .call(brush.move, scale.x.range().map(t.invertX, t)); }; zoom.on("zoom", () => { - if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") + if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") { return; // ignore zoom-by-brush + } let t = d3.event.transform; + // set the zoom to the passed zoom level. if (zoomLevel) { - const tx = (zoomLevel.x * dimensions.width) / zoomLevel.width; - const k = zoomLevel.k; - const ty = zoomLevel.y; + let tx = (zoomLevel.x * dimensions.width) / zoomLevel.width; + let k = zoomLevel.k; + let ty = zoomLevel.y; t = d3.zoomIdentity.translate(tx, ty).scale(k); + zoomLevel = null; // avoid to stuck at same zoom level after setting the zoom by subsequent zooming. + } else { + temp = { ...d3.event.transform, width: dimensions.width }; } scaleForZoom(t); }); @@ -971,11 +997,13 @@ svg.select(".chart-tooltip").style("opacity", 0); }); // store the zoom level after zomming is ended - if (!zoomLevel) { - zoom.on("end", () => { - this.zoomStore = { ...d3.event.transform, width: dimensions.width }; - }); - } + zoom.on("end", () => { + if (!zoomLevel) { + this.zoomStore = temp + ? temp + : { ...d3.event.transform, width: dimensions.width }; + } + }); navigation .append("g") @@ -1154,7 +1182,7 @@ // not guarantee that the DOM is not only updated but also re-painted on the // screen. setTimeout(this.drawDiagram, 150); - + this.initialDiagramValues(); this.templates[0] = this.defaultTemplate; this.form.template = this.templates[0]; this.templateData = this.form.template; diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/identify/Identify.vue --- a/client/src/components/identify/Identify.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/identify/Identify.vue Fri Sep 20 15:35:16 2019 +0200 @@ -5,7 +5,7 @@ { expanded: showIdentify } ]" > -
+
+ + Meta: + +
+
+
-
+
- - {{ recency(feature) }} - +
+ + {{ line }} + +
According gauge data: @@ -62,7 +77,7 @@
@@ -87,11 +102,17 @@ }" />
- - {{ gmAvailability(feature) }} - +
+ + {{ line }} + +
-
+
- - {{ getGaugeStatusText(feature) }} - +
+ + {{ line }} + +
-
+
- - {{ forecastAccuracy(feature) }} - +
+ + {{ line }} + +
+
${nsc24} /24h ${coeffWarn} >${nsc72} / 72h)`, - WARNING: - this.$gettext("Nash-Sutcliffe") + ` (${coeffWarn} < ${nsc72} / 72h)`, - DANGER: - this.$gettext("Nash-Sutcliffe") + - ` (${coeffDanger} < ${nsc24} / 72h)`, - NEUTRAL: this.$gettext("Nash-Sutcliffe not available") + `(${coeffDanger} >${nsc24} /24h ${coeffWarn} >${nsc72} / 72h)` + ], + WARNING: [ + this.$gettext("Nash-Sutcliffe") + ` (${coeffWarn} < ${nsc72} / 72h)` + ], + DANGER: [ + this.$gettext("Nash-Sutcliffe") + ` (${coeffDanger} < ${nsc24} / 72h)` + ], + NEUTRAL: [this.$gettext("Nash-Sutcliffe not available")] }; return messagesPerState[this.gaugeStatus]; }, @@ -283,22 +331,30 @@ return forecastVsRealityColorCodes[this.refGaugeStatus]; }, refGaugeStatusText() { - const nsc24 = this.config.gm_forecast_vs_reality_nsc_24h; - const nsc72 = this.config.gm_forecast_vs_reality_nsc_72h; - const coeffWarn = this.refGaugeCoeffs ? this.refGaugeCoeffs[2].value : ""; + const nsc24 = Number(this.config.gm_forecast_vs_reality_nsc_24h).toFixed( + 2 + ); + const nsc72 = Number(this.config.gm_forecast_vs_reality_nsc_72h).toFixed( + 2 + ); + const coeffWarn = this.refGaugeCoeffs + ? Number(this.refGaugeCoeffs[2].value).toFixed(2) + : ""; const coeffDanger = this.refGaugeCoeffs - ? this.refGaugeCoeffs[0].value + ? Number(this.refGaugeCoeffs[0].value).toFixed(2) : ""; const messagesPerState = { - OK: + OK: [ this.$gettext("Nash-Sutcliffe") + - `(${coeffDanger} >${nsc24} /24h ${coeffWarn} >${nsc72} / 72h)`, - WARNING: - this.$gettext("Nash-Sutcliffe") + ` (${coeffWarn} < ${nsc72} / 72h)`, - DANGER: - this.$gettext("Nash-Sutcliffe") + - ` (${coeffDanger} < ${nsc24} / 72h)`, - NEUTRAL: this.$gettext("Nash-Sutcliffe not available") + `(${coeffDanger} >${nsc24} /24h ${coeffWarn} >${nsc72} / 72h)` + ], + WARNING: [ + this.$gettext("Nash-Sutcliffe") + ` (${coeffWarn} < ${nsc72} / 72h)` + ], + DANGER: [ + this.$gettext("Nash-Sutcliffe") + ` (${coeffDanger} < ${nsc24} / 72h)` + ], + NEUTRAL: [this.$gettext("Nash-Sutcliffe not available")] }; return messagesPerState[this.refGaugeStatus]; } @@ -350,18 +406,31 @@ gmAvailability(feature) { const latestInHours = this.config.gm_latest_hours; const measurementsIn14D = this.config.gm_min_values_14d; + const gauge = classifications.getGauge(feature); + const lastMeasureDate = filters.surveyDate(gauge.get("gm_measuredate")); + const in14Days = gauge.get("gm_n_14d"); const messagesPerState = { - OK: - this.$gettext("Avail: Last measurement <") + - ` ${latestInHours} (${measurementsIn14D} in 14d)`, - WARNING: - this.$gettext("Avail: Below treshold") + - `: ${measurementsIn14D} in 14d`, - DANGER: + OK: [ + this.$gettext("Avail: Latest measurement from") + + `${lastMeasureDate}`, + this.$gettext("Measurement is within") + ` ${latestInHours}h`, + `${in14Days} / ${measurementsIn14D} ${this.$gettext( + "measurements" + )} in 14d` + ], + WARNING: [ + this.$gettext("Avail: Below treshold"), + `${in14Days} / ${measurementsIn14D} ${this.$gettext( + "measurements" + )} in 14d` + ], + DANGER: [ this.$gettext("Avail: Latest measurement older than") + - ` ${latestInHours} d` + ` ${latestInHours} d`, + `(${lastMeasureDate})` + ] }; - return messagesPerState[[classifications.gmAvailability(feature)]]; + return messagesPerState[classifications.gmAvailability(feature)]; }, gmAvailabilityColor(feature) { return gmAvailabilityColorCodes[classifications.gmAvailability(feature)]; @@ -372,16 +441,20 @@ const fa3d = feature.get("forecast_accuracy_3d"); const fa1d = feature.get("forecast_accuracy_1d"); const messagesPerState = { - OK: - this.$gettext("Highest confidence") + - ` <${offset24} cm/24h, <${offset72} cm/72h`, - WARNING: - this.$gettext("Confidence per 72h") + - ` (${fa3d} cm > ${offset72} cm)`, - DANGER: + OK: [ + this.$gettext("Highest confidence"), + `${fa1d} < ${offset24} cm/24h`, + `${fa3d} < ${offset72} cm/72h` + ], + WARNING: [ + this.$gettext("Confidence per 72h") + ` (${fa3d} cm > ${offset72} cm)` + ], + DANGER: [ this.$gettext("Confidence per 24h") + ` (${fa1d} cm > ${offset24} cm)` + ], + NEUTRAL: [this.$gettext("Predictions not available")] }; - return messagesPerState[[classifications.forecastAccuracy(feature)]]; + return messagesPerState[classifications.forecastAccuracy(feature)]; }, forecastAccuracyColor(feature) { return forecastAccuracyColorCodes[ @@ -391,16 +464,26 @@ recency(feature) { const revisitingFactor = this.config.bn_revtime_multiplier; const revisitingTime = feature.get("revisiting_time"); + if (!revisitingTime) return [this.$gettext("No revisiting time defined")]; + const latest = feature.get("date_max"); + if (!latest) return [this.$gettext("No survey-data available")]; + const latestMeasurement = filters.surveyDate(new Date(latest)); const messagesPerState = { - OK: + OK: [ this.$gettext("Data within the revisiting time") + - ` (${revisitingTime}d)`, - WARNING: + ` (${revisitingTime} mth)`, + `${this.$gettext("Latest measurement")} ${latestMeasurement}` + ], + WARNING: [ this.$gettext("Data within revisiting treshold") + - ` (${revisitingTime} * ${revisitingFactor})`, - DANGER: + ` (${revisitingFactor} * ${revisitingTime})`, + `${this.$gettext("Latest measurement")} ${latestMeasurement}` + ], + DANGER: [ this.$gettext("Data too old. Treshold:") + - ` (${revisitingTime}d * ${revisitingFactor})` + ` (${revisitingFactor} * ${revisitingTime}mth)`, + `${this.$gettext("Latest measurement")} ${latestMeasurement}` + ] }; return messagesPerState[classifications.surveyRecency(feature)]; }, diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/importconfiguration/ScheduledImports.vue --- a/client/src/components/importconfiguration/ScheduledImports.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/importconfiguration/ScheduledImports.vue Fri Sep 20 15:35:16 2019 +0200 @@ -718,7 +718,7 @@ this.maxWidth = value; }, setDepth(value) { - this.depth = value; + this.depth = parseInt(value * 100); }, setSourceOrganization(value) { this.sourceOrganization = value; diff -r ae840f9eb4c8 -r 0f2c3cb139cc client/src/components/importconfiguration/types/Fairwaydimensions.vue --- a/client/src/components/importconfiguration/types/Fairwaydimensions.vue Mon Sep 16 16:56:11 2019 +0200 +++ b/client/src/components/importconfiguration/types/Fairwaydimensions.vue Fri Sep 20 15:35:16 2019 +0200 @@ -91,9 +91,10 @@ @input="depthChanged" class="depth form-control form-control-sm" type="number" - :value="depth" + :value="depthInMeter" + step="0.1" /> -
cm
+
m
-
Fairwaydimension
+
+
+ Fairwaydimensions +
+ +