Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PB-1212: Allow delete last point by button when on line editing mode. #1138

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
12 changes: 8 additions & 4 deletions src/modules/drawing/DrawingModule.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ const activeKmlLayer = computed(() => store.getters.activeKmlLayer)
const featureIds = computed(() => store.state.drawing.featureIds)
const isDrawingEmpty = computed(() => store.getters.isDrawingEmpty)
const noFeatureInfo = computed(() => store.getters.noFeatureInfo)
const currentDrawingMode = computed(() => store.state.drawing.mode)
const online = computed(() => store.state.drawing.online)
const selectedEditableFeatures = computed(() => store.state.features.selectedEditableFeatures)
const selectedLineString = computed(() => {
const selectedLineFeature = computed(() => {
if (selectedEditableFeatures.value && selectedEditableFeatures.value.length > 0) {
const selectedFeature = selectedEditableFeatures.value[0]
if (
Expand All @@ -50,7 +51,7 @@ const selectedLineString = computed(() => {
return null
})
const showAddVertexButton = computed(() => {
return store.state.drawing.editingMode === EditMode.MODIFY && !!selectedLineString.value
return store.state.drawing.editingMode === EditMode.MODIFY && !!selectedLineFeature.value
})

const hasKml = computed(() => {
Expand Down Expand Up @@ -200,7 +201,10 @@ function createSourceForProjection() {
})
}
function removeLastPoint() {
drawingInteractions.value.removeLastPoint()
// Only active on drawing mode
if (currentDrawingMode.value) {
drawingInteractions.value.removeLastPoint()
}
}

function removeLastPointOnDeleteKeyUp(event) {
Expand Down Expand Up @@ -242,7 +246,7 @@ async function closeDrawing() {
<DrawingInteractions ref="drawingInteractions" />
<AddVertexButtonOverlay
v-if="showAddVertexButton"
:line-string="selectedLineString.geometry"
:coordinates="selectedLineFeature.geometry.coordinates"
/>
</div>
</template>
4 changes: 1 addition & 3 deletions src/modules/drawing/components/AddVertexButton.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<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'
Expand All @@ -24,7 +23,6 @@ const emit = defineEmits(['button-mounted'])

const buttonRef = ref(null)

const i18n = useI18n()
const store = useStore()

useTippyTooltip('#addVertexButton [data-tippy-content]', { placement: 'left' })
Expand All @@ -47,7 +45,7 @@ function addVertex() {
<div id="addVertexButton" ref="buttonRef">
<button
class="overlay-button d-print-none"
:data-tippy-content="i18n.t(props.tooltipText)"
:data-tippy-content="props.tooltipText"
@click="addVertex"
>
<font-awesome-icon :icon="['fas', 'plus']" />
Expand Down
41 changes: 29 additions & 12 deletions src/modules/drawing/components/AddVertexButtonOverlay.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script setup>
import { LineString } from 'ol/geom'
import Overlay from 'ol/Overlay'
import { computed, onMounted, ref, watch } from 'vue'
import { inject } from 'vue'
Expand All @@ -8,15 +7,23 @@ import { useStore } from 'vuex'

import AddVertexButton from '@/modules/drawing/components/AddVertexButton.vue'

const BASE_OFFSET_DISTANCE = 35
const MEASURE_ADDITIONAL_OFFSET = 40 // additional offset for not covering the measure line label

const props = defineProps({
lineString: {
type: LineString,
coordinates: {
type: Array,
required: true,
validator: (value) => {
return (
Array.isArray(value) &&
value.length >= 2 &&
value.every((coord) => Array.isArray(coord) && coord.length === 2)
)
},
},
})

const coordinates = computed(() => props.lineString.coordinates)

const olMap = inject('olMap')

const firstButtonOverlay = ref(null)
Expand All @@ -26,6 +33,7 @@ const firstButtonCoordinate = ref(null)
const lastButtonCoordinate = ref(null)

const store = useStore()
const coordinates = computed(() => props.coordinates)
const selectedEditableFeatures = computed(() => store.state.features.selectedEditableFeatures)
const selectedFeatureType = computed(() => {
if (selectedEditableFeatures.value && selectedEditableFeatures.value.length > 0) {
Expand Down Expand Up @@ -61,12 +69,13 @@ const updateButtonPositions = () => {
firstButtonCoordinate.value = coords[0]
lastButtonCoordinate.value = coords[coords.length - 1]

let distance = 35
const firstOffset = calculateOffset(coords[0], coords[1], distance)
const firstOffset = calculateOffset(coords[0], coords[1], BASE_OFFSET_DISTANCE)

// adding this so that the button is not on top of the measure line label
if (selectedFeatureType.value === 'MEASURE') {
distance = distance + 40
}
const distance =
selectedFeatureType.value === 'MEASURE'
? BASE_OFFSET_DISTANCE + MEASURE_ADDITIONAL_OFFSET
: BASE_OFFSET_DISTANCE
const lastOffset = calculateOffset(
coords[coords.length - 1],
coords[coords.length - 2],
Expand Down Expand Up @@ -120,6 +129,14 @@ onUnmounted(() => {
</script>

<template>
<AddVertexButton :reverse="true" @button-mounted="onFirstButtonMounted" />
<AddVertexButton :reverse="false" @button-mounted="onLastButtonMounted" />
<AddVertexButton
:reverse="true"
data-cy="extend-from-first-node-button"
@button-mounted="onFirstButtonMounted"
/>
<AddVertexButton
:reverse="false"
data-cy="extend-from-last-node-button"
@button-mounted="onLastButtonMounted"
/>
</template>
1 change: 1 addition & 0 deletions src/modules/drawing/components/DrawingInteractions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ function removeLastPoint() {
if (currentInteraction.value?.removeLastPoint) {
currentInteraction.value.removeLastPoint()
}
selectInteraction.value.removeLastPoint()
}
defineExpose({
removeLastPoint,
Expand Down
3 changes: 2 additions & 1 deletion src/modules/drawing/components/DrawingSelectInteraction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const selectInteraction = new SelectInteraction({
// to select. We will try to add a bigger hit tolerance to mitigate that.
hitTolerance: DRAWING_HIT_TOLERANCE,
})
useModifyInteraction(selectInteraction.getFeatures())
const { removeLastPoint } = useModifyInteraction(selectInteraction.getFeatures())

/** OpenLayers feature currently selected */
const currentlySelectedFeature = ref(null)
Expand Down Expand Up @@ -116,6 +116,7 @@ function selectFeature(feature) {

defineExpose({
selectFeature,
removeLastPoint,
})
</script>

Expand Down
31 changes: 30 additions & 1 deletion src/modules/drawing/components/DrawingToolbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import DrawingToolboxButton from '@/modules/drawing/components/DrawingToolboxBut
import SharePopup from '@/modules/drawing/components/SharePopup.vue'
import { DrawingState } from '@/modules/drawing/lib/export-utils'
import useSaveKmlOnChange from '@/modules/drawing/useKmlDataManagement.composable'
import { EditMode } from '@/store/modules/drawing.store'
import ModalWithBackdrop from '@/utils/components/ModalWithBackdrop.vue'
import { useTippyTooltip } from '@/utils/composables/useTippyTooltip'
import debounce from '@/utils/debounce'
Expand All @@ -38,6 +39,31 @@ const isDrawingLineOrMeasure = computed(() =>
currentDrawingMode.value
)
)
const selectedEditableFeatures = computed(() => store.state.features.selectedEditableFeatures)
const selectedLineString = computed(() => {
return selectedEditableFeatures.value.find((feature) => {
return (
feature.geometry.type === 'LineString' &&
[EditableFeatureTypes.LINEPOLYGON, EditableFeatureTypes.MEASURE].includes(
feature.featureType
)
)
})
})

const selectedLineCoordinates = computed(() => {
if (selectedLineString.value) {
return selectedLineString.value.geometry.coordinates
}
return null
})
const editMode = computed(() => store.state.drawing.editingMode)
const isAllowDeletePointOnSelectedLine = computed(
() =>
editMode.value !== EditMode.OFF &&
selectedLineString.value &&
selectedLineCoordinates.value?.length > 2
)
const activeKmlLayer = computed(() => store.getters.activeKmlLayer)
const drawingName = computed({
get: () => store.state.drawing.name,
Expand Down Expand Up @@ -208,7 +234,10 @@ const debounceSaveDrawingName = debounce(async (newName) => {
</button>
</div>
</div>
<div v-if="isDrawingLineOrMeasure" class="row mt-2">
<div
v-if="isDrawingLineOrMeasure || isAllowDeletePointOnSelectedLine"
class="row mt-2"
>
<div class="col d-grid">
<button
data-cy="drawing-delete-last-point-button"
Expand Down
30 changes: 26 additions & 4 deletions src/modules/drawing/components/useModifyInteraction.composable.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default function useModifyInteraction(features) {
)

const olMap = inject('olMap')
let rightClickDeleteActive = false // to make sure only one listener is active
const { willModify, debounceSaveDrawing } = useSaveKmlOnChange()

const modifyInteraction = new ModifyInteraction({
Expand Down Expand Up @@ -84,15 +85,15 @@ export default function useModifyInteraction(features) {
continueDrawingInteraction.extend(selectedFeature)
continueDrawingInteraction.setActive(true)
modifyInteraction.setActive(false)
olMap.on('contextmenu', onMapRightClick)
activateRightClickDelete()
} else if (newValue === EditMode.MODIFY) {
modifyInteraction.setActive(true)
continueDrawingInteraction.setActive(false)
olMap.on('contextmenu', onMapRightClick) // Keep right-click listener
activateRightClickDelete()
} else {
modifyInteraction.setActive(true)
continueDrawingInteraction.setActive(false)
olMap.un('contextmenu', onMapRightClick)
deactivateRightClickDelete()
}
},
{ immediate: true }
Expand All @@ -114,9 +115,26 @@ export default function useModifyInteraction(features) {
modifyInteraction.un('modifyend', onModifyEnd)
modifyInteraction.un('modifystart', onModifyStart)
continueDrawingInteraction.un('drawend', onExtendEnd)
deactivateRightClickDelete()
})

function onMapRightClick(_event) {
function activateRightClickDelete() {
if (rightClickDeleteActive) {
return
}
olMap.on('contextmenu', removeLastPoint)
rightClickDeleteActive = true
}

function deactivateRightClickDelete() {
olMap.un('contextmenu', removeLastPoint)
rightClickDeleteActive = false
}

function removeLastPoint() {
if (editMode.value === EditMode.OFF) {
return
}
if (continueDrawingInteraction.getActive()) {
continueDrawingInteraction.removeLastPoint()
} else if (modifyInteraction.getActive() && features.getArray().length > 0) {
Expand Down Expand Up @@ -195,4 +213,8 @@ export default function useModifyInteraction(features) {
...dispatcher,
})
}

return {
removeLastPoint,
}
}
53 changes: 53 additions & 0 deletions tests/cypress/tests-e2e/drawing.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ describe('Drawing module tests', () => {
.its('request')
.should((request) => checkKMLRequest(request, [new RegExp(`${regexExpression}`)]))
}

// Check that the linestring has the expected number of points
// Only works for line string drawing
function checkLinestringNumberOfPoints(numberOfPoints) {
cy.readWindowValue('drawingLayer')
.then((drawingLayer) => drawingLayer.getSource().getFeatures())
.should((features) => {
expect(features).to.be.an('Array').lengthOf(1)
const [feature] = features
const lineStringCoordinates = feature.getGeometry().getCoordinates()
expect(lineStringCoordinates).to.be.an('Array').lengthOf(numberOfPoints)
})
}
beforeEach(() => {
cy.goToDrawing()
})
Expand Down Expand Up @@ -545,6 +558,46 @@ describe('Drawing module tests', () => {
cy.wait(250)
readCoordinateClipboard('feature-detail-coordinate-copy', "2'660'013.50, 1'185'172.00")
})
it('can create line, extend it, and delete the last node by right click', () => {
cy.viewport(1920, 1080)
cy.clickDrawingTool(EditableFeatureTypes.LINEPOLYGON)

const lineCoordinates = [
[500, 500],
[550, 550],
[600, 600],
[700, 600],
[800, 600],
[800, 400],
[900, 400],
[1000, 400],
]
lineCoordinates.forEach((coordinate) => {
cy.get('[data-cy="ol-map"]').click(...coordinate)
})
// should create a line by re-clicking the last point
cy.get('[data-cy="ol-map"]').click(...lineCoordinates.at(lineCoordinates.length - 1))
checkLinestringNumberOfPoints(8)

// Extend from the last node of line
cy.get('[data-cy="extend-from-last-node-button"]').click()
cy.get('[data-cy="ol-map"]').click(1100, 450)
// finish extending the line by clicking the last point
cy.get('[data-cy="ol-map"]').click(1100, 450)
checkLinestringNumberOfPoints(9)

// Extend from the first node of line
cy.get('[data-cy="extend-from-first-node-button"]').click()
cy.get('[data-cy="ol-map"]').click(500, 450)
cy.get('[data-cy="ol-map"]').click(600, 450)
// finish extending the line by clicking the last point
cy.get('[data-cy="ol-map"]').click(600, 450)
checkLinestringNumberOfPoints(11)

// Delete the last node by right click
cy.get('[data-cy="ol-map"]').rightclick()
checkLinestringNumberOfPoints(10)
})
it('can create line/polygons and edit them', () => {
cy.clickDrawingTool(EditableFeatureTypes.LINEPOLYGON)
cy.get('[data-cy="ol-map"]').click(100, 250)
Expand Down
Loading