Skip to content

Commit

Permalink
Merge pull request #881 from geoadmin/bug_PB-548_camera_after_reload
Browse files Browse the repository at this point in the history
PB-548 : fix camera position present in URL at startup issue
  • Loading branch information
pakb authored Jun 10, 2024
2 parents 31f1333 + f4cd7e5 commit 9cdb807
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 58 deletions.
69 changes: 49 additions & 20 deletions src/modules/map/components/cesium/CesiumMap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export default {
data() {
return {
viewerCreated: false,
cameraInitialized: false,
popoverCoordinates: [],
}
},
Expand Down Expand Up @@ -246,13 +247,12 @@ export default {
// see https://vuejs.org/guide/essentials/watchers.html#callback-flush-timing
flush: 'post',
},
centerEpsg4326: {
cameraPosition: {
handler() {
if (this.isProjectionWebMercator && this.cameraPosition) {
this.flyToPosition()
}
this.flyToPosition()
},
flush: 'post',
deep: true,
},
},
beforeCreate() {
Expand Down Expand Up @@ -400,14 +400,13 @@ export default {
this.viewer.scene.postRender.addEventListener(
limitCameraPitchRoll(CAMERA_MIN_PITCH, CAMERA_MAX_PITCH, 0.0, 0.0)
)
this.initCamera()
if (this.$refs.compass) {
this.$refs.compass.scene = this.viewer.scene
this.$refs.compass.clock = this.viewer.clock
}
this.flyToPosition()
if (this.selectedFeatures.length > 0) {
this.highlightSelectedFeatures()
}
Expand Down Expand Up @@ -445,6 +444,50 @@ export default {
? firstFeature.coordinates[firstFeature.coordinates.length - 1]
: firstFeature.coordinates
},
initCamera() {
if (this.cameraInitialized) {
return
}
let destination
let orientation
if (this.cameraPosition) {
// a camera position was already define in the URL, we use it
log.debug('Existing camera position found at startup, using', this.cameraPosition)
destination = Cartesian3.fromDegrees(
this.cameraPosition.x,
this.cameraPosition.y,
this.cameraPosition.z
)
orientation = {
heading: CesiumMath.toRadians(this.cameraPosition.heading),
pitch: CesiumMath.toRadians(this.cameraPosition.pitch),
roll: CesiumMath.toRadians(this.cameraPosition.roll),
}
} else {
// no camera position was ever calculated, so we create one using the 2D coordinates
log.debug(
'No camera position defined, creating one using 2D coordinates',
this.centerEpsg4326
)
destination = Cartesian3.fromDegrees(
this.centerEpsg4326[0],
this.centerEpsg4326[1],
calculateHeight(this.resolution, this.viewer.canvas.clientWidth)
)
orientation = {
heading: -CesiumMath.toRadians(this.rotation),
pitch: -CesiumMath.PI_OVER_TWO,
roll: 0,
}
}
this.viewer.camera.flyTo({
destination,
orientation,
duration: 0,
})
this.cameraInitialized = true
},
flyToPosition() {
try {
if (this.cameraPosition) {
Expand All @@ -461,20 +504,6 @@ export default {
},
duration: 1,
})
} else {
this.viewer.camera.flyTo({
destination: Cartesian3.fromDegrees(
this.centerEpsg4326[0],
this.centerEpsg4326[1],
calculateHeight(this.resolution, this.viewer.canvas.clientWidth)
),
orientation: {
heading: -CesiumMath.toRadians(this.rotation),
pitch: -CesiumMath.PI_OVER_TWO,
roll: 0,
},
duration: 0,
})
}
} catch (error) {
log.error('Error while moving the camera', error, this.cameraPosition)
Expand Down
17 changes: 10 additions & 7 deletions src/router/legacyPermalinkManagement.routerPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ const handleLegacyParams = async (legacyParams, store, originView) => {
const { projection } = store.state.position
let legacyCoordinates = []
let latlongCoordinates = []
let cameraPosition = []
let cameraPosition = [null, null, null, null, null, null]

legacyParams.forEach((param_value, param_key) => {
handleLegacyParam(
Expand All @@ -179,9 +179,12 @@ const handleLegacyParams = async (legacyParams, store, originView) => {
cameraPosition
)
})
if (cameraPosition.length >= 3) {
cameraPosition.push('')
newQuery['camera'] = cameraPosition.join(',')
if (cameraPosition.filter((value) => value !== null).length >= 3) {
// if no pitch is set, we look down to the ground instead of letting no value (0, looking at the horizon) go through
if (cameraPosition[3] === null) {
cameraPosition[3] = -90
}
newQuery['camera'] = cameraPosition.map((value) => value ?? '').join(',')
newQuery['3d'] = true
newQuery['sr'] = WEBMERCATOR.epsgNumber

Expand All @@ -206,8 +209,8 @@ const handleLegacyParams = async (legacyParams, store, originView) => {
}

// if a legacy coordinate (x/y, N/E or lon/lat) was used, we need to build the
// center param from them
if (legacyCoordinates.length === 2) {
// center param from them (only if the 3D camera isn't set too)
if (legacyCoordinates.length === 2 && !newQuery['camera']) {
newQuery['center'] = legacyCoordinates.join(',')
}

Expand Down Expand Up @@ -301,7 +304,7 @@ const legacyPermalinkManagementRouterPlugin = (router, store) => {
// legacy params some data are required (e.g. the layer config)
if (mutation.type === 'setAppIsReady') {
log.debug(
'[Legacy URL] app is ready, handle legacy params=${legacyParams.toString()}',
`[Legacy URL] app is ready, handle legacy params=${legacyParams.toString()}`,
legacyParams
)
const newRoute = await handleLegacyParams(
Expand Down
2 changes: 1 addition & 1 deletion src/router/storeSync/PositionParamConfig.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function dispatchCenterFromUrlIntoStore(to, store, urlParamValue) {
}

function generateCenterUrlParamFromStoreValues(store) {
if (store.state.position.center) {
if (store.state.position.center && !store.state.cesium.active) {
return store.state.position.center
.map((val) => store.state.position.projection.roundCoordinateValue(val))
.join(',')
Expand Down
3 changes: 3 additions & 0 deletions src/router/storeSync/ZoomParamConfig.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ function dispatchZoomFromUrlIntoStore(to, store, urlParamValue) {
}

function generateZoomUrlParamFromStoreValues(store) {
if (store.state.cesium.active) {
return null
}
return store.state.position.zoom
}

Expand Down
53 changes: 26 additions & 27 deletions src/store/plugins/sync-camera-lonlatzoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@/modules/map/components/cesium/utils/cameraUtils'
import { normalizeAngle } from '@/store/modules/position.store'
import { WGS84 } from '@/utils/coordinates/coordinateSystems'
import log from '@/utils/logging'

/**
* Plugin to synchronize the 3d camera position and orientation with the center and zoom.
Expand Down Expand Up @@ -45,32 +46,30 @@ export default function syncCameraLonLatZoom(store) {
store.dispatch('setZoom', { zoom, dispatcher: self })
store.dispatch('setRotation', normalizeAngle((rotation * Math.PI) / 180))
}
if (mutation.type === 'setCenter' && mutation.payload.dispatcher !== self) {
store.dispatch('setCameraPosition', {
position: {
x: store.getters.centerEpsg4326[0],
y: store.getters.centerEpsg4326[1],
z: state.position.camera.z,
heading: 0,
pitch: CesiumMath.toDegrees(-CesiumMath.PI_OVER_TWO),
roll: 0,
},
dispatcher: self,
})
}
if (mutation.type === 'setZoom' && mutation.payload.dispatcher !== self) {
const newHeight = calculateHeight(store.getters.resolution, state.ui.width)
store.dispatch('setCameraPosition', {
position: {
x: state.position.camera.x,
y: state.position.camera.y,
z: newHeight,
heading: 0,
pitch: CesiumMath.toDegrees(-CesiumMath.PI_OVER_TWO),
roll: 0,
},
dispatcher: self,
})
}
})
// Subscribing to action to listen to zoomToExtent and selectResultEntry specifically.
// This way we do not have to hook ourselves to setCenter and setZoom mutation, that are triggered
// way more often than extent actions - supporting extent camera positioning is what we are looking for.
store.subscribeAction({
after: (action, state) => {
if (state.position.camera === null) {
return
}
if (['zoomToExtent', 'selectResultEntry'].includes(action.type)) {
log.debug('Adapting camera position to match zoomToExtent/selectResultEntry')
const newHeight = calculateHeight(store.getters.resolution, state.ui.width)
store.dispatch('setCameraPosition', {
position: {
x: store.getters.centerEpsg4326[0],
y: store.getters.centerEpsg4326[1],
z: newHeight,
heading: 0,
pitch: CesiumMath.toDegrees(-CesiumMath.PI_OVER_TWO),
roll: 0,
},
dispatcher: self,
})
}
},
})
}
8 changes: 6 additions & 2 deletions tests/cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ const addFeatureIdentificationIntercepts = () => {
featureDetailTemplate = featureDetail.feature
})

cy.intercept('**identify**', (identifyRequest) => {
cy.intercept('**/MapServer/identify**', (identifyRequest) => {
lastIdentifiedFeatures = []

const {
Expand Down Expand Up @@ -310,7 +310,11 @@ Cypress.Commands.add(
if (!('lang' in queryParams)) {
queryParams.lang = 'en'
}
if (!('center' in queryParams) && !('3d' in queryParams)) {
if (
!['lat', 'lon', 'x', 'y', 'center', '3d'].some((unwantedKey) =>
Object.keys(queryParams).includes(unwantedKey)
)
) {
// "old" MAP_CENTER constant re-projected in LV95
queryParams.center = '2660013.5,1185172'
} else if ('3d' in queryParams && !('sr' in queryParams)) {
Expand Down
2 changes: 1 addition & 1 deletion tests/cypress/tests-e2e/legacyParamImport.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ describe('Test on legacy param import', () => {
cy.readStoreValue('state.position.camera.y').should('eq', lat)
cy.readStoreValue('state.position.camera.z').should('eq', 0)
cy.readStoreValue('state.position.camera.heading').should('eq', heading)
cy.readStoreValue('state.position.camera.pitch').should('eq', 0)
cy.readStoreValue('state.position.camera.pitch').should('eq', -90)
cy.readStoreValue('state.position.camera.roll').should('eq', 0)

// EPSG is set to 3857
Expand Down

0 comments on commit 9cdb807

Please sign in to comment.