From 683cec0530373308ae6c06983a44c6973714fad1 Mon Sep 17 00:00:00 2001 From: Luc Claustres Date: Fri, 25 Oct 2024 16:52:32 +0200 Subject: [PATCH] fix: Measures-based layers are not updated when target default unit is changed (closes #981) --- core/client/store.js | 2 +- .../mixins/globe/mixin.geojson-layers.js | 39 ++++++++++++++++- map/client/mixins/map/mixin.geojson-layers.js | 42 ++++++++++++++++++- 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/core/client/store.js b/core/client/store.js index 85913af73..794a92dd6 100644 --- a/core/client/store.js +++ b/core/client/store.js @@ -15,7 +15,7 @@ export const Store = Object.assign(store, { set(path, value) const eventName = _.kebabCase(`${path}-changed`) Events.emit(eventName, value, previousValue) - Events.emit('store-changed', path, value) + Events.emit('store-changed', path, value, previousValue) }, patch (path, value) { // Patching should not change the object reference to maintain reactivity diff --git a/map/client/mixins/globe/mixin.geojson-layers.js b/map/client/mixins/globe/mixin.geojson-layers.js index 4529ac5de..f3a0d3964 100644 --- a/map/client/mixins/globe/mixin.geojson-layers.js +++ b/map/client/mixins/globe/mixin.geojson-layers.js @@ -3,7 +3,7 @@ import _ from 'lodash' import logger from 'loglevel' import sift from 'sift' import { uid } from 'quasar' -import { Time } from '../../../../core/client/time.js' +import { Time, Units } from '../../../../core.client.js' import { fetchGeoJson, getFeatureId, processFeatures, getFeatureStyleType, isInMemoryLayer } from '../../utils.js' import { convertSimpleStyleToPointStyle, convertSimpleStyleToLineStyle, convertSimpleStyleToPolygonStyle } from '../../utils/utils.style.js' import { convertToCesiumFromSimpleStyle, getPointSimpleStyle, getLineSimpleStyle, getPolygonSimpleStyle } from '../../cesium/utils/utils.style.js' @@ -386,6 +386,41 @@ export const geojsonLayers = { } }) }, + onDefaultUnitChangedGeoJsonLayers (path, value) { + if (!path.startsWith('units.default')) return + const quantity = path.replace('units.default.', '') + const units = _.map(Units.getUnits(quantity), 'name') + // Need to update layers with variables affected by the unit change, + // ie which style depends on it + let geoJsonlayers = _.values(this.layers).filter(sift({ + 'cesium.type': 'geoJson', + 'cesium.realtime': true, + // Not sure why but this does not seem to work with sift + //'variables': { $elemMatch: { unit: { $in: units } } }, + 'variables': { $exists: true }, + isVisible: true, + 'cesium.style': { $exists: true }, + 'cesium.template': { $exists: true } + })) + // Check for each layer if it uses the target unit and templated style uses the unit system or not + geoJsonlayers = geoJsonlayers.filter(layer => { + const unit = _.intersection(units, _.map(layer.variables, 'unit')) + if (_.isEmpty(unit)) return false + for (const template of layer.cesium.template) { + if (template.startsWith('style.')) { + const style = _.get(layer.cesium, template) + if ((typeof style === 'string') && style.includes('Units')) return true + } + } + return false + }) + // Then retrieve the engine layers and update + geoJsonlayers.forEach(layer => { + // Retrieve the layer + const dataSource = this.getCesiumLayerByName(geoJsonlayer.name) + dataSource.updateGeoJson() + }) + }, onLayerShownGeoJsonLayers (layer, engineLayer) { // Check if we have cached geojson data for this layer const cachedGeojson = this.geojsonCache[layer.name] @@ -409,6 +444,7 @@ export const geojsonLayers = { created () { this.registerCesiumConstructor(this.createCesiumGeoJsonLayer) this.$events.on('time-current-time-changed', this.onCurrentTimeChangedGeoJsonLayers) + this.$events.on('store-changed', this.onDefaultUnitChangedGeoJsonLayers) this.$engineEvents.on('layer-shown', this.onLayerShownGeoJsonLayers) this.$engineEvents.on('layer-removed', this.onLayerRemovedGeoJsonLayers) // Map of currently updated layers to avoid reentrance with real-time events as @@ -419,6 +455,7 @@ export const geojsonLayers = { }, beforeUnmount () { this.$events.off('time-current-time-changed', this.onCurrentTimeChangedGeoJsonLayers) + this.$events.off('store-changed', this.onDefaultUnitChangedGeoJsonLayers) this.$engineEvents.off('layer-shown', this.onLayerShownGeoJsonLayers) this.$engineEvents.off('layer-removed', this.onLayerRemovedGeoJsonLayers) diff --git a/map/client/mixins/map/mixin.geojson-layers.js b/map/client/mixins/map/mixin.geojson-layers.js index 3b6f99c61..ca4b0edd8 100644 --- a/map/client/mixins/map/mixin.geojson-layers.js +++ b/map/client/mixins/map/mixin.geojson-layers.js @@ -4,7 +4,7 @@ import sift from 'sift' import logger from 'loglevel' import lineOffset from '@turf/line-offset' import 'leaflet-realtime' -import { Time, utils as kdkCoreUtils } from '../../../../core.client.js' +import { Time, Units, utils as kdkCoreUtils } from '../../../../core.client.js' import { GradientPath } from '../../leaflet/GradientPath.js' import { MaskLayer } from '../../leaflet/MaskLayer.js' import { TiledFeatureLayer } from '../../leaflet/TiledFeatureLayer.js' @@ -567,6 +567,44 @@ export const geojsonLayers = { } } }, + onDefaultUnitChangedGeoJsonLayers (path, value) { + if (!path.startsWith('units.default')) return + const quantity = path.replace('units.default.', '') + const units = _.map(Units.getUnits(quantity), 'name') + // Need to update layers with variables affected by the unit change, + // ie which style depends on it + let geoJsonlayers = _.values(this.layers).filter(sift({ + 'leaflet.type': 'geoJson', + 'leaflet.realtime': true, + // Not sure why but this does not seem to work with sift + //'variables': { $elemMatch: { unit: { $in: units } } }, + 'variables': { $exists: true }, + isVisible: true, + 'leaflet.style': { $exists: true }, + 'leaflet.template': { $exists: true } + })) + // Check for each layer if it uses the target unit and templated style uses the unit system or not + geoJsonlayers = geoJsonlayers.filter(layer => { + const unit = _.intersection(units, _.map(layer.variables, 'unit')) + if (_.isEmpty(unit)) return false + for (const template of layer.leaflet.template) { + if (template.startsWith('style.')) { + const style = _.get(layer.leaflet, template) + if ((typeof style === 'string') && style.includes('Units')) return true + } + } + return false + }) + // Then retrieve the engine layers and update + geoJsonlayers.forEach(layer => { + layer = this.getLeafletLayerByName(layer.name) + if (layer.tiledLayer) { + layer.tiledLayer.redraw() + } else { + layer.update() + } + }) + }, onMapZoomChangedGeoJsonLayers () { // Need to update layers with tooltip defining a minZoom/maxZoom // as we cannot do that in template because tooltip needs to be recreated/destroyed dynamically @@ -628,6 +666,7 @@ export const geojsonLayers = { this.registerLeafletConstructor(this.createLeafletGeoJsonLayer) this.$events.on('time-current-time-changed', this.onCurrentTimeChangedGeoJsonLayers) this.$engineEvents.on('selected-level-changed', this.onCurrentLevelChangedGeoJsonLayers) + this.$events.on('store-changed', this.onDefaultUnitChangedGeoJsonLayers) this.$engineEvents.on('zoomend', this.onMapZoomChangedGeoJsonLayers) this.$engineEvents.on('layer-shown', this.onLayerShownGeoJsonLayers) this.$engineEvents.on('layer-removed', this.onLayerRemovedGeoJsonLayers) @@ -638,6 +677,7 @@ export const geojsonLayers = { beforeUnmount () { this.$events.off('time-current-time-changed', this.onCurrentTimeChangedGeoJsonLayers) this.$engineEvents.off('selected-level-changed', this.onCurrentLevelChangedGeoJsonLayers) + this.$events.off('store-changed', this.onDefaultUnitChangedGeoJsonLayers) this.$engineEvents.off('zoomend', this.onMapZoomChangedGeoJsonLayers) this.$engineEvents.off('layer-shown', this.onLayerShownGeoJsonLayers) this.$engineEvents.off('layer-removed', this.onLayerRemovedGeoJsonLayers)