Mercurial > gemma
changeset 3538:5be5b54336ea password
merge with default
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Fri, 31 May 2019 09:33:38 +0200 |
parents | c64c47ff2ab1 (current diff) cbf883596e4e (diff) |
children | 60f48bc1498a |
files | |
diffstat | 13 files changed, 172 insertions(+), 152 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/fairway/Fairwayprofile.vue Wed May 29 09:56:42 2019 +0200 +++ b/client/src/components/fairway/Fairwayprofile.vue Fri May 31 09:33:38 2019 +0200 @@ -17,9 +17,15 @@ </div> <div class="legend"> <span - style="background-color: #4a2f06; width: 20px; height: 20px;" + style="width: 14px; height: 14px; background-color: #4a2f06; border: solid 3px black; background-clip: padding-box; box-sizing: content-box;" ></span> - Ground + Sediment + </div> + <div class="legend"> + <span + style="width: 14px; height: 14px; background-color: rgba(74, 47, 6, 0.6); border: solid 3px #943007; background-clip: padding-box; box-sizing: content-box;" + ></span> + Sediment (Compare) </div> <div> <select @@ -96,9 +102,9 @@ height: null, margin: { top: 20, - right: 40, - bottom: 30, - left: 40 + right: 80, + bottom: 60, + left: 80 }, form: { template: null @@ -141,6 +147,7 @@ }; }, computed: { + ...mapGetters("map", ["openLayersMap"]), ...mapGetters("fairwayprofile", ["totalLength"]), ...mapState("fairwayprofile", [ "additionalSurvey", @@ -149,32 +156,21 @@ "endPoint", "fairwayData", "maxAlt", - "referenceWaterLevel", - "selectedWaterLevel", - "waterLevels" + "selectedWaterLevel" ]), + ...mapState("bottlenecks", ["selectedSurvey", "selectedBottleneck"]), ...mapState("application", ["paneSetup"]), title() { let dates = [this.selectedSurvey.date_info]; + let waterlevelLabel = + this.selectedWaterLevel === "ref" + ? this.selectedSurvey.depth_reference + : "Current"; if (this.additionalSurvey) dates.push(this.additionalSurvey.date_info); dates.map(d => this.$options.filters.dateTime(d, true)); return `${this.$gettext("Fairwayprofile")}: ${ this.selectedBottleneck - } (${dates.join(", ")})`; - }, - selectedSurvey: { - get() { - return this.$store.state.bottlenecks.selectedSurvey; - } - }, - selectedBottleneck: { - get() { - return this.$store.state.bottlenecks.selectedBottleneck; - } - }, - ...mapState("bottlenecks", ["selectedSurvey"]), - relativeWaterLevelDelta() { - return this.selectedWaterLevel.value - this.referenceWaterLevel; + } (${dates.join(", ")}) WL: ${waterlevelLabel} (${this.waterlevel} cm)`; }, currentData() { if ( @@ -192,15 +188,20 @@ return []; return this.currentProfile[this.additionalSurvey.date_info].points; }, - xScale() { - return [0, this.totalLength]; + bottleneck() { + return this.openLayersMap() + .getLayer("BOTTLENECKS") + .getSource() + .getFeatures() + .find(f => f.get("objnam") === this.selectedBottleneck); }, - yScaleRight() { - //ToDO calcReleativeDepth(this.maxAlt) to get the - // maximum depth according to the actual waterlevel - // additionally: take the one which is higher reference or current waterlevel - const DELTA = this.maxAlt * 1.1 - this.maxAlt; - return [this.maxAlt * 1 + DELTA, -DELTA]; + waterlevel() { + return this.selectedWaterLevel === "ref" + ? this.refWaterlevel + : this.bottleneck.get("gm_waterlevel"); + }, + refWaterlevel() { + return this.selectedSurvey.waterlevel_value; } }, watch: { @@ -371,7 +372,7 @@ } }); } - this.pdf.doc.save("Fairwayprofile diagram"); + this.pdf.doc.save(this.title.replace(/\s/g, "_").replace(/[():,]/g, "")); }, addDiagram(position, offset, width, height) { let x = offset.x, @@ -429,36 +430,17 @@ this.pdf.doc.circle(x, y + 10, 2, "FD"); this.pdf.doc.text(x + 3, y + 11, "Ground"); }, - calcRelativeDepth(depth) { - /* takes a depth value and substracts the delta of the relative waterlevel - * say the reference level is above the current level, the ground is nearer, - * thus, the depth is lower. - * - * E.g.: - * - * Reference waterlevel 5m, current 4m => delta = -1m - * If the distance to the ground was 3m from the 5m mark - * it is now only 2m from the current waterlevel. - * - * Vice versa: - * - * If the reference level is 5m and the current 6m => delta = +1m - * The ground is one meter farer away from the current waterlevel - * - */ - return depth - this.relativeWaterLevelDelta; - }, drawDiagram() { d3.select(".diagram-container svg").remove(); this.scaleFairwayProfile(); let svg = d3.select(".diagram-container").append("svg"); svg.attr("width", "100%"); svg.attr("height", "100%"); - const width = this.width - this.margin.right - 1.5 * this.margin.left; - const height = this.height - this.margin.top - 2 * this.margin.bottom; + const width = this.width - this.margin.right - this.margin.left; + const height = this.height - this.margin.top - this.margin.bottom; const currentData = this.currentData; const additionalData = this.additionalData; - const { xScale, yScaleRight, graph } = this.generateCoordinates( + const { xScale, yScaleRight, graph } = this.generateScalesAndGraph( svg, height, width @@ -498,7 +480,6 @@ } for (let data of this.fairwayData) { const [startPoint, endPoint, depth] = data.coordinates[0]; - const style = data.style(); let fairwayArea = d3 .area() .x(function(d) { @@ -513,7 +494,7 @@ .datum([{ x: startPoint, y: depth }, { x: endPoint, y: depth }]) .attr("fill", "#002AFF") .attr("fill-opacity", 0.65) - .attr("stroke", style[0].getStroke().getColor()) + .attr("stroke", "transparent") .attr("d", fairwayArea); } }, @@ -521,14 +502,21 @@ graph .append("text") .attr("transform", ["rotate(-90)"]) - .attr("y", this.width - 70) + .attr("y", this.width - 100) .attr("x", -(this.height - this.margin.top - this.margin.bottom) / 2) - .attr("dy", "1em") .attr("fill", "black") .style("text-anchor", "middle") .text("Depth [m]"); graph .append("text") + .attr("transform", ["rotate(-90)"]) + .attr("y", -50) + .attr("x", -(this.height - this.margin.top - this.margin.bottom) / 2) + .attr("fill", "black") + .style("text-anchor", "middle") + .text("Waterlevel [cm]"); + graph + .append("text") .attr("y", -50) .attr("x", -(height / 4)) .attr("dy", "1em") @@ -540,21 +528,35 @@ ]) .text("Width [m]"); }, - generateCoordinates(svg, height, width) { + generateScalesAndGraph(svg, height, width) { let xScale = d3 .scaleLinear() - .domain(this.xScale) + .domain([0, this.totalLength]) .rangeRound([0, width]); - xScale.ticks(5); - let yScaleRight = d3 .scaleLinear() - .domain(this.yScaleRight) + .domain([ + this.maxAlt * 1.1 + + Math.abs(this.waterlevel - this.refWaterlevel) / 100, + -(this.maxAlt * 0.1) + ]) .rangeRound([height, 0]); - let xAxis = d3.axisBottom(xScale); - let yAxis2 = d3.axisRight(yScaleRight); + let yScaleLeft = d3 + .scaleLinear() + .domain([ + this.waterlevel - + (this.maxAlt * 100 + + Math.abs(this.waterlevel - this.refWaterlevel)), + this.waterlevel + this.maxAlt * 0.1 * 100 + ]) + .rangeRound([height, 0]); + + let xAxis = d3.axisBottom(xScale).ticks(5); + let yAxisRight = d3.axisRight(yScaleRight); + let yAxisLeft = d3.axisLeft(yScaleLeft); + let graph = svg .append("g") .attr( @@ -564,7 +566,7 @@ graph .append("g") .attr("transform", "translate(0," + height + ")") - .call(xAxis.ticks(5)) + .call(xAxis) .selectAll(".tick text") .attr("fill", "black") .select(function() { @@ -575,7 +577,7 @@ graph .append("g") .attr("transform", "translate(" + width + ",0)") - .call(yAxis2) + .call(yAxisRight) .selectAll(".tick text") .attr("fill", "black") .select(function() { @@ -583,6 +585,18 @@ }) .selectAll(".tick line") .attr("stroke", "black"); + graph + .append("g") + .attr("transform", "translate(0 0)") + .call(yAxisLeft) + .selectAll(".tick text") + .attr("fill", "black") + .select(function() { + return this.parentNode; + }) + .selectAll(".tick line") + .attr("stroke", "black"); + graph.selectAll(".domain").attr("stroke", "black"); return { xScale, yScaleRight, graph }; }, @@ -601,7 +615,7 @@ .datum([{ x: 0, y: 0 }, { x: this.totalLength, y: 0 }]) .attr("fill-opacity", 0.65) .attr("fill", WATER_COLOR) - .attr("stroke", WATER_COLOR) + .attr("stroke", "transparent") .attr("d", waterArea); }, drawProfile({ @@ -620,25 +634,27 @@ .x(d => { return xScale(d.x); }) - .y(d => { - return yScaleRight(d.y); - }); + .y(d => + yScaleRight( + d.y + Math.abs(this.waterlevel - this.refWaterlevel) / 100 + ) + ); let profileArea = d3 .area() .x(function(d) { return xScale(d.x); }) .y0(height) - .y1(function(d) { - return yScaleRight(d.y); - }); + .y1(d => + yScaleRight( + d.y + Math.abs(this.waterlevel - this.refWaterlevel) / 100 + ) + ); graph .append("path") .datum(part) .attr("fill", color) - .attr("stroke", color) - .attr("stroke-width", 3) - .attr("stroke-opacity", opacity) + .attr("stroke", "transparent") .attr("fill-opacity", opacity) .attr("d", profileArea); graph
--- a/client/src/components/fairway/Profiles.vue Wed May 29 09:56:42 2019 +0200 +++ b/client/src/components/fairway/Profiles.vue Fri May 31 09:33:38 2019 +0200 @@ -37,7 +37,7 @@ </select> <div v-if="selectedBottleneck"> <div class="d-flex mt-2"> - <div class="flex-fill"> + <div class="flex-fill" style="max-width: 75px;"> <small class="text-muted"> <translate>Waterlevel</translate>: </small> @@ -45,15 +45,11 @@ v-model="selectedWaterLevel" class="form-control form-control-sm small" > - <option value="" v-if="Object.keys(waterLevels).length === 0"> - <translate>Current</translate> + <option value="ref"> + <translate>Depth Reference</translate> </option> - <option - v-for="wl in Object.keys(waterLevels)" - :key="wl" - :value="wl" - > - {{ wl | surveyDate }} + <option value="current"> + <translate>Current Waterlevel</translate> </option> </select> </div> @@ -327,7 +323,7 @@ }, selectedWaterLevel: { get() { - return this.$store.state.fairwayprofile.selectedWaterLevel.date || ""; + return this.$store.state.fairwayprofile.selectedWaterLevel; }, set(value) { this.$store.commit("fairwayprofile/setSelectedWaterLevel", value);
--- a/client/src/components/map/styles.js Wed May 29 09:56:42 2019 +0200 +++ b/client/src/components/map/styles.js Fri May 31 09:33:38 2019 +0200 @@ -247,20 +247,31 @@ geom = new Point(getCenter(feature.getGeometry().getExtent())); } maps.forEach(m => { - let frame = `<polyline points='16,0 32,32 0,32 16,0' stroke='grey' stroke-width='1' fill='white'/>`; - let waterlevel = `<polyline points="16,0 24,16 16,32 8,16 16,0" stroke='grey' stroke-width='1' fill='${colorWaterlevel}'/>`; - let accuracy = `<polyline points="24,16 32,32 16,32 24,16" stroke='grey' stroke-width='1' fill='${colorAccuracy}'/>`; - let comparison = `<polyline points="8,16 16,32 0,32 8,16" stroke='grey' stroke-width='1' fill='${colorComparison}'/>`; - let svg = `data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><g>${frame}${waterlevel}${comparison}${accuracy}</g></svg>`; - s.push( - new Style({ - geometry: geom, - image: new Icon({ - src: svg, - anchor: [-0.5, 1] + if ( + (m.getLayer("BOTTLENECKS").getVisible() && + feature.getId().indexOf("bottlenecks") > -1) || + (m.getLayer("SECTIONS").getVisible() && + feature.getId().indexOf("sections") > -1) || + (m.getLayer("STRETCHES").getVisible() && + feature.getId().indexOf("stretches") > -1) || + (m.getLayer("GAUGES").getVisible() && + feature.getId().indexOf("gauges") > -1) + ) { + let frame = `<polyline points='16,0 32,32 0,32 16,0' stroke='grey' stroke-width='1' fill='white'/>`; + let waterlevel = `<polyline points="16,0 24,16 16,32 8,16 16,0" stroke='grey' stroke-width='1' fill='${colorWaterlevel}'/>`; + let accuracy = `<polyline points="24,16 32,32 16,32 24,16" stroke='grey' stroke-width='1' fill='${colorAccuracy}'/>`; + let comparison = `<polyline points="8,16 16,32 0,32 8,16" stroke='grey' stroke-width='1' fill='${colorComparison}'/>`; + let svg = `data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><g>${frame}${waterlevel}${comparison}${accuracy}</g></svg>`; + s.push( + new Style({ + geometry: geom, + image: new Icon({ + src: svg, + anchor: [-0.5, 1] + }) }) - }) - ); + ); + } if ( m.getLayer("BOTTLENECKS").getVisible() &&
--- a/client/src/store/fairwayprofile.js Wed May 29 09:56:42 2019 +0200 +++ b/client/src/store/fairwayprofile.js Fri May 31 09:33:38 2019 +0200 @@ -28,9 +28,7 @@ minAlt: 0, maxAlt: 0, currentProfile: {}, - referenceWaterLevel: null, - waterLevels: {}, - selectedWaterLevel: "", + selectedWaterLevel: "ref", fairwayData: [], startPoint: null, endPoint: null, @@ -61,7 +59,7 @@ state.additionalSurvey = additionalSurvey; }, setSelectedWaterLevel: (state, level) => { - state.selectedWaterLevel = state.waterLevels[level]; + state.selectedWaterLevel = level; }, setDifferencesLoading: (state, value) => { state.differencesLoading = value; @@ -69,8 +67,6 @@ profileLoaded: (state, answer) => { const { response, surveyDate } = answer; const { data } = response; - const { waterlevel } = response.data.properties; - const { value, when } = waterlevel; const coordinates = data.geometry.coordinates; if (!coordinates) return; const startPoint = state.startPoint; @@ -79,12 +75,6 @@ const result = prepareProfile({ geoJSON, startPoint, endPoint }); // Use Vue.set() to make new object properties rective // https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats - const entry = { - date: when, - value: value - }; - state.waterLevels = { [when]: entry }; - state.selectedWaterLevel = entry; Vue.set(state.currentProfile, surveyDate, { points: result.points, length: result.lengthPolyLine @@ -116,9 +106,7 @@ state.fairwayData = []; state.startPoint = null; state.endPoint = null; - state.referenceWaterLevel = null; - state.waterLevels = {}; - state.selectedWaterLevel = ""; + state.selectedWaterLevel = "ref"; }, previousCuts: (state, previousCuts) => { state.previousCuts = previousCuts;
--- a/pkg/controllers/cross.go Wed May 29 09:56:42 2019 +0200 +++ b/pkg/controllers/cross.go Fri May 31 09:33:38 2019 +0200 @@ -21,7 +21,6 @@ "net/http" "time" - "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/models" "gemma.intevation.de/gemma/pkg/octree" ) @@ -167,13 +166,6 @@ Type: "MultiLineString", Coordinates: joined, }, - Properties: map[string]interface{}{ - "waterlevel": map[string]interface{}{ - // TODO: Fetch values from database. - "value": float64(50), - "when": start.Format(common.TimeFormat), - }, - }, }, }
--- a/pkg/controllers/stretches.go Wed May 29 09:56:42 2019 +0200 +++ b/pkg/controllers/stretches.go Fri May 31 09:33:38 2019 +0200 @@ -418,7 +418,7 @@ return } - from, ok := parseFormTime(rw, req, "form", time.Now().AddDate(-1, 0, 0)) + from, ok := parseFormTime(rw, req, "from", time.Now().AddDate(-1, 0, 0)) if !ok { return }
--- a/pkg/imports/agm.go Wed May 29 09:56:42 2019 +0200 +++ b/pkg/imports/agm.go Fri May 31 09:33:38 2019 +0200 @@ -182,10 +182,12 @@ staging_done ) VALUES ( ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int), - (SELECT validity FROM waterway.gauges - WHERE location - = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) - AND validity @> CAST($6 AS timestamp with time zone)), + COALESCE( + (SELECT validity FROM waterway.gauges + WHERE location + = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) + AND validity @> CAST($6 AS timestamp with time zone)), + tstzrange(NULL, NULL)), $6, $7, $8,
--- a/pkg/imports/bn.go Wed May 29 09:56:42 2019 +0200 +++ b/pkg/imports/bn.go Fri May 31 09:33:38 2019 +0200 @@ -20,6 +20,7 @@ "errors" "regexp" "strconv" + "strings" "time" "gemma.intevation.de/gemma/pkg/soap/ifbn" @@ -63,8 +64,10 @@ ) VALUES ( $1, isrs_fromText($2), - (SELECT validity FROM waterway.gauges - WHERE location = isrs_fromText($2) AND NOT erased), + COALESCE( + (SELECT validity FROM waterway.gauges + WHERE location = isrs_fromText($2) AND NOT erased), + tstzrange(NULL, NULL)), $3, $4, isrsrange(least(isrs_fromText($5), isrs_fromText($6)), @@ -268,10 +271,12 @@ rb, lb := splitRBLB(bn.Rb_lb) var revisitingTime *int - if bn.Revisiting_time != nil { + if bn.Revisiting_time != nil && + len(strings.TrimSpace(*bn.Revisiting_time)) > 0 { i, err := strconv.Atoi(*bn.Revisiting_time) if err != nil { - feedback.Warn("Cannot convert '%s' to number of months", + feedback.Warn( + "Cannot convert given revisiting time '%s' to number of months", *bn.Revisiting_time) } else { revisitingTime = &i
--- a/pkg/imports/errors.go Wed May 29 09:56:42 2019 +0200 +++ b/pkg/imports/errors.go Fri May 31 09:33:38 2019 +0200 @@ -57,10 +57,10 @@ switch err.SchemaName { case "waterway": switch err.TableName { - case "gauge_measurements": + case "gauge_measurements", "gauge_predictions", "bottlenecks": switch err.ConstraintName { case "gauge_key": - return "Referenced gauge is not in database" + return "Referenced gauge with matching temporal validity not available" } } }
--- a/pkg/imports/gm.go Wed May 29 09:56:42 2019 +0200 +++ b/pkg/imports/gm.go Fri May 31 09:33:38 2019 +0200 @@ -73,10 +73,12 @@ staging_done ) VALUES ( ($1, $2, $3, $4, $5), - (SELECT validity FROM waterway.gauges - WHERE location - = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) - AND validity @> CAST($6 AS timestamp with time zone)), + COALESCE( + (SELECT validity FROM waterway.gauges + WHERE location + = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) + AND validity @> CAST($6 AS timestamp with time zone)), + tstzrange(NULL, NULL)), $6, $7, $8, @@ -108,10 +110,12 @@ source_organization ) VALUES( ($1, $2, $3, $4, $5), - (SELECT validity FROM waterway.gauges - WHERE location - = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) - AND validity @> CAST($6 AS timestamp with time zone)), + COALESCE( + (SELECT validity FROM waterway.gauges + WHERE location + = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) + AND validity @> CAST($6 AS timestamp with time zone)), + tstzrange(NULL, NULL)), $6, $7, $8,
--- a/pkg/imports/sr.go Wed May 29 09:56:42 2019 +0200 +++ b/pkg/imports/sr.go Fri May 31 09:33:38 2019 +0200 @@ -164,7 +164,8 @@ selectGaugeLDCSQL = ` SELECT - grwl.value + grwl.value, + grwl.depth_reference FROM waterway.gauges_reference_water_levels grwl JOIN waterway.bottlenecks bns ON grwl.location = bns.gauge_location @@ -208,7 +209,11 @@ if m.DepthReference == "ZPG" { feedback.Info("Found ZPG as reference system -> translating Z values to LDC") var ldc float64 - err := conn.QueryRowContext(ctx, selectGaugeLDCSQL, m.Bottleneck).Scan(&ldc) + var depthReference string + err := conn.QueryRowContext(ctx, selectGaugeLDCSQL, m.Bottleneck).Scan( + &ldc, + &depthReference, + ) switch { case err == sql.ErrNoRows: return nil, errors.New("Cannot load LDC value") @@ -218,7 +223,7 @@ xform = func(v octree.Vertex) octree.Vertex { return octree.Vertex{X: v.X, Y: v.Y, Z: ldc - v.Z} } - m.DepthReference = "LDC" + m.DepthReference = depthReference } if err := m.Validate(ctx, conn); err != nil {
--- a/pkg/imports/wg.go Wed May 29 09:56:42 2019 +0200 +++ b/pkg/imports/wg.go Fri May 31 09:33:38 2019 +0200 @@ -235,10 +235,10 @@ gauges = append(gauges, isrs) feedback.Info("Processing %s", code) - // We need a valid time range to identify gauge versions in DB + // We need a valid, non-empty time range to identify gauge versions if dr.Enddate != nil && dr.Startdate != nil && - time.Time(*dr.Enddate).Before(time.Time(*dr.Startdate)) { - feedback.Warn("End date before start date") + !time.Time(*dr.Enddate).After(time.Time(*dr.Startdate)) { + feedback.Warn("End date not after start date") unchanged++ continue }
--- a/schema/gemma.sql Wed May 29 09:56:42 2019 +0200 +++ b/schema/gemma.sql Fri May 31 09:33:38 2019 +0200 @@ -280,7 +280,7 @@ geom geography(POINT, 4326) NOT NULL, applicability_from_km int8, applicability_to_km int8, - validity tstzrange, + validity tstzrange NOT NULL, zero_point double precision NOT NULL, geodref varchar, date_info timestamp with time zone NOT NULL, @@ -288,6 +288,7 @@ lastupdate timestamp with time zone NOT NULL, -- entry removed from external data source (RIS-Index)/historicised: erased boolean NOT NULL DEFAULT false, + CHECK (erased OR NOT isempty(validity)), PRIMARY KEY (location, validity), EXCLUDE USING GiST (isrs_astext(location) WITH =, validity WITH &&) DEFERRABLE INITIALLY DEFERRED @@ -490,9 +491,9 @@ bottleneck_id varchar UNIQUE NOT NULL, gauge_location isrs NOT NULL, gauge_validity tstzrange NOT NULL, - FOREIGN KEY (gauge_location, gauge_validity) REFERENCES gauges - ON UPDATE CASCADE, - -- XXX: DRC references "ch. 3.1.1", which does not exist in document. + CONSTRAINT gauge_key + FOREIGN KEY (gauge_location, gauge_validity) REFERENCES gauges + ON UPDATE CASCADE, objnam varchar, nobjnm varchar, stretch isrsrange NOT NULL,