Skip to content

Commit

Permalink
feat: Replace the time series widget using new stackable time series (c…
Browse files Browse the repository at this point in the history
…loses #376)
  • Loading branch information
claustres committed Aug 27, 2024
1 parent 23919ff commit 1adfc2a
Show file tree
Hide file tree
Showing 14 changed files with 624 additions and 82 deletions.
49 changes: 5 additions & 44 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,51 +79,11 @@ const topWidgets = [{
visible: 'hasFeature',
handler: 'onExportFeature'
}]
}, {
id: 'time-series', label: 'KTimeSeries.LABEL', icon: 'las la-chart-line',
content: { component: 'widget/KTimeSeries' },
header: [{
id: 'absolute-time-range',
component: 'time/KAbsoluteTimeRange'
}, {
id: 'restore-time-range',
icon: 'las la-undo',
tooltip: 'KTimeSeries.RESTORE_TIME_RANGE',
visible: 'hasZoomHistory',
handler: 'onZoomRestored'
}, {
id: 'relative-time-ranges',
component: 'menu/KMenu',
icon: 'las la-history',
content: [{
component: 'time/KRelativeTimeRanges',
ranges: ['last-hour', 'last-2-hours', 'last-3-hours', 'last-6-hours',
'last-12-hours', 'last-day', 'last-2-days', 'last-3-days', 'last-week',
'next-12-hours', 'next-day', 'next-2-days', 'next-3-days']
}]
}, {
id: 'run-options',
component: 'input/KOptionsChooser',
icon: 'las la-clock',
tooltip: 'KTimeSeries.RUN',
visible: 'hasRunTimes',
hideSelected: false,
options: ':runOptions',
on: { event: 'option-chosen', listener: 'onUpdateRun' }
}, {
id: 'center-view',
icon: 'las la-eye',
tooltip: 'KTimeSeries.CENTER_ON',
visible: 'probedVariables',
handler: 'onCenterOn'
}, {
id: 'export-feature',
icon: 'las la-file-download',
tooltip: 'KTimeSeries.EXPORT_SERIES',
visible: 'probedVariables',
handler: 'onExportSeries'
}]
}, {
id: 'time-series', label: 'TimeSeries.LABEL', icon: 'las la-chart-line',
content: { component: 'TimeSeries' },
header: [{ component: 'TimeSeriesToolbar' }]
}, {
id: 'elevation-profile', label: 'KElevationProfile.LABEL', icon: 'las la-mountain',
content: { component: 'widget/KElevationProfile' },
header: [{
Expand Down Expand Up @@ -640,6 +600,7 @@ module.exports = {
layers: {
actions: mapLayerActions
},
selection: { multiple: 'ctrlKey' },
featuresChunkSize: 5000 // TODO: here or in mapEngine ?
},
globeActivity: {
Expand Down
3 changes: 2 additions & 1 deletion src/boot/kdk.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import logger from 'loglevel'
import config from 'config'
import { Notify } from 'quasar'
import postRobot from 'post-robot'
import utils from '../utils'
import * as utils from '../utils'
import appHooks from '../app.hooks'
import services from '../services'
import { Router } from '../router'
Expand Down Expand Up @@ -162,6 +162,7 @@ export default async ({ app, router }) => {
app.component('KStamp', await kdkCoreUtils.loadComponent('KStamp'))
app.component('KModal', await kdkCoreUtils.loadComponent('KModal'))
app.component('KDialog', await kdkCoreUtils.loadComponent('KDialog'))
app.component('KMenu', await kdkCoreUtils.loadComponent('menu/KMenu'))
app.component('KForm', await kdkCoreUtils.loadComponent('form/KForm'))
app.component('KPage', await kdkCoreUtils.loadComponent('layout/KPage'))
app.component('KTour', await kdkCoreUtils.loadComponent('app/KTour'))
Expand Down
61 changes: 55 additions & 6 deletions src/components/GlobeActivity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@

<script>
import _ from 'lodash'
import moment from 'moment'
import { computed } from 'vue'
import { mixins as kCoreMixins } from '@kalisio/kdk/core.client'
import { Store, Time, Layout, mixins as kCoreMixins } from '@kalisio/kdk/core.client'
import { mixins as kMapMixins, composables as kMapComposables } from '@kalisio/kdk/map.client'
import { MixinStore } from '../mixin-store.js'
import { ComposableStore } from '../composable-store.js'
import utils from '../utils.js'
import * as utils from '../utils'
import config from 'config'
const name = 'globeActivity'
Expand All @@ -36,7 +37,6 @@ export default {
baseActivityMixin,
kMapMixins.activity,
kMapMixins.style,
kMapMixins.featureSelection,
kMapMixins.featureService,
kMapMixins.infobox,
kMapMixins.weacast,
Expand Down Expand Up @@ -86,6 +86,17 @@ export default {
handler () {
this.refreshLayers()
}
},
'selection.items': {
handler () {
this.updateSelection()
},
deep: true
},
'probe.item': {
handler () {
this.updateSelection()
}
}
},
methods: {
Expand Down Expand Up @@ -118,6 +129,30 @@ export default {
const response = await utils.sendEmbedEvent('layer-update', { name, geoJson, options })
await kMapMixins.globe.geojsonLayers.methods.updateLayer.call(this, name, (response && response.data) || geoJson, options)
},
handleWidget (widget) {
// If window already open on another widget keep it
if (widget && (widget !== 'none') && !this.isWidgetWindowVisible(widget)) this.openWidget(widget)
},
async updateTimeSeries () {
this.state.timeSeries = await utils.updateTimeSeries(this.state.timeSeries)
},
updateHighlights () {
this.clearHighlights()
this.getSelectedItems().forEach(item => {
this.highlight(item.feature || item.location, item.layer)
})
if (this.hasProbedLocation()) this.highlight(this.getProbedLocation(), this.getProbedLayer())
},
async updateSelection () {
this.updateHighlights()
await this.updateTimeSeries()
if (this.hasProbedLocation() || this.hasSelectedItems()) {
this.handleWidget(this.getWidgetForProbe() || this.getWidgetForSelection())
} else {
// Hide the window
Layout.setWindowVisible('top', false)
}
},
async onClicked (options, event) {
const latlng = _.get(event, 'latlng')
const pickedPosition = _.get(event, 'pickedPosition')
Expand Down Expand Up @@ -164,6 +199,12 @@ export default {
this.$engineEvents.on('layer-removed', this.onRemovedLayerEvent)
this.onUpdatedLayerEvent = this.generateHandlerForLayerEvent('layer-updated')
this.$engineEvents.on('layer-updated', this.onUpdatedLayerEvent)
this.$engineEvents.on('selected-level-changed', this.updateTimeSeries)
// Initialize the time range
const span = Store.get('timeseries.span')
const start = moment(Time.getCurrentTime()).subtract(span, 'm')
const end = moment(Time.getCurrentTime()).add(span, 'm')
Time.patchRange({ start, end })
},
beforeUnmount () {
this.$engineEvents.off('click', this.onClicked)
Expand All @@ -173,16 +214,24 @@ export default {
this.$engineEvents.off('layer-hidden', this.onHiddenLayerEvent)
this.$engineEvents.off('layer-removed', this.onRemovedLayerEvent)
this.$engineEvents.off('layer-updated', this.onUpdatedLayerEvent)
this.$engineEvents.off('selected-level-changed', this.updateTimeSeries)
},
unmounted () {
utils.sendEmbedEvent('globe-destroyed')
},
async setup () {
const activity = kMapComposables.useActivity(name)
const project = kMapComposables.useProject()
// Initialize state and project
Object.assign(activity.state, {
timeSeries: []
})
await project.loadProject()
activity.setSelectionMode('multiple')
const expose = {
...kMapComposables.useActivity(name),
...kMapComposables.useProject()
...activity,
...project
}
await expose.loadProject()
const additionalComposables = _.get(config, `${name}.additionalComposables`, [])
for (const use of additionalComposables.map((name) => ComposableStore.get(name))) { Object.assign(expose, use(name)) }
return expose
Expand Down
72 changes: 61 additions & 11 deletions src/components/MapActivity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
<script>
import _ from 'lodash'
import L from 'leaflet'
import moment from 'moment'
import 'leaflet-rotate/dist/leaflet-rotate-src.js'
import 'leaflet-arrowheads'
import { computed } from 'vue'
import { mixins as kCoreMixins } from '@kalisio/kdk/core.client'
import { Store, Time, Layout, mixins as kCoreMixins } from '@kalisio/kdk/core.client'
import { mixins as kMapMixins, composables as kMapComposables } from '@kalisio/kdk/map.client'
import { MixinStore } from '../mixin-store.js'
import { ComposableStore } from '../composable-store.js'
import utils from '../utils.js'
import * as utils from '../utils'
import config from 'config'
const name = 'mapActivity'
Expand Down Expand Up @@ -55,7 +56,6 @@ export default {
baseActivityMixin,
kMapMixins.activity,
kMapMixins.style,
kMapMixins.featureSelection,
kMapMixins.featureService,
kMapMixins.infobox,
kMapMixins.weacast,
Expand Down Expand Up @@ -106,6 +106,17 @@ export default {
handler () {
this.refreshLayers()
}
},
'selection.items': {
handler () {
this.updateSelection()
},
deep: true
},
'probe.item': {
handler () {
this.updateSelection()
}
}
},
methods: {
Expand Down Expand Up @@ -140,6 +151,30 @@ export default {
const response = await utils.sendEmbedEvent('layer-update', { name, geoJson, options })
await kMapMixins.map.geojsonLayers.methods.updateLayer.call(this, name, (response && response.data) || geoJson, options)
},
handleWidget (widget) {
// If window already open on another widget keep it
if (widget && (widget !== 'none') && !this.isWidgetWindowVisible(widget)) this.openWidget(widget)
},
async updateTimeSeries () {
this.state.timeSeries = await utils.updateTimeSeries(this.state.timeSeries)
},
updateHighlights () {
this.clearHighlights()
this.getSelectedItems().forEach(item => {
this.highlight(item.feature || item.location, item.layer)
})
if (this.hasProbedLocation()) this.highlight(this.getProbedLocation(), this.getProbedLayer())
},
async updateSelection () {
this.updateHighlights()
await this.updateTimeSeries()
if (this.hasProbedLocation() || this.hasSelectedItems()) {
this.handleWidget(this.getWidgetForProbe() || this.getWidgetForSelection())
} else {
// Hide the window
Layout.setWindowVisible('top', false)
}
},
getHighlightMarker (feature, options) {
if ((options.name === kMapComposables.HighlightsLayerName) && this.isWeatherProbe(feature)) {
return {
Expand Down Expand Up @@ -219,15 +254,15 @@ export default {
this.leafletHandlers = {}
},
onMoveEnd () {
// Update navigation information in store
// Update navigation information in store, this is useful eg in test to be able to retrieve current state
const center = this.map.getCenter()
const zoom = this.map.getZoom()
const bounds = this.map.getBounds()
const south = bounds.getSouth()
const west = bounds.getWest()
const north = bounds.getNorth()
const east = bounds.getEast()
this.$store.patch(this.activityName, {
Object.assign(this.state, {
longitude: center.lng,
latitude: center.lat,
zoom,
Expand All @@ -251,9 +286,14 @@ export default {
this.forwardLayerEvents(allLayerEvents)
this.$engineEvents.on('edit-start', this.onEditStartEvent)
this.$engineEvents.on('edit-stop', this.onEditStopEvent)
// We store some information about the current navigation state in store, initialize it
this.$store.set(this.activityName, {})
this.$engineEvents.on('moveend', this.onMoveEnd)
this.$engineEvents.on('forecast-model-changed', this.updateTimeSeries)
this.$engineEvents.on('selected-level-changed', this.updateTimeSeries)
// Initialize the time range
const span = Store.get('timeseries.span')
const start = moment(Time.getCurrentTime()).subtract(span, 'm')
const end = moment(Time.getCurrentTime()).add(span, 'm')
Time.patchRange({ start, end })
},
beforeUnmount () {
// Remove event connections
Expand All @@ -262,19 +302,29 @@ export default {
this.$engineEvents.off('edit-start', this.onEditStartEvent)
this.$engineEvents.off('edit-stop', this.onEditStopEvent)
this.$engineEvents.off('moveend', this.onMoveEnd)
this.$engineEvents.off('forecast-model-changed', this.updateTimeSeries)
this.$engineEvents.off('selected-level-changed', this.updateTimeSeries)
this.unregisterStyle('point', this.getHighlightMarker)
this.unregisterStyle('tooltip', this.getHighlightTooltip)
},
unmounted () {
utils.sendEmbedEvent('map-destroyed')
},
async setup () {
const activity = kMapComposables.useActivity(name)
const weather = kMapComposables.useWeather(name)
const project = kMapComposables.useProject()
// Initialize state and project
Object.assign(activity.state, {
timeSeries: []
})
await project.loadProject()
activity.setSelectionMode('multiple')
const expose = {
...kMapComposables.useActivity(name),
...kMapComposables.useWeather(name),
...kMapComposables.useProject()
...activity,
...weather,
...project
}
await expose.loadProject()
const additionalComposables = _.get(config, `${name}.additionalComposables`, [])
for (const use of additionalComposables.map((name) => ComposableStore.get(name))) { Object.assign(expose, use(name)) }
return expose
Expand Down
Loading

0 comments on commit 1adfc2a

Please sign in to comment.