Skip to content

Commit

Permalink
Merge pull request #1129 from geoadmin/pb-199-add-new-point
Browse files Browse the repository at this point in the history
PB-199: add new point on an existing line
  • Loading branch information
pakb authored Nov 21, 2024
2 parents 519e8ca + d07f885 commit 86da74d
Show file tree
Hide file tree
Showing 11 changed files with 382 additions and 15 deletions.
35 changes: 34 additions & 1 deletion src/modules/drawing/DrawingModule.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import { computed, inject, onBeforeUnmount, onMounted, provide, ref, watch } fro
import { useI18n } from 'vue-i18n'
import { useStore } from 'vuex'
import { EditableFeatureTypes } from '@/api/features/EditableFeature.class'
import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config'
import AddVertexButtonOverlay from '@/modules/drawing/components/AddVertexButtonOverlay.vue'
import DrawingInteractions from '@/modules/drawing/components/DrawingInteractions.vue'
import DrawingToolbox from '@/modules/drawing/components/DrawingToolbox.vue'
import DrawingTooltip from '@/modules/drawing/components/DrawingTooltip.vue'
import { DrawingState } from '@/modules/drawing/lib/export-utils'
import useKmlDataManagement from '@/modules/drawing/useKmlDataManagement.composable'
import { EditMode } from '@/store/modules/drawing.store'
import { FeatureInfoPositions } from '@/store/modules/ui.store'
import { getIcon, parseIconUrl } from '@/utils/kmlUtils'
import log from '@/utils/logging'
Expand All @@ -32,6 +35,24 @@ const featureIds = computed(() => store.state.drawing.featureIds)
const isDrawingEmpty = computed(() => store.getters.isDrawingEmpty)
const noFeatureInfo = computed(() => store.getters.noFeatureInfo)
const online = computed(() => store.state.drawing.online)
const selectedEditableFeatures = computed(() => store.state.features.selectedEditableFeatures)
const selectedLineString = computed(() => {
if (selectedEditableFeatures.value && selectedEditableFeatures.value.length > 0) {
const selectedFeature = selectedEditableFeatures.value[0]
if (
selectedFeature.geometry.type === 'LineString' &&
(selectedFeature.featureType === EditableFeatureTypes.LINEPOLYGON ||
selectedFeature.featureType === EditableFeatureTypes.MEASURE)
) {
return selectedFeature
}
}
return null
})
const showAddVertexButton = computed(() => {
return store.state.drawing.editingMode === EditMode.MODIFY && !!selectedLineString.value
})
const hasKml = computed(() => {
if (online.value) {
return !!activeKmlLayer.value
Expand Down Expand Up @@ -107,7 +128,15 @@ watch(availableIconSets, () => {
}
})
})
watch(selectedEditableFeatures, (newValue) => {
if (newValue) {
if (store.state.drawing.editingMode === EditMode.OFF) {
store.dispatch('setEditingMode', { mode: EditMode.MODIFY, ...dispatcher })
}
} else {
store.dispatch('setEditingMode', { mode: EditMode.OFF, ...dispatcher })
}
})
onMounted(() => {
if (noFeatureInfo.value) {
// Left clicking while in drawing mode has its own logic not covered in click-on-map-management.plugin.js
Expand Down Expand Up @@ -211,5 +240,9 @@ async function closeDrawing() {
<DrawingToolbox @remove-last-point="removeLastPoint" @close-drawing="closeDrawing" />
<DrawingTooltip />
<DrawingInteractions ref="drawingInteractions" />
<AddVertexButtonOverlay
v-if="showAddVertexButton"
:line-string="selectedLineString.geometry"
/>
</div>
</template>
60 changes: 60 additions & 0 deletions src/modules/drawing/components/AddVertexButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<script setup>
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useStore } from 'vuex'
import { EditMode } from '@/store/modules/drawing.store'
import { useTippyTooltip } from '@/utils/composables/useTippyTooltip'
const dispatcher = { dispatcher: 'AddVertexButton.vue' }
const props = defineProps({
tooltipText: {
type: String,
default: 'modify_add_vertex',
},
// If true, the button will add a vertex in the reverse direction
reverse: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['button-mounted'])
const buttonRef = ref(null)
const i18n = useI18n()
const store = useStore()
useTippyTooltip('#addVertexButton [data-tippy-content]', { placement: 'left' })
onMounted(() => {
// Emit an event to notify the parent component that the button is mounted
emit('button-mounted', buttonRef.value)
})
function addVertex() {
store.dispatch('setEditingMode', {
mode: EditMode.EXTEND,
reverseLineStringExtension: props.reverse,
...dispatcher,
})
}
</script>

<template>
<div id="addVertexButton" ref="buttonRef">
<button
class="overlay-button d-print-none"
:data-tippy-content="i18n.t(props.tooltipText)"
@click="addVertex"
>
<font-awesome-icon :icon="['fas', 'plus']" />
</button>
</div>
</template>

<style lang="scss" scoped>
@import '@/modules/map/scss/toolbox-buttons';
</style>
125 changes: 125 additions & 0 deletions src/modules/drawing/components/AddVertexButtonOverlay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<script setup>
import { LineString } from 'ol/geom'
import Overlay from 'ol/Overlay'
import { computed, onMounted, ref, watch } from 'vue'
import { inject } from 'vue'
import { onUnmounted } from 'vue'
import { useStore } from 'vuex'
import AddVertexButton from '@/modules/drawing/components/AddVertexButton.vue'
const props = defineProps({
lineString: {
type: LineString,
required: true,
},
})
const coordinates = computed(() => props.lineString.coordinates)
const olMap = inject('olMap')
const firstButtonOverlay = ref(null)
const lastButtonOverlay = ref(null)
const firstButtonCoordinate = ref(null)
const lastButtonCoordinate = ref(null)
const store = useStore()
const selectedEditableFeatures = computed(() => store.state.features.selectedEditableFeatures)
const selectedFeatureType = computed(() => {
if (selectedEditableFeatures.value && selectedEditableFeatures.value.length > 0) {
const selectedFeature = selectedEditableFeatures.value[0]
return selectedFeature.featureType
}
return null
})
const calculateOffset = (point1, point2, distance) => {
if (!point1 || !point2) {
return [distance, -distance]
}
// Vector from point1 to point2
const dx = point2[0] - point1[0]
const dy = point2[1] - point1[1]
// Normalize the vector
const length = Math.sqrt(dx * dx + dy * dy)
if (length === 0) return [distance, -distance]
// Get unit vector in opposite direction
const ux = -dx / length
const uy = -dy / length
// There is minus in y-direction because the y-axis is inverted in the map
return [ux * distance, -uy * distance]
}
const updateButtonPositions = () => {
const coords = coordinates.value
firstButtonCoordinate.value = coords[0]
lastButtonCoordinate.value = coords[coords.length - 1]
let distance = 35
const firstOffset = calculateOffset(coords[0], coords[1], distance)
// adding this so that the button is not on top of the measure line label
if (selectedFeatureType.value === 'MEASURE') {
distance = distance + 40
}
const lastOffset = calculateOffset(
coords[coords.length - 1],
coords[coords.length - 2],
distance
)
if (firstButtonOverlay.value) {
firstButtonOverlay.value.setPosition(firstButtonCoordinate.value)
firstButtonOverlay.value.setOffset(firstOffset)
}
if (lastButtonOverlay.value) {
lastButtonOverlay.value.setPosition(lastButtonCoordinate.value)
lastButtonOverlay.value.setOffset(lastOffset)
}
}
const onFirstButtonMounted = (buttonElement) => {
firstButtonOverlay.value = new Overlay({
element: buttonElement,
positioning: 'center-center',
stopEvent: true,
})
olMap.addOverlay(firstButtonOverlay.value)
updateButtonPositions()
}
const onLastButtonMounted = (buttonElement) => {
lastButtonOverlay.value = new Overlay({
element: buttonElement,
positioning: 'center-center',
stopEvent: true,
})
olMap.addOverlay(lastButtonOverlay.value)
updateButtonPositions()
}
watch(coordinates, updateButtonPositions)
onMounted(() => {
updateButtonPositions()
})
onUnmounted(() => {
if (firstButtonOverlay.value) {
olMap.removeOverlay(firstButtonOverlay.value)
}
if (lastButtonOverlay.value) {
olMap.removeOverlay(lastButtonOverlay.value)
}
})
</script>

<template>
<AddVertexButton :reverse="true" @button-mounted="onFirstButtonMounted" />
<AddVertexButton :reverse="false" @button-mounted="onLastButtonMounted" />
</template>
Loading

0 comments on commit 86da74d

Please sign in to comment.