view client/src/components/gauge/Gauges.vue @ 3044:c71373594719

client: map: prepared store to hold multiple map objects This will be necessary to sync maps, toggle layers per map, etc. Therefore the methods to move the map (moveToExtent, etc.) became actions instead of mutations.
author Markus Kottlaender <markus@intevation.de>
date Sat, 13 Apr 2019 16:02:06 +0200
parents 1b8bb4f89227
children 1ef2f4179d30
line wrap: on
line source

<template>
  <div
    :class="[
      'box ui-element rounded bg-white text-nowrap',
      { expanded: showGauges }
    ]"
  >
    <div style="width: 18rem">
      <UIBoxHeader
        icon="ruler-vertical"
        :title="gaugesLabel"
        :closeCallback="close"
      />
      <div class="box-body">
        <UISpinnerOverlay v-if="loading" />
        <select
          @change="moveToGauge"
          v-model="selectedGaugeISRS"
          class="form-control font-weight-bold"
        >
          <option :value="null">
            <translate>Select Gauge</translate>
          </option>
          <optgroup
            v-for="(gaugesForCountry, cc) in orderedGauges"
            :key="cc"
            :label="cc"
          >
            <option
              v-for="g in gaugesForCountry"
              :key="g.properties.isrs_code"
              :value="g.properties.isrs_code"
            >
              {{ gaugeLabel(g) }}
            </option>
          </optgroup>
        </select>
        <div v-if="selectedGaugeISRS" class="mt-2">
          <hr class="mb-1" />
          <div class="row no-gutters mb-2">
            <div class="col-6 pr-1">
              <small class="text-muted"><translate>From</translate>:</small>
              <input
                type="date"
                class="form-control form-control-sm small"
                :value="dateFrom && dateFrom.toISOString().split('T')[0]"
                @input="dateFrom = $event.target.valueAsDate"
              />
            </div>
            <div class="col-6 pl-1">
              <small class="text-muted"><translate>To</translate>:</small>
              <input
                type="date"
                class="form-control form-control-sm small"
                :value="dateTo && dateTo.toISOString().split('T')[0]"
                @input="dateTo = $event.target.valueAsDate"
              />
            </div>
          </div>
          <button
            @click="showWaterlevelDiagram()"
            class="btn btn-sm btn-info d-block w-100"
          >
            <translate>Show Waterlevels</translate>
          </button>
          <hr class="mb-1" />
          <div class="row no-gutters mb-2">
            <small class="text-muted">
              <translate>Compare to</translate>:
            </small>
            <input
              type="number"
              step="1"
              min="1900"
              :max="new Date().getFullYear()"
              class="form-control form-control-sm small"
              v-model="yearCompare"
            />
          </div>
          <button
            @click="showHydrologicalConditionsDiagram()"
            class="btn btn-sm btn-info d-block w-100 mt-2"
          >
            <translate>Show Hydrological Conditions</translate>
          </button>
        </div>
      </div>
    </div>
  </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, mapGetters } from "vuex";
import { displayError } from "@/lib/errors";

export default {
  data() {
    return {
      loading: false
    };
  },
  computed: {
    ...mapState("application", ["showGauges", "activeSplitscreenId"]),
    ...mapState("gauges", ["gauges", "longtermInterval"]),
    ...mapGetters("gauges", ["selectedGauge"]),
    gaugesLabel() {
      return this.$gettext("Gauges");
    },
    orderedGauges() {
      let orderedGauges = {};
      this.gauges.forEach(g => {
        let isrsInfo = this.isrsInfo(g);
        if (orderedGauges.hasOwnProperty(isrsInfo.countryCode)) {
          orderedGauges[isrsInfo.countryCode].push(g);
        } else {
          orderedGauges[isrsInfo.countryCode] = [g];
        }
      });
      return orderedGauges;
    },
    selectedGaugeISRS: {
      get() {
        return this.$store.state.gauges.selectedGaugeISRS;
      },
      set(isrs) {
        this.$store.dispatch("gauges/selectedGaugeISRS", isrs);
      }
    },
    dateFrom: {
      get() {
        return this.$store.state.gauges.dateFrom;
      },
      set(date) {
        this.$store.commit("gauges/dateFrom", date);
      }
    },
    dateTo: {
      get() {
        return this.$store.state.gauges.dateTo;
      },
      set(date) {
        this.$store.commit("gauges/dateTo", date);
      }
    },
    yearCompare: {
      get() {
        return this.$store.state.gauges.yearCompare;
      },
      set(year) {
        this.$store.commit("gauges/yearCompare", year);
      }
    }
  },
  watch: {
    selectedGaugeISRS() {
      if (this.activeSplitscreenId === "gauge-waterlevel") {
        this.showWaterlevelDiagram();
      }
      if (this.activeSplitscreenId === "gauge-hydrological-conditions") {
        this.showHydrologicalConditionsDiagram();
      }
    }
  },
  methods: {
    close() {
      this.$store.commit("application/showGauges", false);
    },
    moveToGauge() {
      if (!this.selectedGauge) return;
      this.$store.dispatch("map/moveToExtent", {
        feature: this.selectedGauge,
        zoom: null,
        preventZoomOut: true
      });
    },
    showWaterlevelDiagram() {
      // for panning the map to the gauge on opening the diagram: needs to be
      // set outside of the expandCallback to not always refer to the currently
      // selectedGauge
      let coordinates = this.selectedGauge.geometry.coordinates;

      // configure splitscreen
      let splitscreenConf = {
        id: "gauge-waterlevel",
        component: "waterlevel",
        title: `${this.gaugeLabel(this.selectedGauge)}: ${this.$gettext(
          "Waterlevel"
        )} ${this.dateFrom.toLocaleDateString()} - ${this.dateTo.toLocaleDateString()}`,
        icon: "ruler-vertical",
        closeCallback: () => {
          this.$store.commit("gauges/selectedGaugeISRS", null);
          this.$store.commit("gauges/waterlevels", []);
        },
        expandCallback: () => {
          this.$store.dispatch("map/moveMap", {
            coordinates,
            zoom: null,
            preventZoomOut: true
          });
        }
      };
      this.$store.commit("application/addSplitscreen", splitscreenConf);
      this.$store.commit("application/activeSplitscreenId", splitscreenConf.id);
      this.$store.commit("application/splitscreenLoading", true);
      this.loading = true;
      this.$store.commit("application/showSplitscreen", true);

      Promise.all([
        this.$store.dispatch("gauges/loadWaterlevels"),
        this.$store.dispatch("gauges/loadNashSutcliffe")
      ])
        .catch(error => {
          const { status, data } = error.response;
          displayError({
            title: "Backend Error",
            message: `${status}: ${data.message || data}`
          });
        })
        .finally(() => {
          this.$store.commit("application/splitscreenLoading", false);
          this.loading = false;
        });
    },
    showHydrologicalConditionsDiagram() {
      // for panning the map to the gauge on opening the diagram: needs to be
      // set outside of the expandCallback to not always refer to the currently
      // selectedGauge
      let coordinates = this.selectedGauge.geometry.coordinates;

      // configure splitscreen
      let splitscreenConf = {
        id: "gauge-hydrological-conditions",
        component: "hydrological-conditions",
        title: `${this.gaugeLabel(this.selectedGauge)}: ${this.$gettext(
          "Hydrological Conditions"
        )}`,
        icon: "ruler-vertical",
        closeCallback: () => {
          this.$store.commit("gauges/selectedGaugeISRS", null);
          this.$store.commit("gauges/longtermWaterlevels", []);
          this.$store.commit("gauges/yearWaterlevels", []);
        },
        expandCallback: () => {
          this.$store.dispatch("map/moveMap", {
            coordinates,
            zoom: null,
            preventZoomOut: true
          });
        }
      };
      this.$store.commit("application/addSplitscreen", splitscreenConf);
      this.$store.commit("application/activeSplitscreenId", splitscreenConf.id);
      this.$store.commit("application/splitscreenLoading", true);
      this.loading = true;
      this.$store.commit("application/showSplitscreen", true);

      Promise.all([
        this.$store.dispatch("gauges/loadLongtermWaterlevels"),
        this.$store.dispatch("gauges/loadYearWaterlevels")
      ])
        .then(() => {
          splitscreenConf.title = `${
            splitscreenConf.title
          } ${this.longtermInterval.join(" - ")}`;
          this.$store.commit("application/addSplitscreen", splitscreenConf);
        })
        .catch(error => {
          const { status, data } = error.response;
          displayError({
            title: "Backend Error",
            message: `${status}: ${data.message || data}`
          });
        })
        .finally(() => {
          this.$store.commit("application/splitscreenLoading", false);
          this.loading = false;
        });
    },
    gaugeLabel(gauge) {
      return `${gauge.properties.objname} (${this.isrsInfo(gauge).orc})`;
    },
    isrsInfo(gauge) {
      let isrsInfo = gauge.id
        .split(".")[1]
        .replace(/[()]/g, "")
        .split(",");

      return {
        countryCode: isrsInfo[0],
        loCode: isrsInfo[1],
        fairwaySection: isrsInfo[2],
        orc: isrsInfo[3],
        hectometre: isrsInfo[4]
      };
    }
  },
  mounted() {
    this.$store.dispatch("gauges/loadGauges");
  }
};
</script>