Skip to content

Commit dd8e2e3

Browse files
authored
Merge pull request #582 from geoadmin/bug_BGDIINF_SB-3214_fix_3d_zoom_in_out_buttons
BGDIINF_SB-3214 : add dedicated zoom in/out 3D buttons
2 parents df35795 + e117a75 commit dd8e2e3

File tree

4 files changed

+179
-87
lines changed

4 files changed

+179
-87
lines changed

src/modules/map/components/cesium/CesiumMap.vue

+14-15
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,14 @@
6666
<FeatureEdit v-if="editFeature" :read-only="true" :feature="editFeature" />
6767
<FeatureList direction="column" />
6868
</CesiumPopover>
69-
<cesium-compass v-show="isDesktopMode && !isFullScreenMode" ref="compass" class="compass" />
69+
<CesiumToolbox
70+
v-if="viewerCreated && isDesktopMode && !isFullScreenMode"
71+
class="cesium-toolbox position-absolute start-50 translate-middle-x"
72+
/>
7073
<slot />
7174
</div>
7275
</template>
7376
<script>
74-
import '@geoblocks/cesium-compass'
7577
import 'cesium/Build/Cesium/Widgets/widgets.css'
7678
7779
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
@@ -111,6 +113,7 @@ import FeatureEdit from '@/modules/infobox/components/FeatureEdit.vue'
111113
import FeatureList from '@/modules/infobox/components/FeatureList.vue'
112114
import CesiumInternalLayer from '@/modules/map/components/cesium/CesiumInternalLayer.vue'
113115
import CesiumPopover from '@/modules/map/components/cesium/CesiumPopover.vue'
116+
import CesiumToolbox from '@/modules/map/components/cesium/CesiumToolbox.vue'
114117
import {
115118
CAMERA_MAX_PITCH,
116119
CAMERA_MAX_ZOOM_DISTANCE,
@@ -135,7 +138,14 @@ import { identifyGeoJSONFeatureAt } from '@/utils/identifyOnVectorLayer'
135138
import log from '@/utils/logging'
136139
137140
export default {
138-
components: { FontAwesomeIcon, CesiumPopover, FeatureEdit, FeatureList, CesiumInternalLayer },
141+
components: {
142+
CesiumToolbox,
143+
FontAwesomeIcon,
144+
CesiumPopover,
145+
FeatureEdit,
146+
FeatureList,
147+
CesiumInternalLayer,
148+
},
139149
provide() {
140150
return {
141151
// sharing cesium viewer object with children components
@@ -327,10 +337,6 @@ export default {
327337
requestRenderMode: true,
328338
})
329339
330-
const compass = this.$refs.compass
331-
compass.scene = this.viewer.scene
332-
compass.clock = this.viewer.clock
333-
334340
const scene = this.viewer.scene
335341
scene.useDepthPicking = true
336342
scene.pickTranslucentDepth = true
@@ -564,15 +570,8 @@ export default {
564570
display: none !important;
565571
}
566572
567-
$compass-size: 95px;
568-
cesium-compass {
569-
position: absolute;
573+
.cesium-toolbox {
570574
bottom: $footer-height + $screen-padding-for-ui-elements;
571-
right: 50%;
572575
z-index: $zindex-map + 1;
573-
width: $compass-size;
574-
height: $compass-size;
575-
--cesium-compass-stroke-color: rgba(0, 0, 0, 0.6);
576-
--cesium-compass-fill-color: rgb(224, 225, 226);
577576
}
578577
</style>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<script setup>
2+
import '@geoblocks/cesium-compass'
3+
4+
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
5+
import { Ray } from 'cesium'
6+
import { computed, inject, onMounted, ref } from 'vue'
7+
import { useStore } from 'vuex'
8+
9+
import log from '@/utils/logging'
10+
11+
const compass = ref(null)
12+
13+
const store = useStore()
14+
15+
const isDesktopMode = computed(() => store.getters.isDesktopMode)
16+
const resolution = computed(() => store.getters.resolution)
17+
18+
const getViewer = inject('getViewer')
19+
20+
const viewer = getViewer()
21+
22+
onMounted(() => {
23+
if (viewer) {
24+
compass.value.scene = viewer.scene
25+
compass.value.clock = viewer.clock
26+
} else {
27+
log.error('No Cesium viewer found, could not link compass')
28+
}
29+
})
30+
31+
const resolutionRatioForZoomInOut = 200
32+
const step = computed(() => resolution.value * resolutionRatioForZoomInOut)
33+
34+
function moveCamera(distance) {
35+
const camera = viewer.scene.camera
36+
if (camera) {
37+
camera.flyTo({
38+
destination: Ray.getPoint(new Ray(camera.position, camera.direction), distance),
39+
orientation: {
40+
heading: camera.heading,
41+
pitch: camera.pitch,
42+
roll: camera.roll,
43+
},
44+
duration: 0.25,
45+
})
46+
}
47+
}
48+
49+
function moveForward() {
50+
moveCamera(step.value)
51+
}
52+
53+
function moveBackward() {
54+
moveCamera(-step.value)
55+
}
56+
</script>
57+
58+
<template>
59+
<div class="cesium-toolbox">
60+
<button class="cesium-toolbox-button" @click="moveForward">
61+
<FontAwesomeIcon icon="plus" />
62+
</button>
63+
<cesium-compass v-show="isDesktopMode" ref="compass" class="cesium-toolbox-compass" />
64+
<button class="cesium-toolbox-button" @click="moveBackward">
65+
<FontAwesomeIcon icon="minus" />
66+
</button>
67+
</div>
68+
</template>
69+
70+
<style lang="scss" scoped>
71+
@import 'src/scss/webmapviewer-bootstrap-theme';
72+
73+
.cesium-toolbox {
74+
display: flex;
75+
76+
$compass-size: 95px;
77+
$button-size: $compass-size / 2;
78+
&-button {
79+
width: $button-size;
80+
height: $button-size;
81+
border-radius: $button-size / 2;
82+
border: 2px solid rgba(0, 0, 0, 0.4);
83+
background: rgb(224, 225, 226);
84+
font-size: $button-size / 2.5;
85+
color: rgba(0, 0, 0, 0.8);
86+
}
87+
88+
&-compass {
89+
position: relative;
90+
width: $compass-size;
91+
height: $compass-size;
92+
--cesium-compass-stroke-color: rgba(0, 0, 0, 0.6);
93+
--cesium-compass-fill-color: rgb(224, 225, 226);
94+
}
95+
}
96+
</style>

src/modules/menu/MenuModule.vue

+64-71
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,63 @@
1+
<script setup>
2+
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
3+
import { computed, ref, watch } from 'vue'
4+
import { useI18n } from 'vue-i18n'
5+
import { useStore } from 'vuex'
6+
7+
import BlackBackdrop from '@/modules/menu/components/BlackBackdrop.vue'
8+
import DebugToolbar from '@/modules/menu/components/debug/DebugToolbar.vue'
9+
import HeaderWithSearch from '@/modules/menu/components/header/HeaderWithSearch.vue'
10+
import MenuTray from '@/modules/menu/components/menu/MenuTray.vue'
11+
import TimeSlider from '@/modules/menu/components/timeslider/TimeSlider.vue'
12+
import FullScreenButton from '@/modules/menu/components/toolboxRight/FullScreenButton.vue'
13+
import GeolocButton from '@/modules/menu/components/toolboxRight/GeolocButton.vue'
14+
import TimeSliderButton from '@/modules/menu/components/toolboxRight/TimeSliderButton.vue'
15+
import Toggle3dButton from '@/modules/menu/components/toolboxRight/Toggle3dButton.vue'
16+
import ZoomButtons from '@/modules/menu/components/toolboxRight/ZoomButtons.vue'
17+
18+
const showTimeSlider = ref(false)
19+
20+
const i18n = useI18n()
21+
const store = useStore()
22+
23+
const isGeolocationActive = computed(() => store.state.geolocation.active)
24+
const isGeolocationDenied = computed(() => store.state.geolocation.denied)
25+
const showMenu = computed(() => store.state.ui.showMenu)
26+
const isFullscreenMode = computed(() => store.state.ui.fullscreenMode)
27+
const isEmbedded = computed(() => store.state.ui.embeddedMode)
28+
const previewYear = computed(() => store.state.layers.previewYear)
29+
const inDrawingMode = computed(() => store.state.ui.showDrawingOverlay)
30+
const is3dActive = computed(() => store.state.cesium.active)
31+
32+
const isHeaderShown = computed(() => store.getters.isHeaderShown)
33+
const isPhoneMode = computed(() => store.getters.isPhoneMode)
34+
const isDesktopMode = computed(() => store.getters.isDesktopMode)
35+
const isMenuShown = computed(() => store.getters.isMenuShown)
36+
const isMenuTrayShown = computed(() => store.getters.isMenuTrayShown)
37+
const hasDevSiteWarning = computed(() => store.getters.hasDevSiteWarning)
38+
const visibleLayersWithTimeConfig = computed(() => store.getters.visibleLayersWithTimeConfig)
39+
40+
watch(previewYear, () => {
41+
// hiding the time slider if the preview has been cleared
42+
if (!previewYear.value) {
43+
showTimeSlider.value = false
44+
}
45+
})
46+
47+
function toggleGeolocation() {
48+
store.dispatch('toggleGeolocation')
49+
}
50+
function increaseZoom() {
51+
store.dispatch('increaseZoom')
52+
}
53+
function decreaseZoom() {
54+
store.dispatch('decreaseZoom')
55+
}
56+
function toggleMenu() {
57+
store.dispatch('toggleMenu')
58+
}
59+
</script>
60+
161
<template>
262
<div class="menu position-absolute w-100 h-100 start-0 top-0 pe-none">
363
<!-- In order to place the drawing toolbox correctly (so that zoom/geolocation button are under, etc...)
@@ -33,7 +93,7 @@
3393
@click="toggleGeolocation"
3494
/>
3595
<ZoomButtons
36-
v-if="!isFullscreenMode"
96+
v-if="!isFullscreenMode && !is3dActive"
3797
@zoom-in="increaseZoom"
3898
@zoom-out="decreaseZoom"
3999
/>
@@ -75,83 +135,16 @@
75135
@click="toggleMenu"
76136
>
77137
<FontAwesomeIcon :icon="showMenu ? 'caret-up' : 'caret-down'" />
78-
<span class="ms-1">{{ $t(showMenu ? 'close_menu' : 'open_menu') }}</span>
138+
<span class="ms-1">{{
139+
i18n.t(showMenu ? 'close_menu' : 'open_menu')
140+
}}</span>
79141
</button>
80142
</div>
81143
</transition>
82144
</div>
83145
</div>
84146
</template>
85147

86-
<script>
87-
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
88-
import { mapActions, mapGetters, mapState } from 'vuex'
89-
90-
import BlackBackdrop from '@/modules/menu/components/BlackBackdrop.vue'
91-
import DebugToolbar from '@/modules/menu/components/debug/DebugToolbar.vue'
92-
import HeaderWithSearch from '@/modules/menu/components/header/HeaderWithSearch.vue'
93-
import MenuTray from '@/modules/menu/components/menu/MenuTray.vue'
94-
import TimeSlider from '@/modules/menu/components/timeslider/TimeSlider.vue'
95-
import FullScreenButton from '@/modules/menu/components/toolboxRight/FullScreenButton.vue'
96-
import GeolocButton from '@/modules/menu/components/toolboxRight/GeolocButton.vue'
97-
import TimeSliderButton from '@/modules/menu/components/toolboxRight/TimeSliderButton.vue'
98-
import Toggle3dButton from '@/modules/menu/components/toolboxRight/Toggle3dButton.vue'
99-
import ZoomButtons from '@/modules/menu/components/toolboxRight/ZoomButtons.vue'
100-
101-
export default {
102-
components: {
103-
FullScreenButton,
104-
DebugToolbar,
105-
Toggle3dButton,
106-
FontAwesomeIcon,
107-
TimeSlider,
108-
TimeSliderButton,
109-
HeaderWithSearch,
110-
BlackBackdrop,
111-
ZoomButtons,
112-
GeolocButton,
113-
MenuTray,
114-
},
115-
data() {
116-
return {
117-
showTimeSlider: false,
118-
}
119-
},
120-
computed: {
121-
...mapState({
122-
isGeolocationActive: (state) => state.geolocation.active,
123-
isGeolocationDenied: (state) => state.geolocation.denied,
124-
showMenu: (state) => state.ui.showMenu,
125-
isFullscreenMode: (state) => state.ui.fullscreenMode,
126-
isEmbedded: (state) => state.ui.embeddedMode,
127-
previewYear: (state) => state.layers.previewYear,
128-
inDrawingMode: (state) => state.ui.showDrawingOverlay,
129-
}),
130-
...mapGetters([
131-
'isHeaderShown',
132-
'isPhoneMode',
133-
'isDesktopMode',
134-
'isMenuShown',
135-
'isMenuTrayShown',
136-
'hasDevSiteWarning',
137-
'visibleLayers',
138-
'visibleLayersWithTimeConfig',
139-
]),
140-
},
141-
watch: {
142-
previewYear() {
143-
// hiding the time slider if the preview has been cleared
144-
if (!this.previewYear) {
145-
this.showTimeSlider = false
146-
}
147-
},
148-
},
149-
methods: {
150-
...mapActions(['toggleGeolocation', 'increaseZoom', 'decreaseZoom', 'toggleMenu']),
151-
},
152-
}
153-
</script>
154-
155148
<style lang="scss" scoped>
156149
@import 'src/scss/media-query.mixin';
157150
@import 'src/scss/variables';

src/store/plugins/sync-camera-lonlatzoom.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import { WGS84 } from '@/utils/coordinates/coordinateSystems'
1111
*/
1212
export default function syncCameraLonLatZoom(store) {
1313
store.subscribe((mutation, state) => {
14-
if (mutation.type === 'setCameraPosition' && state.position.camera !== null) {
14+
// only reacting to mutation when the camera is set (when 3D is active and loaded)
15+
if (state.position.camera === null) {
16+
return
17+
}
18+
if (mutation.type === 'setCameraPosition') {
1519
const lon = parseFloat(state.position.camera.x)
1620
const lat = parseFloat(state.position.camera.y)
1721
const height = parseFloat(state.position.camera.z)

0 commit comments

Comments
 (0)