Skip to content

Commit

Permalink
Merge pull request #915 from Deltares/908-laat-gebruiker-de-time-rang…
Browse files Browse the repository at this point in the history
…e-starttime-en-endtime-aanpassen

Add ability to set the start and endtime of the graph data
  • Loading branch information
ekkelenkamp authored Jun 18, 2024
2 parents f31c51f + eb03fd1 commit e5dd7da
Show file tree
Hide file tree
Showing 12 changed files with 620 additions and 206 deletions.
446 changes: 426 additions & 20 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"vue-maplibre-gl": "^3.1.3",
"vue-router": "^4.3.0",
"vue-slider-component": "^4.1.0-beta.7",
"vuetify": "^3.5.9"
"vuetify": "^3.6.9"
},
"devDependencies": {
"@mdi/font": "^7.4.47",
Expand All @@ -72,7 +72,7 @@
"prettier": "3.2.5",
"sonarqube-scanner": "^3.3.0",
"typescript": "^5.4.2",
"vite": "^5.1.6",
"vite": "^5.3.1",
"vite-plugin-vuetify": "^2.0.3",
"vitest": "^1.3.1",
"vue-tsc": "^2.0.6"
Expand Down
5 changes: 5 additions & 0 deletions src/components/charts/TimeSeriesChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,11 @@ const refreshChart = () => {
for (const id of removeIds) {
axis.removeChart(id)
}
if (props.config.xAxis) {
axis.setOptions({
x: props.config.xAxis,
})
}
if (props.config.yAxis) {
axis.setOptions({
y: props.config.yAxis,
Expand Down
11 changes: 10 additions & 1 deletion src/components/spatialdisplay/SpatialTimeSeriesDisplay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import {
import { computed } from 'vue'
import TimeSeriesFileDownloadComponent from '@/components/download/TimeSeriesFileDownloadComponent.vue'
import { useUserSettingsStore } from '@/stores/userSettings.ts'
import { useSystemTimeStore } from '@/stores/systemTime'
interface Props {
filter: filterActionsFilter | timeSeriesGridActionsFilter
elevationChartFilter?: timeSeriesGridActionsFilter
Expand All @@ -87,6 +88,7 @@ const openFileDownloadDialog = () => {
showFileDownloadDialog.value = true
}
const settings = useUserSettingsStore()
const systemTimeStore = useSystemTimeStore()

const options = computed<UseDisplayConfigOptions>(() => {
return {
Expand All @@ -101,7 +103,12 @@ const emit = defineEmits(['close'])
const baseUrl = configManager.get('VITE_FEWS_WEBSERVICES_URL')

const filter = computed(() => props.filter)
const { displayConfig } = useDisplayConfigFilter(baseUrl, filter)
const { displayConfig } = useDisplayConfigFilter(
baseUrl,
filter,
() => systemTimeStore.startTime,
() => systemTimeStore.endTime,
)
watch(
() => displayConfig,
() => {
Expand All @@ -117,6 +124,8 @@ watch(
const { displayConfig: elevationChartDisplayconfig } = useDisplayConfigFilter(
baseUrl,
() => props.elevationChartFilter ?? {},
() => systemTimeStore.startTime,
() => systemTimeStore.endTime,
)

interface DisplayTypeItem {
Expand Down
56 changes: 14 additions & 42 deletions src/components/time-control/IntervalSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@
<v-icon v-show="isActive" small> mdi-check </v-icon>
</template>
</v-list-item>
<v-list-item
:active="1 === selectedIndex"
@click="onSelectInterval(1)"
disabled
>
<v-list-item :active="1 === selectedIndex" @click="onSelectInterval(1)">
Custom
<template v-slot:append="{ isActive }">
<v-icon v-show="isActive" small> mdi-check </v-icon>
Expand All @@ -24,7 +20,7 @@
:active="index === selectedIndex - 2"
@click="onSelectInterval(index + 2)"
>
{{ intervalToLocaleString(item) }}
{{ item.label }}
<template v-slot:append="{ isActive }">
<v-icon v-show="isActive" small> mdi-check </v-icon>
</template>
Expand All @@ -33,75 +29,51 @@
</template>

<script setup lang="ts">
import { DateTime, Duration } from 'luxon'
import type { IntervalItem, Interval } from '@/lib/TimeControl/interval'
import { isEqual } from 'lodash-es'
import { onBeforeMount, ref, watch } from 'vue'
interface Props {
modelValue: string
items: string[]
items: IntervalItem[]
now: Date
}
const props = withDefaults(defineProps<Props>(), {
modelValue: 'default',
items: () => {
return []
},
now: () => new Date(),
})
const emit = defineEmits(['update:modelValue'])
const interval = defineModel<Interval>({ required: true })
const selectedIndex = ref(0)
onBeforeMount(() => {
updateIndex(props.modelValue)
updateIndex(interval.value)
})
const intervalToLocaleString = (interval: string) => {
const parts = interval.split('/')
if (parts.length === 2) {
const startDateTime = DateTime.fromJSDate(props.now).plus(
Duration.fromISO(parts[0]),
)
const endDateTime = DateTime.fromJSDate(props.now).plus(
Duration.fromISO(parts[1]),
)
return startDateTime.toRelative() + ' / ' + endDateTime.toRelative()
} else {
const startDateTime = DateTime.fromJSDate(props.now).plus(
Duration.fromISO(parts[0]),
)
return startDateTime.toRelative()
}
}
const onSelectInterval = (index: number) => {
let selectedInterval = undefined
if (index === 0) {
selectedInterval = 'default'
interval.value = 'default'
} else if (index === 1) {
selectedInterval = 'custom'
interval.value = 'custom'
} else {
selectedInterval = props.items[index - 2]
interval.value = props.items[index - 2]
}
emit('update:modelValue', selectedInterval)
}
function updateIndex(newValue: string | undefined) {
function updateIndex(newValue: Interval) {
if (newValue === 'default') {
selectedIndex.value = 0
} else if (newValue === undefined) {
} else if (newValue === 'custom' || newValue === undefined) {
selectedIndex.value = 1
} else {
selectedIndex.value =
props.items.findIndex((entry) => entry === newValue) + 2
props.items.findIndex((entry) => isEqual(entry, newValue)) + 2
}
}
watch(
() => props.modelValue,
(newValue) => updateIndex(newValue),
)
watch(interval, (newValue) => updateIndex(newValue))
</script>

<style scoped>
Expand Down
138 changes: 46 additions & 92 deletions src/components/time-control/TimeControlMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,62 +16,33 @@
<v-card width="500px">
<v-row no-gutters>
<v-col>
<v-form
v-model="datesAreValid"
:disabled="store.selectedInterval !== 'custom'"
>
<v-card-actions>
<v-text-field
v-model="startDateString"
<v-form ref="form" :disabled="!isCustomInterval">
<div class="pa-4">
<v-date-input
v-model="customStartDate"
:disabled="!isCustomInterval"
label="Start"
density="compact"
variant="solo-filled"
flat
:rules="[rules.required, rules.date]"
>
<template v-slot:prepend>
<v-menu offset-y :close-on-content-click="false">
<template v-slot:activator="{ props }">
<v-icon v-bind="props">mdi-calendar-start</v-icon>
</template>
<v-date-picker
v-model="startDates"
multiple
no-title
hide-actions
>
<template #header></template>
</v-date-picker>
</v-menu>
</template>
</v-text-field>
</v-card-actions>
<v-card-actions>
<v-text-field
v-model="endDateString"
:rules="[
() =>
dateOrderIsCorrect || 'Start date must be before end date',
]"
/>
<v-date-input
v-model="customEndDate"
:disabled="!isCustomInterval"
label="End"
density="compact"
variant="solo-filled"
flat
:rules="[rules.required, rules.date]"
>
<template v-slot:prepend>
<v-menu offset-y :close-on-content-click="false">
<template v-slot:activator="{ props }">
<v-icon v-bind="props">mdi-calendar-end</v-icon>
</template>
<v-date-picker
v-model="endDates"
multiple
no-title
hide-actions
>
<template #header></template>
</v-date-picker>
</v-menu>
</template>
</v-text-field>
</v-card-actions>
:rules="[
() =>
dateOrderIsCorrect || 'End date must be after start date',
]"
/>
</div>
</v-form>
</v-col>
<v-col>
Expand Down Expand Up @@ -102,62 +73,45 @@

<script setup lang="ts">
import IntervalSelector from './IntervalSelector.vue'
import { VDateInput } from 'vuetify/labs/components'
import type { VForm } from 'vuetify/components'
import { ref, computed } from 'vue'
import { useSystemTimeStore } from '../../stores/systemTime'
import { DateTime } from 'luxon'
import { ref, computed, watchEffect, watch } from 'vue'
import { useSystemTimeStore } from '@/stores/systemTime'
import { useConfigStore } from '@/stores/config'
import { periodPresetToIntervalItem } from '@/lib/TimeControl/interval'
const store = useSystemTimeStore()
const datesAreValid = ref(true)
const DATE_FMT = 'yyyy-MM-dd'
const rules = {
required: (value: string) => (value !== undefined && !!value) || 'Required',
date: (value: string) => {
const date = DateTime.fromFormat(value || '', DATE_FMT)
return !isNaN(date.valueOf()) || 'Invalid date'
},
}
const configStore = useConfigStore()
const intervalItems = ['-PT12H', '-P1D', '-P1W', '-P2W', '-P1M', '-P1D/P11D']
const form = ref<VForm>()
const dates = ref<[Date, Date]>([new Date(), new Date()])
const dateOrderIsCorrect = computed(
() =>
!customStartDate.value ||
!customEndDate.value ||
customStartDate.value < customEndDate.value,
)
const startDates = computed({
get() {
return [dates.value[0]]
},
set(newValue: Date[]) {
dates.value[0] = newValue[0]
},
const intervalItems = computed(() => {
const presets = configStore.general.timeSettings?.viewPeriodPresets
return presets?.map(periodPresetToIntervalItem) ?? []
})
const endDates = computed({
get() {
return [dates.value[1]]
},
set(newValue: Date[]) {
dates.value[1] = newValue[0]
},
})
const customStartDate = ref<Date>()
const customEndDate = ref<Date>()
const startDateString = computed({
get() {
return DateTime.fromJSDate(dates.value[0]).toFormat(DATE_FMT)
},
set(newValue: string) {
dates.value[0] = DateTime.fromFormat(newValue, DATE_FMT).toJSDate()
},
})
const isCustomInterval = computed(() => store.selectedInterval === 'custom')
const endDateString = computed({
get() {
return DateTime.fromJSDate(dates.value[1]).toFormat(DATE_FMT)
},
set(newValue: string) {
dates.value[1] = DateTime.fromFormat(newValue, DATE_FMT).toJSDate()
},
watchEffect(() => {
if (isCustomInterval.value && dateOrderIsCorrect.value) {
store.startTime = customStartDate.value
store.endTime = customEndDate.value
}
})
watch([customStartDate, customEndDate], () => form.value?.validate())
function onIntervalChange() {
store.changeInterval()
}
Expand Down
4 changes: 4 additions & 0 deletions src/components/timeseries/TimeSeriesDisplay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import TimeSeriesComponent from '@/components/timeseries/TimeSeriesComponent.vue
import { DisplayType } from '@/lib/display/DisplayConfig'
import { useUserSettingsStore } from '@/stores/userSettings'
import TimeSeriesFileDownloadComponent from '@/components/download/TimeSeriesFileDownloadComponent.vue'
import { useSystemTimeStore } from '@/stores/systemTime'
const showFileDownloadDialog = ref(false)
const openFileDownloadDialog = () => {
Expand All @@ -88,6 +89,7 @@ const props = withDefaults(defineProps<Props>(), {
})
const settings = useUserSettingsStore()
const systemTimeStore = useSystemTimeStore()
const baseUrl = configManager.get('VITE_FEWS_WEBSERVICES_URL')
Expand All @@ -110,6 +112,8 @@ const { displays, displayConfig } = useDisplayConfig(
}
},
selectedPlot,
() => systemTimeStore.startTime,
() => systemTimeStore.endTime,
options,
)
Expand Down
Loading

0 comments on commit e5dd7da

Please sign in to comment.