-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1146 from geoadmin/feat-pb-995-cesium-wmts-compos…
- Loading branch information
Showing
8 changed files
with
300 additions
and
180 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
260 changes: 108 additions & 152 deletions
260
src/modules/map/components/cesium/CesiumWMTSLayer.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,169 +1,125 @@ | ||
<template> | ||
<slot /> | ||
</template> | ||
|
||
<script> | ||
import { | ||
ImageryLayer, | ||
Rectangle, | ||
UrlTemplateImageryProvider, | ||
WebMapTileServiceImageryProvider, | ||
} from 'cesium' | ||
import { isEqual } from 'lodash' | ||
import { mapActions } from 'vuex' | ||
<script setup> | ||
import { Rectangle, UrlTemplateImageryProvider, WebMapTileServiceImageryProvider } from 'cesium' | ||
import { computed, inject, onBeforeUnmount, toRef, toRefs, watch } from 'vue' | ||
import { useStore } from 'vuex' | ||
import ExternalWMTSLayer, { WMTSEncodingTypes } from '@/api/layers/ExternalWMTSLayer.class' | ||
import GeoAdminWMTSLayer from '@/api/layers/GeoAdminWMTSLayer.class' | ||
import { DEFAULT_PROJECTION } from '@/config/map.config' | ||
import CoordinateSystem from '@/utils/coordinates/CoordinateSystem.class' | ||
import useAddImageryLayer from '@/modules/map/components/cesium/utils/useAddImageryLayer.composable' | ||
import { WGS84 } from '@/utils/coordinates/coordinateSystems' | ||
import ErrorMessage from '@/utils/ErrorMessage.class' | ||
import { getTimestampFromConfig, getWmtsXyzUrl } from '@/utils/layerUtils' | ||
import { getWmtsXyzUrl } from '@/utils/layerUtils' | ||
import log from '@/utils/logging' | ||
import addImageryLayerMixins from './utils/addImageryLayer-mixins' | ||
const dispatcher = { dispatcher: 'CesiumWMTSLayer.vue' } | ||
const MAXIMUM_LEVEL_OF_DETAILS = 18 | ||
const unsupportedProjectionError = new ErrorMessage('3d_unsupported_projection') | ||
const threeDError = new ErrorMessage('3d_unsupported_projection') | ||
export default { | ||
mixins: [addImageryLayerMixins], | ||
props: { | ||
wmtsLayerConfig: { | ||
type: [GeoAdminWMTSLayer, ExternalWMTSLayer], | ||
required: true, | ||
}, | ||
projection: { | ||
type: CoordinateSystem, | ||
required: true, | ||
}, | ||
zIndex: { | ||
type: Number, | ||
default: -1, | ||
}, | ||
isTimeSliderActive: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
parentLayerOpacity: { | ||
type: Number, | ||
default: null, | ||
}, | ||
const props = defineProps({ | ||
wmtsLayerConfig: { | ||
type: [GeoAdminWMTSLayer, ExternalWMTSLayer], | ||
required: true, | ||
}, | ||
computed: { | ||
layerId() { | ||
return this.wmtsLayerConfig.id | ||
}, | ||
opacity() { | ||
return this.parentLayerOpacity ?? this.wmtsLayerConfig.opacity ?? 1.0 | ||
}, | ||
url() { | ||
return getWmtsXyzUrl(this.wmtsLayerConfig, this.projection, { | ||
addTimestamp: true, | ||
}) | ||
}, | ||
tileMatrixSet() { | ||
const set = | ||
this.wmtsLayerConfig.tileMatrixSets.find( | ||
(set) => set.projection.epsg === this.projection.epsg | ||
) ?? null | ||
if (!set) { | ||
log.error( | ||
`External layer ${this.wmtsLayerConfig.id} does not support ${this.projection.epsg}` | ||
) | ||
this.addLayerError({ | ||
layerId: this.wmtsLayerConfig.id, | ||
isExternal: this.wmtsLayerConfig.isExternal, | ||
baseUrl: this.wmtsLayerConfig.baseUrl, | ||
error: threeDError, | ||
...dispatcher, | ||
}) | ||
} | ||
return set | ||
}, | ||
tileMatrixSetId() { | ||
return this.tileMatrixSet?.id ?? '' | ||
}, | ||
dimensions() { | ||
const dimensions = {} | ||
this.wmtsLayerConfig.dimensions?.reduce((acc, dimension) => { | ||
if (dimension.current) { | ||
acc[dimension.id] = 'current' | ||
} else { | ||
acc[dimension.id] = dimension.values[0] | ||
} | ||
}, dimensions) | ||
if (this.wmtsLayerConfig.hasMultipleTimestamps) { | ||
// if we have a time config use it as dimension | ||
const timestamp = getTimestampFromConfig(this.wmtsLayerConfig) | ||
// overwrite any Time, TIME or time dimension | ||
const timeDimension = Object.entries(dimensions).find( | ||
(e) => e[0].toLowerCase() === 'time' | ||
) | ||
if (timeDimension) { | ||
dimensions[timeDimension[0]] = timestamp | ||
} | ||
} | ||
return dimensions | ||
}, | ||
}, | ||
watch: { | ||
dimensions(newDimension, oldDimension) { | ||
if (!isEqual(newDimension, oldDimension)) { | ||
log.debug(`layer dimension have been updated`, oldDimension, newDimension) | ||
this.updateLayer() | ||
} | ||
}, | ||
}, | ||
unmounted() { | ||
if (this.wmtsLayerConfig.containErrorMessage(threeDError)) { | ||
this.removeLayerError({ | ||
layerId: this.wmtsLayerConfig.id, | ||
isExternal: this.wmtsLayerConfig.isExternal, | ||
baseUrl: this.wmtsLayerConfig.baseUrl, | ||
error: threeDError, | ||
...dispatcher, | ||
}) | ||
} | ||
zIndex: { | ||
type: Number, | ||
default: -1, | ||
}, | ||
methods: { | ||
...mapActions(['addLayerError', 'removeLayerError']), | ||
createImagery(url) { | ||
const options = { | ||
alpha: this.opacity, | ||
} | ||
if (this.wmtsLayerConfig instanceof ExternalWMTSLayer && this.tileMatrixSetId) { | ||
return new ImageryLayer( | ||
new WebMapTileServiceImageryProvider({ | ||
url: | ||
this.wmtsLayerConfig.getTileEncoding === WMTSEncodingTypes.KVP | ||
? this.wmtsLayerConfig.baseUrl | ||
: this.wmtsLayerConfig.urlTemplate, | ||
layer: this.wmtsLayerConfig.id, | ||
style: this.wmtsLayerConfig.style, | ||
tileMatrixSetID: this.tileMatrixSetId, | ||
dimensions: this.dimensions, | ||
}), | ||
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 null | ||
}, | ||
parentLayerOpacity: { | ||
type: Number, | ||
default: null, | ||
}, | ||
}) | ||
const { wmtsLayerConfig, zIndex, parentLayerOpacity } = toRefs(props) | ||
const getViewer = inject('getViewer') | ||
const store = useStore() | ||
const projection = computed(() => store.state.position.projection) | ||
const opacity = computed(() => parentLayerOpacity.value ?? wmtsLayerConfig.value.opacity ?? 1.0) | ||
const currentYear = computed(() => wmtsLayerConfig.value.timeConfig?.currentYear) | ||
const url = computed(() => | ||
getWmtsXyzUrl(wmtsLayerConfig.value, projection.value, { | ||
addTimestamp: true, | ||
}) | ||
) | ||
const tileMatrixSet = computed(() => { | ||
if (!wmtsLayerConfig.value.tileMatrixSets) { | ||
return null | ||
} | ||
if ( | ||
!wmtsLayerConfig.value.tileMatrixSets.some( | ||
(set) => set.projection.epsg === projection.value.epsg | ||
) | ||
) { | ||
log.error( | ||
`External layer ${wmtsLayerConfig.value.id} does not support ${projection.value.epsg}` | ||
) | ||
store.dispatch('addLayerError', { | ||
layerId: wmtsLayerConfig.value.id, | ||
isExternal: wmtsLayerConfig.value.isExternal, | ||
baseUrl: wmtsLayerConfig.value.baseUrl, | ||
error: unsupportedProjectionError, | ||
...dispatcher, | ||
}) | ||
} | ||
return wmtsLayerConfig.value.tileMatrixSets | ||
}) | ||
const tileMatrixSetId = computed(() => tileMatrixSet.value?.id ?? projection.value.epsg) | ||
const tileMatrixLabels = computed(() => wmtsLayerConfig.value?.options?.tileGrid?.getMatrixIds()) | ||
watch(currentYear, () => { | ||
refreshLayer() | ||
}) | ||
onBeforeUnmount(() => { | ||
if (wmtsLayerConfig.value.containErrorMessage(unsupportedProjectionError)) { | ||
store.dispatch('removeLayerError', { | ||
layerId: wmtsLayerConfig.value.id, | ||
isExternal: wmtsLayerConfig.value.isExternal, | ||
baseUrl: wmtsLayerConfig.value.baseUrl, | ||
error: unsupportedProjectionError, | ||
...dispatcher, | ||
}) | ||
} | ||
}) | ||
function createProvider() { | ||
let provider | ||
if (wmtsLayerConfig.value instanceof ExternalWMTSLayer && tileMatrixSetId.value) { | ||
provider = new WebMapTileServiceImageryProvider({ | ||
url: | ||
wmtsLayerConfig.value.getTileEncoding === WMTSEncodingTypes.KVP | ||
? wmtsLayerConfig.value.baseUrl | ||
: wmtsLayerConfig.value.urlTemplate, | ||
layer: wmtsLayerConfig.value.id, | ||
style: wmtsLayerConfig.value.style, | ||
tileMatrixSetID: tileMatrixSetId.value, | ||
tileMatrixLabels: tileMatrixLabels.value, | ||
}) | ||
} else if (wmtsLayerConfig.value instanceof GeoAdminWMTSLayer) { | ||
provider = new UrlTemplateImageryProvider({ | ||
rectangle: Rectangle.fromDegrees(...DEFAULT_PROJECTION.getBoundsAs(WGS84).flatten), | ||
maximumLevel: MAXIMUM_LEVEL_OF_DETAILS, | ||
url: url.value, | ||
}) | ||
} else { | ||
log.error('Unknown WMTS layer type', wmtsLayerConfig.value, 'could not create 3D layer') | ||
} | ||
return provider | ||
} | ||
const { refreshLayer } = useAddImageryLayer( | ||
getViewer(), | ||
createProvider, | ||
toRef(zIndex), | ||
toRef(opacity) | ||
) | ||
</script> | ||
<template> | ||
<slot /> | ||
</template> |
Oops, something went wrong.