Skip to content

Commit

Permalink
Merge pull request #860 from geoadmin/feat-PB-505-projection-error
Browse files Browse the repository at this point in the history
PB-505: Added error when external WMTS layer don't support WGS84
  • Loading branch information
ltshb authored May 27, 2024
2 parents 2425c19 + 824aab0 commit 7c5a603
Show file tree
Hide file tree
Showing 14 changed files with 155 additions and 39 deletions.
31 changes: 27 additions & 4 deletions src/api/layers/AbstractLayer.class.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { cloneDeep } from 'lodash'

import { InvalidLayerDataError } from '@/api/layers/InvalidLayerData.error'

/**
Expand Down Expand Up @@ -121,15 +123,36 @@ export default class AbstractLayer {
this.isLoading = isLoading
this.hasDescription = hasDescription
this.hasLegend = hasLegend
this.errorKey = null
this.errorKeys = new Set()
this.hasError = false
this.timeConfig = timeConfig
this.hasMultipleTimestamps = this.timeConfig?.timeEntries?.length > 1
}

hasErrorKey(key) {
return this.errorKeys.has(key)
}

getFirstErrorKey() {
return this.errorKeys.values().next().value
}

addErrorKey(key) {
this.errorKeys.add(key)
this.hasError = true
}

removeErrorKey(key) {
this.errorKeys.delete(key)
this.hasError = !!this.errorKeys.size
}

clearErrorKeys() {
this.errorKeys.clear()
this.hasError = false
}

clone() {
let clone = Object.assign(Object.create(Object.getPrototypeOf(this)), this)
clone.attributions = this.attributions.map((attribution) => attribution.clone())
return clone
return cloneDeep(this)
}
}
3 changes: 2 additions & 1 deletion src/modules/i18n/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -681,5 +681,6 @@
"3d_vegetation": "Vegetationen",
"3d_constructions": "Gebäude und Konstruktionen",
"webmapviewer_live_disclaimer": "Grosse Veränderungen stehen bevor, <a target='_blank' href='https://www.swisstopo.admin.ch/de'>erfahren Sie mehr</a>",
"drawing_too_large": "Deine Zeichnung ist zu gross, entferne einige Details."
"drawing_too_large": "Deine Zeichnung ist zu gross, entferne einige Details.",
"3d_unsupported_projection": "Dieser Datensatz (externe Quelle) kann wegen fehlender Unterstützung der Projektion EPSG:4326 nicht in 3D dargestellt werden"
}
3 changes: 2 additions & 1 deletion src/modules/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -681,5 +681,6 @@
"3d_vegetation": "Vegetations",
"3d_constructions": "Buildings and constructions",
"webmapviewer_live_disclaimer": "Big changes are coming soon, <a target='_blank' href='https://www.swisstopo.admin.ch/en'>learn more</a>",
"drawing_too_large": "Your drawing is too large, remove some features"
"drawing_too_large": "Your drawing is too large, remove some features",
"3d_unsupported_projection": "This map provided by external source can't be displayed in 3d because it doesn't support the projection EPSG:4326"
}
3 changes: 2 additions & 1 deletion src/modules/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -681,5 +681,6 @@
"3d_vegetation": "Végétations",
"3d_constructions": "Bâtiments et constructions",
"webmapviewer_live_disclaimer": "De grands changements sont à venir, <a target='_blank' href='https://www.swisstopo.admin.ch/fr'>en savoir plus</a>",
"drawing_too_large": "Ton dessin est trop grand, enlève quelques éléments"
"drawing_too_large": "Ton dessin est trop grand, enlève quelques éléments",
"3d_unsupported_projection": "La carte ne peut pas être affichées en 3d parce qu'elle ne supporte pas la projection EPSG:4326"
}
3 changes: 2 additions & 1 deletion src/modules/i18n/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -681,5 +681,6 @@
"3d_vegetation": "Vegetazione",
"3d_constructions": "Edifici e costruzioni",
"webmapviewer_live_disclaimer": "Grandi cambiamenti in arrivo, <a target='_blank' href='https://www.swisstopo.admin.ch/it'>per saperne di più</a>",
"drawing_too_large": "Il tuo disegno è troppo grande, rimuovi alcune caratteristiche"
"drawing_too_large": "Il tuo disegno è troppo grande, rimuovi alcune caratteristiche",
"3d_unsupported_projection": "La mappa non può essere visualizzata in 3D perché non supporta la proiezione EPSG:4326"
}
3 changes: 2 additions & 1 deletion src/modules/i18n/locales/rm.json
Original file line number Diff line number Diff line change
Expand Up @@ -679,5 +679,6 @@
"3d_vegetation": "Vegietaziun",
"3d_constructions": "Edifizis ed installaziuns",
"webmapviewer_live_disclaimer": "Grondas midadas vegnan prest, <a target='_blank' href='https://www.swisstopo.admin.ch/de'>emprender dapli</a>",
"drawing_too_large": "Tes dissegn è memia grond, allontanescha intgins detagls"
"drawing_too_large": "Tes dissegn è memia grond, allontanescha intgins detagls",
"3d_unsupported_projection": "La carta na po betg vegnir mussada en 3D perquai ch'ella na sustegna betg la projecziun EPSG:4326"
}
52 changes: 39 additions & 13 deletions src/modules/map/components/cesium/CesiumWMTSLayer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
UrlTemplateImageryProvider,
WebMapTileServiceImageryProvider,
} from 'cesium'
import { isEqual } from 'lodash'
import { mapActions } from 'vuex'
import ExternalWMTSLayer, { WMTSEncodingTypes } from '@/api/layers/ExternalWMTSLayer.class'
import GeoAdminWMTSLayer from '@/api/layers/GeoAdminWMTSLayer.class'
Expand All @@ -23,8 +25,12 @@ import log from '@/utils/logging'
import addImageryLayerMixins from './utils/addImageryLayer-mixins'
const dispatcher = { dispatcher: 'CesiumWMTSLayer.vue' }
const MAXIMUM_LEVEL_OF_DETAILS = 18
const threeDErrorKey = '3d_unsupported_projection'
export default {
mixins: [addImageryLayerMixins],
props: {
Expand Down Expand Up @@ -72,6 +78,11 @@ export default {
log.error(
`External layer ${this.wmtsLayerConfig.id} does not support ${this.projection.epsg}`
)
this.addLayerErrorKey({
layerId: this.wmtsLayerConfig.id,
errorKey: threeDErrorKey,
...dispatcher,
})
}
return set
},
Expand Down Expand Up @@ -108,17 +119,30 @@ export default {
},
},
watch: {
dimensions() {
this.updateLayer()
dimensions(newDimension, oldDimension) {
if (!isEqual(newDimension, oldDimension)) {
log.debug(`layer dimension have been updated`, oldDimension, newDimension)
this.updateLayer()
}
},
},
unmounted() {
if (this.wmtsLayerConfig.hasErrorKey(threeDErrorKey)) {
this.removeLayerErrorKey({
layerId: this.wmtsLayerConfig.id,
errorKey: threeDErrorKey,
...dispatcher,
})
}
},
methods: {
...mapActions(['addLayerErrorKey', 'removeLayerErrorKey']),
createImagery(url) {
const options = {
show: this.wmtsLayerConfig.visible,
alpha: this.opacity,
}
if (this.wmtsLayerConfig instanceof ExternalWMTSLayer) {
if (this.wmtsLayerConfig instanceof ExternalWMTSLayer && this.tileMatrixSetId) {
return new ImageryLayer(
new WebMapTileServiceImageryProvider({
url:
Expand All @@ -132,17 +156,19 @@ export default {
}),
options
)
} else if (this.wmtsLayerConfig instanceof GeoAdminWMTSLayer) {
return new ImageryLayer(
new UrlTemplateImageryProvider({
rectangle: Rectangle.fromDegrees(
...DEFAULT_PROJECTION.getBoundsAs(WGS84).flatten
),
maximumLevel: MAXIMUM_LEVEL_OF_DETAILS,
url: url,
}),
options
)
}
return new ImageryLayer(
new UrlTemplateImageryProvider({
rectangle: Rectangle.fromDegrees(
...DEFAULT_PROJECTION.getBoundsAs(WGS84).flatten
),
maximumLevel: MAXIMUM_LEVEL_OF_DETAILS,
url: url,
}),
options
)
return null
},
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ const addImageryLayerMixins = {
const index = viewer.scene.imageryLayers.indexOf(this.layer)
viewer.scene.imageryLayers.remove(this.layer)
this.layer = this.createImagery(this.url)
viewer.scene.imageryLayers.add(this.layer, index)
if (this.layer) {
viewer.scene.imageryLayers.add(this.layer, index)
}
},
},
watch: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ function duplicateLayer() {
<ErrorButton
v-else-if="layer.hasError"
:compact="compact"
:error-message="layer.errorKey"
:error-message="layer.getFirstErrorKey()"
:data-cy="`button-error-${id}-${index}`"
/>
<MenuActiveLayersListItemTimeSelector
Expand Down
81 changes: 71 additions & 10 deletions src/store/modules/layers.store.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,22 @@ const getters = {
getActiveLayersById: (state) => (layerId) =>
state.activeLayers.filter((layer) => layer.id === layerId),

/**
* Retrieves layer(s) by ID.
*
* Search in active layer and in preview layer
*
* @param {string} layerId ID of the layer(s) to retrieve
* @returns {[AbstractLayer]} All active layers matching the ID
*/
getLayersById: (state) => (layerId) => {
const layers = state.activeLayers.filter((layer) => layer.id === layerId)
if (state.previewLayer?.id === layerId) {
layers.push(state.previewLayer)
}
return layers
},

/**
* Retrieves active layer by index
*
Expand Down Expand Up @@ -539,24 +555,24 @@ const actions = {
},

/**
* Set a layer error translation key.
* Add a layer error translation key.
*
* NOTE: This set the error key to all layers matching the ID.
*
* @param {string} layerId Layer ID of the layer to set the error
* @param {string} errorKey Error translation key to add
* @param {string} dispatcher Action dispatcher name
*/
setLayerErrorKey({ commit, getters }, { layerId, errorKey, dispatcher }) {
const layers = getters.getActiveLayersById(layerId)
addLayerErrorKey({ commit, getters }, { layerId, errorKey, dispatcher }) {
const layers = getters.getLayersById(layerId)
if (layers.length === 0) {
throw new Error(
`Failed to update layer error key "${layerId}", layer not found in active layers`
`Failed to add layer error key "${layerId}", layer not found in active layers`
)
}
const updatedLayers = layers.map((layer) => {
const clone = layer.clone()
clone.errorKey = errorKey
clone.hasError = !!errorKey
clone.addErrorKey(errorKey)
if (clone.isLoading) {
clone.isLoading = false
}
Expand All @@ -565,6 +581,53 @@ const actions = {
commit('updateLayers', { layers: updatedLayers, dispatcher })
},

/**
* Remove a layer error translation key.
*
* NOTE: This set the error key to all layers matching the ID.
*
* @param {string} layerId Layer ID of the layer to set the error
* @param {string} errorKey Error translation key to remove
* @param {string} dispatcher Action dispatcher name
*/
removeLayerErrorKey({ commit, getters }, { layerId, errorKey, dispatcher }) {
const layers = getters.getLayersById(layerId)
if (layers.length === 0) {
throw new Error(
`Failed to remove layer error key "${layerId}", layer not found in active layers`
)
}
const updatedLayers = layers.map((layer) => {
const clone = layer.clone()
clone.removeErrorKey(errorKey)
return clone
})
commit('updateLayers', { layers: updatedLayers, dispatcher })
},

/**
* Remove all layer error translation keys.
*
* NOTE: This set the error key to all layers matching the ID.
*
* @param {string} layerId Layer ID of the layer to clear the error keys
* @param {string} dispatcher Action dispatcher name
*/
clearLayerErrorKeys({ commit, getters }, { layerId, dispatcher }) {
const layers = getters.getLayerById(layerId)
if (layers.length === 0) {
throw new Error(
`Failed to clear layer error keys "${layerId}", layer not found in active layers`
)
}
const updatedLayers = layers.map((layer) => {
const clone = layer.clone()
clone.clearErrorKeys()
return clone
})
commit('updateLayers', { layers: updatedLayers, dispatcher })
},

/**
* Set KML/GPX layer(s) with its data and metadata.
*
Expand Down Expand Up @@ -599,11 +662,9 @@ const actions = {
clone.isLoading = false

if (!extent) {
clone.errorKey = 'kml_gpx_file_empty'
clone.hasError = true
clone.addErrorKey('kml_gpx_file_empty')
} else if (!getExtentForProjection(rootState.position.projection, extent)) {
clone.errorKey = 'kml_gpx_file_out_of_bounds'
clone.hasError = true
clone.addErrorKey('kml_gpx_file_out_of_bounds')
}
}
if (metadata) {
Expand Down
2 changes: 1 addition & 1 deletion src/store/plugins/external-layers.plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ async function updateExternalLayer(store, capabilities, layer, projection) {
return updated
} catch (error) {
log.error(`Failed to update external layer ${layer.id}: `, error)
store.dispatch('setLayerErrorKey', {
store.dispatch('addLayerErrorKey', {
layerId: layer.id,
errorKey: error.key ? error.key : 'error',
...dispatcher,
Expand Down
3 changes: 1 addition & 2 deletions src/store/plugins/load-geojson-style-and-data.plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,7 @@ function loadDataAndStyle(geoJsonLayer) {
)
const clone = geoJsonLayer.clone()
clone.isLoading = false
clone.errorKey = 'loading_error_network_failure'
clone.hasError = true
clone.addErrorKey('loading_error_network_failure')
return clone
}),
}
Expand Down
2 changes: 1 addition & 1 deletion src/store/plugins/load-gpx-data.plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async function loadGpx(store, gpxLayer) {
})
} catch (error) {
log.error(`Error while fetching GPX data for layer ${gpxLayer?.id}`)
store.dispatch('setLayerErrorKey', {
store.dispatch('addLayerErrorKey', {
layerId: gpxLayer.id,
errorKey: `loading_error_network_failure`,
...dispatcher,
Expand Down
2 changes: 1 addition & 1 deletion src/store/plugins/load-kml-data.plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ async function loadData(store, kmlLayer) {
})
} catch (error) {
log.error(`Error while fetching KML data for layer ${kmlLayer?.id}: ${error}`)
store.dispatch('setLayerErrorKey', {
store.dispatch('addLayerErrorKey', {
layerId: kmlLayer.id,
errorKey: `loading_error_network_failure`,
...dispatcher,
Expand Down

0 comments on commit 7c5a603

Please sign in to comment.