From dae9c7665fbcc2b208381e6b7fdf240f7d270de3 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Mon, 11 Nov 2024 15:14:35 +0700 Subject: [PATCH 01/29] PB-199: Add new point to the line on right click. --- .../useModifyInteraction.composable.js | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/modules/drawing/components/useModifyInteraction.composable.js b/src/modules/drawing/components/useModifyInteraction.composable.js index e29a027b33..818ff308d5 100644 --- a/src/modules/drawing/components/useModifyInteraction.composable.js +++ b/src/modules/drawing/components/useModifyInteraction.composable.js @@ -58,13 +58,51 @@ export default function useModifyInteraction(features) { modifyInteraction.on('modifystart', onModifyStart) modifyInteraction.on('modifyend', onModifyEnd) olMap.addInteraction(modifyInteraction) + olMap.on('contextmenu', onMapRightClick) }) onBeforeUnmount(() => { olMap.removeInteraction(modifyInteraction) modifyInteraction.un('modifyend', onModifyEnd) modifyInteraction.un('modifystart', onModifyStart) + olMap.un('contextmenu', onMapRightClick) }) + function onMapRightClick(event) { + const newCoordinate = olMap.getEventCoordinate(event.originalEvent) + + const [feature] = features.getArray() + + if (feature) { + const geometry = feature.getGeometry() + if (geometry.getType() === 'LineString') { + geometry.appendCoordinate(newCoordinate) + } else if (geometry.getType() === 'Polygon') { + const coordinates = geometry.getCoordinates() + coordinates[0].push(newCoordinate) + geometry.setCoordinates(coordinates) + } + + const storeFeature = feature.get('editableFeature') + store.dispatch('changeFeatureIsDragged', { + feature: storeFeature, + isDragged: false, + ...dispatcher, + }) + store.dispatch('changeFeatureCoordinates', { + feature: storeFeature, + coordinates: extractOlFeatureCoordinates(feature), + geodesicCoordinates: extractOlFeatureGeodesicCoordinates(feature), + ...dispatcher, + }) + store.dispatch('changeFeatureGeometry', { + feature: storeFeature, + geometry: new GeoJSON().writeGeometryObject(feature.getGeometry()), + }) + olMap.getTarget().classList.remove(cursorGrabbingClass) + debounceSaveDrawing() + } + } + function onModifyStart(event) { const [feature] = event.features.getArray() From 3ae57c9ddb00b128d0ea53be160ef6a6d97933aa Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Mon, 11 Nov 2024 15:41:15 +0700 Subject: [PATCH 02/29] PB-199: Add tooltip for right click to add new point. --- src/modules/drawing/components/DrawingTooltip.vue | 6 +++++- src/modules/i18n/locales/de.json | 1 + src/modules/i18n/locales/en.json | 1 + src/modules/i18n/locales/fr.json | 1 + src/modules/i18n/locales/it.json | 1 + src/modules/i18n/locales/rm.json | 1 + 6 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/modules/drawing/components/DrawingTooltip.vue b/src/modules/drawing/components/DrawingTooltip.vue index 7e89223e09..ec2af7c848 100644 --- a/src/modules/drawing/components/DrawingTooltip.vue +++ b/src/modules/drawing/components/DrawingTooltip.vue @@ -144,7 +144,11 @@ function onPointerMove(event) { translationKeys = 'select_no_feature' } } else { - translationKeys = 'select_no_feature' + if (hasFeatureSelected) { + translationKeys = ['select_no_feature', 'modify_add_vertex'] + } else { + translationKeys = 'select_no_feature' + } } } diff --git a/src/modules/i18n/locales/de.json b/src/modules/i18n/locales/de.json index 4c41a8bfac..520353291b 100644 --- a/src/modules/i18n/locales/de.json +++ b/src/modules/i18n/locales/de.json @@ -393,6 +393,7 @@ "meteoschweiz_service_link_href": "http://www.meteoschweiz.admin.ch", "meteoschweiz_service_link_label": "MeteoSchweiz", "mobile_redirect": "Mobile Version", + "modify_add_vertex": "Klicken Sie mit der rechten Maustaste, um dem ausgewählten Feature einen neuen Punkt hinzuzufügen", "modify_color_label": "Farbe", "modify_description": "Beschreibung", "modify_existing_vertex_annotation": "Verschieben von Text: klicken und ziehen ", diff --git a/src/modules/i18n/locales/en.json b/src/modules/i18n/locales/en.json index 7c08eaee94..fb9b381077 100644 --- a/src/modules/i18n/locales/en.json +++ b/src/modules/i18n/locales/en.json @@ -393,6 +393,7 @@ "meteoschweiz_service_link_href": "http://www.meteoswiss.admin.ch", "meteoschweiz_service_link_label": "MeteoSwiss", "mobile_redirect": "Mobile version", + "modify_add_vertex": "Right click to add new point to the selected feature", "modify_color_label": "Color", "modify_description": "Description", "modify_existing_vertex_annotation": "Click then drag to move the text", diff --git a/src/modules/i18n/locales/fr.json b/src/modules/i18n/locales/fr.json index c663855b79..6a04dead5e 100644 --- a/src/modules/i18n/locales/fr.json +++ b/src/modules/i18n/locales/fr.json @@ -393,6 +393,7 @@ "meteoschweiz_service_link_href": "http://www.meteosuisse.admin.ch", "meteoschweiz_service_link_label": "MeteoSuisse", "mobile_redirect": "Version mobile", + "modify_add_vertex": "Cliquez avec le bouton droit pour ajouter un nouveau point à l'entité sélectionnée", "modify_color_label": "Couleur", "modify_description": "Description", "modify_existing_vertex_annotation": "Cliquer puis bouger le curseur pour déplacer l'annotation", diff --git a/src/modules/i18n/locales/it.json b/src/modules/i18n/locales/it.json index 2632e18c37..1a9187f4ef 100644 --- a/src/modules/i18n/locales/it.json +++ b/src/modules/i18n/locales/it.json @@ -393,6 +393,7 @@ "meteoschweiz_service_link_href": "http://www.meteosvizzera.admin.ch", "meteoschweiz_service_link_label": "MeteoSvizzera", "mobile_redirect": "Versione mobile", + "modify_add_vertex": "Fare clic con il pulsante destro del mouse per aggiungere un nuovo punto alla feature selezionata", "modify_color_label": "Colore", "modify_description": "Descrizione", "modify_existing_vertex_annotation": "Cliccare quindi trascinare per spostare il testo", diff --git a/src/modules/i18n/locales/rm.json b/src/modules/i18n/locales/rm.json index 22293b3540..3259c25338 100644 --- a/src/modules/i18n/locales/rm.json +++ b/src/modules/i18n/locales/rm.json @@ -391,6 +391,7 @@ "meteoschweiz_service_link_href": "http://www.meteoschweiz.admin.ch", "meteoschweiz_service_link_label": "MeteoSvizra", "mobile_redirect": "Versiun mobila", + "modify_add_vertex": "Klikisar o ćaćutno kliko te thoves nevo punkto ki alosardi funkcia", "modify_color_label": "Colur", "modify_description": "Descripziun", "modify_existing_vertex_annotation": "Spustar text :cliccar e trair", From eb92d92c4469cd6a7a143b873dc084307487d54f Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Wed, 13 Nov 2024 15:13:17 +0700 Subject: [PATCH 03/29] PB-199: Add basic buttons for adding new vertex as an overlay. --- src/modules/drawing/DrawingModule.vue | 19 +++++ .../drawing/components/AddVertexButton.vue | 76 ++++++++++++++++++ .../components/AddVertexButtonOverlay.vue | 77 +++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 src/modules/drawing/components/AddVertexButton.vue create mode 100644 src/modules/drawing/components/AddVertexButtonOverlay.vue diff --git a/src/modules/drawing/DrawingModule.vue b/src/modules/drawing/DrawingModule.vue index 7a94ad7c58..79352099c4 100644 --- a/src/modules/drawing/DrawingModule.vue +++ b/src/modules/drawing/DrawingModule.vue @@ -6,6 +6,7 @@ import { useI18n } from 'vue-i18n' import { useStore } from 'vuex' 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' @@ -32,6 +33,20 @@ 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') { + return selectedFeature + } else { + return null + } + } else { + return null + } +}) + const hasKml = computed(() => { if (online.value) { return !!activeKmlLayer.value @@ -211,5 +226,9 @@ async function closeDrawing() { + diff --git a/src/modules/drawing/components/AddVertexButton.vue b/src/modules/drawing/components/AddVertexButton.vue new file mode 100644 index 0000000000..df5c9727cf --- /dev/null +++ b/src/modules/drawing/components/AddVertexButton.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/src/modules/drawing/components/AddVertexButtonOverlay.vue b/src/modules/drawing/components/AddVertexButtonOverlay.vue new file mode 100644 index 0000000000..a22b420407 --- /dev/null +++ b/src/modules/drawing/components/AddVertexButtonOverlay.vue @@ -0,0 +1,77 @@ + + + From 8169577d516f4265253513a8248aebbd9ff196c5 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Wed, 13 Nov 2024 15:58:02 +0700 Subject: [PATCH 04/29] PB-199: Use LineString instead Feature. --- src/modules/drawing/DrawingModule.vue | 2 +- .../drawing/components/AddVertexButton.vue | 16 ++++++++++++++++ .../components/AddVertexButtonOverlay.vue | 8 ++++---- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/modules/drawing/DrawingModule.vue b/src/modules/drawing/DrawingModule.vue index 79352099c4..7d874c21a0 100644 --- a/src/modules/drawing/DrawingModule.vue +++ b/src/modules/drawing/DrawingModule.vue @@ -228,7 +228,7 @@ async function closeDrawing() { diff --git a/src/modules/drawing/components/AddVertexButton.vue b/src/modules/drawing/components/AddVertexButton.vue index df5c9727cf..ed8659ccb1 100644 --- a/src/modules/drawing/components/AddVertexButton.vue +++ b/src/modules/drawing/components/AddVertexButton.vue @@ -40,6 +40,13 @@ onMounted(() => { z-index: 99; } +.btn { + background: none; + border: none; + padding: 0; + cursor: pointer; +} + .icon-circle { display: inline-block; width: 1.5rem; @@ -50,6 +57,15 @@ onMounted(() => { align-items: center; justify-content: center; border: 1px solid black; + transition: + background-color 0.3s, + border-color 0.3s; +} + +.btn:hover .icon-circle { + background-color: #e0e0e0; /* Darker background color */ + border-color: black; + font-weight: bold; } .tooltip { diff --git a/src/modules/drawing/components/AddVertexButtonOverlay.vue b/src/modules/drawing/components/AddVertexButtonOverlay.vue index a22b420407..26d4d8121b 100644 --- a/src/modules/drawing/components/AddVertexButtonOverlay.vue +++ b/src/modules/drawing/components/AddVertexButtonOverlay.vue @@ -1,5 +1,5 @@ - diff --git a/src/modules/drawing/components/AddVertexButtonOverlay.vue b/src/modules/drawing/components/AddVertexButtonOverlay.vue index 26d4d8121b..f555fb1c1d 100644 --- a/src/modules/drawing/components/AddVertexButtonOverlay.vue +++ b/src/modules/drawing/components/AddVertexButtonOverlay.vue @@ -39,7 +39,7 @@ const onFirstButtonMounted = (buttonElement) => { element: buttonElement, positioning: 'center-center', stopEvent: true, - // offset: [-50, -50], // TODO: make this dynamic according to the next point + offset: [-25, -25], // TODO: make this dynamic according to the next point }) olMap.addOverlay(firstButtonOverlay.value) updateButtonPositions() @@ -50,7 +50,7 @@ const onLastButtonMounted = (buttonElement) => { element: buttonElement, positioning: 'center-center', stopEvent: true, - // offset: [-50, -50], // TODO: make this dynamic according to the next point + offset: [-25, -25], // TODO: make this dynamic according to the next point }) olMap.addOverlay(lastButtonOverlay.value) updateButtonPositions() From 7569ce237c011306e4ac2641050d8faf95c09cd8 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Mon, 18 Nov 2024 10:41:46 +0700 Subject: [PATCH 06/29] PB-199: Implement extend line string. --- src/api/features/EditableFeature.class.js | 40 ++++++++++++++++++- .../drawing/components/AddVertexButton.vue | 6 ++- .../useDrawingModeInteraction.composable.js | 29 +++++++++++++- src/store/modules/features.store.js | 2 +- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/api/features/EditableFeature.class.js b/src/api/features/EditableFeature.class.js index 989eac4c9e..4bc31dd484 100644 --- a/src/api/features/EditableFeature.class.js +++ b/src/api/features/EditableFeature.class.js @@ -1,4 +1,6 @@ -import { Icon as olIcon } from 'ol/style' +import { Feature } from 'ol' +import { LineString } from 'ol/geom' +import { Icon as olIcon, Stroke, Style } from 'ol/style' import { extractOlFeatureGeodesicCoordinates } from '@/api/features/features.api' import SelectableFeature from '@/api/features/SelectableFeature.class' @@ -218,4 +220,40 @@ export default class EditableFeature extends SelectableFeature { set geodesicCoordinates(coordinates) { this._geodesicCoordinates = coordinates } + + /** + * Converts this EditableFeature to an OpenLayers Feature + * + * @returns {ol.Feature} + */ + toOlFeature() { + if (this._featureType !== EditableFeatureTypes.LINEPOLYGON) { + throw new Error('Feature type must be LINEPOLYGON') + } + // Create LineString geometry from coordinates + const lineGeom = new LineString(this._coordinates) + + // Create OpenLayers Feature + const olFeature = new Feature({ + geometry: lineGeom, + name: this._title, + description: this._description, + id: this._id, + }) + + // Add style + olFeature.setStyle( + new Style({ + stroke: new Stroke({ + color: this._fillColor, + width: 2, + }), + }) + ) + + // Set feature ID + olFeature.setId(this._id) + + return olFeature + } } diff --git a/src/modules/drawing/components/AddVertexButton.vue b/src/modules/drawing/components/AddVertexButton.vue index 6ea83d79b5..faa84a4fb5 100644 --- a/src/modules/drawing/components/AddVertexButton.vue +++ b/src/modules/drawing/components/AddVertexButton.vue @@ -1,8 +1,12 @@ diff --git a/src/modules/drawing/components/useDrawingModeInteraction.composable.js b/src/modules/drawing/components/useDrawingModeInteraction.composable.js index 75e233e488..2ec6a1449b 100644 --- a/src/modules/drawing/components/useDrawingModeInteraction.composable.js +++ b/src/modules/drawing/components/useDrawingModeInteraction.composable.js @@ -76,7 +76,9 @@ export default function useDrawingModeInteraction({ ) if (selectedFeature) { interaction = continueDrawingInteraction - interaction.extend(selectedFeature.toOlFeature()) + const reverse = store.state.drawing.reverseLineStringExtension + const lineFeature = selectedFeature.toOlFeature(reverse) + interaction.extend(lineFeature) } } diff --git a/src/store/modules/drawing.store.js b/src/store/modules/drawing.store.js index 130183da38..6a121f4bf6 100644 --- a/src/store/modules/drawing.store.js +++ b/src/store/modules/drawing.store.js @@ -69,6 +69,13 @@ export default { * @type {String | null} */ name: null, + /** + * If true, continue the line string from the starting vertex, else it will continue from + * the last vertex + * + * @type {Boolean | null} + */ + reverseLineStringExtension: false, }, getters: { isDrawingEmpty(state) { @@ -127,6 +134,9 @@ export default { setDrawingName({ commit }, { name, dispatcher }) { commit('setDrawingName', { name, dispatcher }) }, + setReverseLineStringExtension({ commit }, { reverseLineStringExtension, dispatcher }) { + commit('setReverseLineStringExtension', { reverseLineStringExtension, dispatcher }) + }, }, mutations: { setDrawingMode: (state, { mode }) => (state.mode = mode), @@ -144,5 +154,8 @@ export default { setDrawingName(state, { name }) { state.name = name }, + setReverseLineStringExtension(state, { reverseLineStringExtension }) { + state.reverseLineStringExtension = reverseLineStringExtension + }, }, } From c2f9ed92f4f5833f1a571c9237d6a386b25ad943 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Mon, 18 Nov 2024 11:31:41 +0700 Subject: [PATCH 08/29] PB-199: Only show add vertex button while selecting line but not when editing. --- src/modules/drawing/DrawingModule.vue | 5 ++++- .../components/useDrawingModeInteraction.composable.js | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/modules/drawing/DrawingModule.vue b/src/modules/drawing/DrawingModule.vue index 7d874c21a0..c9092e7fe8 100644 --- a/src/modules/drawing/DrawingModule.vue +++ b/src/modules/drawing/DrawingModule.vue @@ -46,6 +46,9 @@ const selectedLineString = computed(() => { return null } }) +const showAddVertexButton = computed(() => { + return !!selectedLineString.value && store.state.drawing.mode === null +}) const hasKml = computed(() => { if (online.value) { @@ -227,7 +230,7 @@ async function closeDrawing() { diff --git a/src/modules/drawing/components/useDrawingModeInteraction.composable.js b/src/modules/drawing/components/useDrawingModeInteraction.composable.js index 2ec6a1449b..c0f8700780 100644 --- a/src/modules/drawing/components/useDrawingModeInteraction.composable.js +++ b/src/modules/drawing/components/useDrawingModeInteraction.composable.js @@ -212,6 +212,10 @@ export default function useDrawingModeInteraction({ interaction.finishDrawing() store.dispatch('addDrawingFeature', { featureId: feature.getId(), ...dispatcher }) store.dispatch('setDrawingMode', { mode: null, ...dispatcher }) + store.dispatch('setReverseLineStringExtension', { + reverseLineStringExtension: null, + ...dispatcher, + }) if (drawEndCallback) { drawEndCallback(feature) } From ba277ad9879a502e2810d99cd193f8667e06cf6b Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Mon, 18 Nov 2024 13:43:02 +0700 Subject: [PATCH 09/29] PB-199: Remove unused code from the previous approach. --- .../drawing/components/DrawingTooltip.vue | 6 +-- .../useModifyInteraction.composable.js | 38 ------------------- 2 files changed, 1 insertion(+), 43 deletions(-) diff --git a/src/modules/drawing/components/DrawingTooltip.vue b/src/modules/drawing/components/DrawingTooltip.vue index ec2af7c848..7e89223e09 100644 --- a/src/modules/drawing/components/DrawingTooltip.vue +++ b/src/modules/drawing/components/DrawingTooltip.vue @@ -144,11 +144,7 @@ function onPointerMove(event) { translationKeys = 'select_no_feature' } } else { - if (hasFeatureSelected) { - translationKeys = ['select_no_feature', 'modify_add_vertex'] - } else { - translationKeys = 'select_no_feature' - } + translationKeys = 'select_no_feature' } } diff --git a/src/modules/drawing/components/useModifyInteraction.composable.js b/src/modules/drawing/components/useModifyInteraction.composable.js index 818ff308d5..e29a027b33 100644 --- a/src/modules/drawing/components/useModifyInteraction.composable.js +++ b/src/modules/drawing/components/useModifyInteraction.composable.js @@ -58,51 +58,13 @@ export default function useModifyInteraction(features) { modifyInteraction.on('modifystart', onModifyStart) modifyInteraction.on('modifyend', onModifyEnd) olMap.addInteraction(modifyInteraction) - olMap.on('contextmenu', onMapRightClick) }) onBeforeUnmount(() => { olMap.removeInteraction(modifyInteraction) modifyInteraction.un('modifyend', onModifyEnd) modifyInteraction.un('modifystart', onModifyStart) - olMap.un('contextmenu', onMapRightClick) }) - function onMapRightClick(event) { - const newCoordinate = olMap.getEventCoordinate(event.originalEvent) - - const [feature] = features.getArray() - - if (feature) { - const geometry = feature.getGeometry() - if (geometry.getType() === 'LineString') { - geometry.appendCoordinate(newCoordinate) - } else if (geometry.getType() === 'Polygon') { - const coordinates = geometry.getCoordinates() - coordinates[0].push(newCoordinate) - geometry.setCoordinates(coordinates) - } - - const storeFeature = feature.get('editableFeature') - store.dispatch('changeFeatureIsDragged', { - feature: storeFeature, - isDragged: false, - ...dispatcher, - }) - store.dispatch('changeFeatureCoordinates', { - feature: storeFeature, - coordinates: extractOlFeatureCoordinates(feature), - geodesicCoordinates: extractOlFeatureGeodesicCoordinates(feature), - ...dispatcher, - }) - store.dispatch('changeFeatureGeometry', { - feature: storeFeature, - geometry: new GeoJSON().writeGeometryObject(feature.getGeometry()), - }) - olMap.getTarget().classList.remove(cursorGrabbingClass) - debounceSaveDrawing() - } - } - function onModifyStart(event) { const [feature] = event.features.getArray() From 65bb6049a01f5fb412e4a51d101e04b332cb4b82 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Mon, 18 Nov 2024 13:51:16 +0700 Subject: [PATCH 10/29] PB-199: Use proper tooltip. --- src/modules/drawing/components/AddVertexButton.vue | 6 ++++-- .../drawing/components/AddVertexButtonOverlay.vue | 12 ++---------- src/modules/i18n/locales/de.json | 2 +- src/modules/i18n/locales/en.json | 2 +- src/modules/i18n/locales/fr.json | 2 +- src/modules/i18n/locales/it.json | 2 +- src/modules/i18n/locales/rm.json | 2 +- 7 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/modules/drawing/components/AddVertexButton.vue b/src/modules/drawing/components/AddVertexButton.vue index 76bdb9cae5..8677b1a2a8 100644 --- a/src/modules/drawing/components/AddVertexButton.vue +++ b/src/modules/drawing/components/AddVertexButton.vue @@ -1,17 +1,19 @@ diff --git a/src/modules/i18n/locales/de.json b/src/modules/i18n/locales/de.json index 520353291b..2d66130a5a 100644 --- a/src/modules/i18n/locales/de.json +++ b/src/modules/i18n/locales/de.json @@ -393,7 +393,7 @@ "meteoschweiz_service_link_href": "http://www.meteoschweiz.admin.ch", "meteoschweiz_service_link_label": "MeteoSchweiz", "mobile_redirect": "Mobile Version", - "modify_add_vertex": "Klicken Sie mit der rechten Maustaste, um dem ausgewählten Feature einen neuen Punkt hinzuzufügen", + "modify_add_vertex": "Neuen Punkt zum Verlängern der ausgewählten Linie hinzufügen", "modify_color_label": "Farbe", "modify_description": "Beschreibung", "modify_existing_vertex_annotation": "Verschieben von Text: klicken und ziehen ", diff --git a/src/modules/i18n/locales/en.json b/src/modules/i18n/locales/en.json index fb9b381077..4951b4015f 100644 --- a/src/modules/i18n/locales/en.json +++ b/src/modules/i18n/locales/en.json @@ -393,7 +393,7 @@ "meteoschweiz_service_link_href": "http://www.meteoswiss.admin.ch", "meteoschweiz_service_link_label": "MeteoSwiss", "mobile_redirect": "Mobile version", - "modify_add_vertex": "Right click to add new point to the selected feature", + "modify_add_vertex": "Add new point for extending the selected line", "modify_color_label": "Color", "modify_description": "Description", "modify_existing_vertex_annotation": "Click then drag to move the text", diff --git a/src/modules/i18n/locales/fr.json b/src/modules/i18n/locales/fr.json index 6a04dead5e..7580c596df 100644 --- a/src/modules/i18n/locales/fr.json +++ b/src/modules/i18n/locales/fr.json @@ -393,7 +393,7 @@ "meteoschweiz_service_link_href": "http://www.meteosuisse.admin.ch", "meteoschweiz_service_link_label": "MeteoSuisse", "mobile_redirect": "Version mobile", - "modify_add_vertex": "Cliquez avec le bouton droit pour ajouter un nouveau point à l'entité sélectionnée", + "modify_add_vertex": "Ajouter un nouveau point pour prolonger la ligne sélectionnée", "modify_color_label": "Couleur", "modify_description": "Description", "modify_existing_vertex_annotation": "Cliquer puis bouger le curseur pour déplacer l'annotation", diff --git a/src/modules/i18n/locales/it.json b/src/modules/i18n/locales/it.json index 1a9187f4ef..e8c6167de7 100644 --- a/src/modules/i18n/locales/it.json +++ b/src/modules/i18n/locales/it.json @@ -393,7 +393,7 @@ "meteoschweiz_service_link_href": "http://www.meteosvizzera.admin.ch", "meteoschweiz_service_link_label": "MeteoSvizzera", "mobile_redirect": "Versione mobile", - "modify_add_vertex": "Fare clic con il pulsante destro del mouse per aggiungere un nuovo punto alla feature selezionata", + "modify_add_vertex": "Aggiungi un nuovo punto per estendere la linea selezionata", "modify_color_label": "Colore", "modify_description": "Descrizione", "modify_existing_vertex_annotation": "Cliccare quindi trascinare per spostare il testo", diff --git a/src/modules/i18n/locales/rm.json b/src/modules/i18n/locales/rm.json index 3259c25338..8469afb657 100644 --- a/src/modules/i18n/locales/rm.json +++ b/src/modules/i18n/locales/rm.json @@ -391,7 +391,7 @@ "meteoschweiz_service_link_href": "http://www.meteoschweiz.admin.ch", "meteoschweiz_service_link_label": "MeteoSvizra", "mobile_redirect": "Versiun mobila", - "modify_add_vertex": "Klikisar o ćaćutno kliko te thoves nevo punkto ki alosardi funkcia", + "modify_add_vertex": "Thov nevo punkto vaś te lungǎres i alosardi linia", "modify_color_label": "Colur", "modify_description": "Descripziun", "modify_existing_vertex_annotation": "Spustar text :cliccar e trair", From 2994ed287ea28c3da5f2b0c08652a2cc81e62473 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Mon, 18 Nov 2024 14:18:20 +0700 Subject: [PATCH 11/29] PB-199: Add style for overlay buttons. --- .../drawing/components/AddVertexButton.vue | 4 ++-- src/modules/map/scss/toolbox-buttons.scss | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/modules/drawing/components/AddVertexButton.vue b/src/modules/drawing/components/AddVertexButton.vue index 8677b1a2a8..4a3445df91 100644 --- a/src/modules/drawing/components/AddVertexButton.vue +++ b/src/modules/drawing/components/AddVertexButton.vue @@ -43,11 +43,11 @@ onMounted(() => { diff --git a/src/modules/map/scss/toolbox-buttons.scss b/src/modules/map/scss/toolbox-buttons.scss index 9412042016..aa90846387 100644 --- a/src/modules/map/scss/toolbox-buttons.scss +++ b/src/modules/map/scss/toolbox-buttons.scss @@ -43,3 +43,19 @@ font-size: smaller; text-align: center; } + +.overlay-button { + @extend .toolbox-button; + height: $map-button-diameter * 0.75; + width: $map-button-diameter * 0.75; + border-radius: $map-button-diameter * 0.5; + + &-icon { + height: ($map-button-diameter - 25px); + } + + &-inner-circle, + .svg-inline--fa { + height: $map-button-inner-icon-diameter * 0.75; + } +} From 4f2ef78bda2c0e3d4d2d05904d615444fa3a3369 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Mon, 18 Nov 2024 14:34:00 +0700 Subject: [PATCH 12/29] PB-199: Position add vertex button depending on the line string geometry. --- .../components/AddVertexButtonOverlay.vue | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/modules/drawing/components/AddVertexButtonOverlay.vue b/src/modules/drawing/components/AddVertexButtonOverlay.vue index 8a54abedf0..169088e964 100644 --- a/src/modules/drawing/components/AddVertexButtonOverlay.vue +++ b/src/modules/drawing/components/AddVertexButtonOverlay.vue @@ -22,15 +22,45 @@ const lastButtonOverlay = ref(null) const firstButtonCoordinate = ref(null) const lastButtonCoordinate = ref(null) +const calculateOffset = (point1, point2, distance = 35) => { + 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 coordinates = props.lineString.coordinates firstButtonCoordinate.value = coordinates[0] lastButtonCoordinate.value = coordinates[coordinates.length - 1] + + const firstOffset = calculateOffset(coordinates[0], coordinates[1]) + const lastOffset = calculateOffset( + coordinates[coordinates.length - 1], + coordinates[coordinates.length - 2] + ) + if (firstButtonOverlay.value) { firstButtonOverlay.value.setPosition(firstButtonCoordinate.value) + firstButtonOverlay.value.setOffset(firstOffset) } if (lastButtonOverlay.value) { lastButtonOverlay.value.setPosition(lastButtonCoordinate.value) + lastButtonOverlay.value.setOffset(lastOffset) } } From 8ec2467c4e7bda01f9f58e09e642c06d0e0309a5 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Mon, 18 Nov 2024 14:45:49 +0700 Subject: [PATCH 13/29] PB-199: Only show the add vertex button on linestring excluding measurement line. --- src/modules/drawing/DrawingModule.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/drawing/DrawingModule.vue b/src/modules/drawing/DrawingModule.vue index c9092e7fe8..edeacd15b6 100644 --- a/src/modules/drawing/DrawingModule.vue +++ b/src/modules/drawing/DrawingModule.vue @@ -5,6 +5,7 @@ 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' @@ -37,7 +38,10 @@ const selectedEditableFeatures = computed(() => store.state.features.selectedEdi const selectedLineString = computed(() => { if (selectedEditableFeatures.value && selectedEditableFeatures.value.length > 0) { const selectedFeature = selectedEditableFeatures.value[0] - if (selectedFeature.geometry.type === 'LineString') { + if ( + selectedFeature.geometry.type === 'LineString' && + selectedFeature.featureType === EditableFeatureTypes.LINEPOLYGON + ) { return selectedFeature } else { return null From 4239c2a800375ff6848cd47e08122a098a61e753 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Wed, 20 Nov 2024 13:55:29 +0700 Subject: [PATCH 14/29] PB-199: Use different approach, putting the continue drawing interaction in modify interaction. --- src/modules/drawing/DrawingModule.vue | 5 ++ .../drawing/components/AddVertexButton.vue | 4 +- .../useDrawingModeInteraction.composable.js | 9 ++-- .../useModifyInteraction.composable.js | 53 +++++++++++++++++-- src/store/modules/drawing.store.js | 8 +++ 5 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/modules/drawing/DrawingModule.vue b/src/modules/drawing/DrawingModule.vue index edeacd15b6..bf3f48bf88 100644 --- a/src/modules/drawing/DrawingModule.vue +++ b/src/modules/drawing/DrawingModule.vue @@ -36,6 +36,8 @@ const noFeatureInfo = computed(() => store.getters.noFeatureInfo) const online = computed(() => store.state.drawing.online) const selectedEditableFeatures = computed(() => store.state.features.selectedEditableFeatures) const selectedLineString = computed(() => { + // eslint-disable-next-line no-unused-vars + const x = store.state.drawing.extendingLineString if (selectedEditableFeatures.value && selectedEditableFeatures.value.length > 0) { const selectedFeature = selectedEditableFeatures.value[0] if ( @@ -51,6 +53,9 @@ const selectedLineString = computed(() => { } }) const showAddVertexButton = computed(() => { + if (store.state.drawing.extendingLineString) { + return false + } return !!selectedLineString.value && store.state.drawing.mode === null }) diff --git a/src/modules/drawing/components/AddVertexButton.vue b/src/modules/drawing/components/AddVertexButton.vue index 4a3445df91..e186d81fc9 100644 --- a/src/modules/drawing/components/AddVertexButton.vue +++ b/src/modules/drawing/components/AddVertexButton.vue @@ -4,7 +4,7 @@ import { onMounted, ref } from 'vue' import { useI18n } from 'vue-i18n' import { useStore } from 'vuex' -import { EditableFeatureTypes } from '@/api/features/EditableFeature.class' +// import { EditableFeatureTypes } from '@/api/features/EditableFeature.class' import { useTippyTooltip } from '@/utils/composables/useTippyTooltip' const dispatcher = { dispatcher: 'AddVertexButton.vue' } const i18n = useI18n() @@ -31,7 +31,7 @@ function addVertex() { reverseLineStringExtension: props.reverse, ...dispatcher, }) - store.dispatch('setDrawingMode', { mode: EditableFeatureTypes.LINEPOLYGON, ...dispatcher }) + store.dispatch('setExtendingLineString', { extendingLineString: true, ...dispatcher }) } onMounted(() => { diff --git a/src/modules/drawing/components/useDrawingModeInteraction.composable.js b/src/modules/drawing/components/useDrawingModeInteraction.composable.js index c0f8700780..15eecd5322 100644 --- a/src/modules/drawing/components/useDrawingModeInteraction.composable.js +++ b/src/modules/drawing/components/useDrawingModeInteraction.composable.js @@ -66,14 +66,13 @@ export default function useDrawingModeInteraction({ const snapInteraction = new SnapInteraction({ source: drawingLayer.getSource(), }) + let selectedFeatureId = null + let selectedFeature = null onMounted(() => { - const selectedFeatureId = store.state.features.selectedEditableFeatures[0]?.id + selectedFeatureId = store.state.features.selectedEditableFeatures[0]?.id if (selectedFeatureId) { - const selectedFeature = getEditableFeatureWithId( - store.state.features, - selectedFeatureId - ) + selectedFeature = getEditableFeatureWithId(store.state.features, selectedFeatureId) if (selectedFeature) { interaction = continueDrawingInteraction const reverse = store.state.drawing.reverseLineStringExtension diff --git a/src/modules/drawing/components/useModifyInteraction.composable.js b/src/modules/drawing/components/useModifyInteraction.composable.js index e29a027b33..214af10b5e 100644 --- a/src/modules/drawing/components/useModifyInteraction.composable.js +++ b/src/modules/drawing/components/useModifyInteraction.composable.js @@ -1,7 +1,8 @@ -import { noModifierKeys, singleClick } from 'ol/events/condition' +import { noModifierKeys, primaryAction, singleClick } from 'ol/events/condition' import GeoJSON from 'ol/format/GeoJSON' +import DrawInteraction from 'ol/interaction/Draw' import ModifyInteraction from 'ol/interaction/Modify' -import { inject, onBeforeUnmount, onMounted } from 'vue' +import { inject, onBeforeUnmount, onMounted, watch } from 'vue' import { useStore } from 'vuex' import { @@ -9,9 +10,10 @@ import { extractOlFeatureGeodesicCoordinates, } from '@/api/features/features.api' import { DRAWING_HIT_TOLERANCE } from '@/config/map.config' -import { editingVertexStyleFunction } from '@/modules/drawing/lib/style' +import { drawLineStyle, editingVertexStyleFunction } from '@/modules/drawing/lib/style' import useSaveKmlOnChange from '@/modules/drawing/useKmlDataManagement.composable' import { segmentExtent, subsegments } from '@/utils/geodesicManager' +import log from '@/utils/logging' const dispatcher = { dispatcher: 'useModifyInteraction.composable' } const cursorGrabbingClass = 'cursor-grabbing' @@ -54,15 +56,47 @@ export default function useModifyInteraction(features) { wrapX: true, }) + const continueDrawingInteraction = new DrawInteraction({ + style: drawLineStyle, + type: 'LineString', // Only works for LineString + minPoints: 2, + stopClick: true, + // only left-click to draw (primaryAction) + condition: (e) => primaryAction(e), + wrapX: true, + }) + + watch( + () => store.state.drawing.extendingLineString, + (newValue) => { + if (newValue && features.getArray().length > 0) { + const selectedFeature = features.getArray()[0] + continueDrawingInteraction.extend(selectedFeature) + continueDrawingInteraction.setActive(true) + modifyInteraction.setActive(false) + } else { + modifyInteraction.setActive(true) + continueDrawingInteraction.setActive(false) + } + }, + { immediate: true } + ) + onMounted(() => { modifyInteraction.on('modifystart', onModifyStart) modifyInteraction.on('modifyend', onModifyEnd) olMap.addInteraction(modifyInteraction) + + continueDrawingInteraction.on('drawend', onExtendEnd) + olMap.addInteraction(continueDrawingInteraction) + continueDrawingInteraction.setActive(false) }) onBeforeUnmount(() => { olMap.removeInteraction(modifyInteraction) + olMap.removeInteraction(continueDrawingInteraction) modifyInteraction.un('modifyend', onModifyEnd) modifyInteraction.un('modifystart', onModifyStart) + continueDrawingInteraction.un('drawend', onExtendEnd) }) function onModifyStart(event) { @@ -106,4 +140,17 @@ export default function useModifyInteraction(features) { debounceSaveDrawing() } } + + function onExtendEnd(event) { + log.debug('onExtendEnd', event) + // Update the original feature with new coordinates + const newCoords = event.feature.getGeometry().getCoordinates() + log.debug('drawend coordinate', newCoords) + log.debug('selectedFeature', features) + store.dispatch('setExtendingLineString', { + extendingLineString: false, + ...dispatcher, + }) + debounceSaveDrawing() + } } diff --git a/src/store/modules/drawing.store.js b/src/store/modules/drawing.store.js index 6a121f4bf6..0f40c39b4c 100644 --- a/src/store/modules/drawing.store.js +++ b/src/store/modules/drawing.store.js @@ -76,6 +76,8 @@ export default { * @type {Boolean | null} */ reverseLineStringExtension: false, + + extendingLineString: false, }, getters: { isDrawingEmpty(state) { @@ -137,6 +139,9 @@ export default { setReverseLineStringExtension({ commit }, { reverseLineStringExtension, dispatcher }) { commit('setReverseLineStringExtension', { reverseLineStringExtension, dispatcher }) }, + setExtendingLineString({ commit }, { extendingLineString, dispatcher }) { + commit('setExtendingLineString', { extendingLineString, dispatcher }) + }, }, mutations: { setDrawingMode: (state, { mode }) => (state.mode = mode), @@ -157,5 +162,8 @@ export default { setReverseLineStringExtension(state, { reverseLineStringExtension }) { state.reverseLineStringExtension = reverseLineStringExtension }, + setExtendingLineString(state, { extendingLineString }) { + state.extendingLineString = extendingLineString + }, }, } From 48206c31cf26b076b2390aa9d0a9abf8da8f5095 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Wed, 20 Nov 2024 14:15:08 +0700 Subject: [PATCH 15/29] PB-199: add vertex from the starting point. --- .../drawing/components/useModifyInteraction.composable.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/drawing/components/useModifyInteraction.composable.js b/src/modules/drawing/components/useModifyInteraction.composable.js index 214af10b5e..b2a6803b32 100644 --- a/src/modules/drawing/components/useModifyInteraction.composable.js +++ b/src/modules/drawing/components/useModifyInteraction.composable.js @@ -71,6 +71,11 @@ export default function useModifyInteraction(features) { (newValue) => { if (newValue && features.getArray().length > 0) { const selectedFeature = features.getArray()[0] + if (store.state.drawing.reverseLineStringExtension) { + selectedFeature + .getGeometry() + .setCoordinates(selectedFeature.getGeometry().getCoordinates().reverse()) + } continueDrawingInteraction.extend(selectedFeature) continueDrawingInteraction.setActive(true) modifyInteraction.setActive(false) From 96c51860abdc3be0f36090d4dbc2a937739d18c1 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Wed, 20 Nov 2024 14:20:54 +0700 Subject: [PATCH 16/29] PB-199: Remove old approach. --- src/api/features/EditableFeature.class.js | 42 +------------------ .../useDrawingModeInteraction.composable.js | 34 +-------------- src/store/modules/features.store.js | 2 +- 3 files changed, 3 insertions(+), 75 deletions(-) diff --git a/src/api/features/EditableFeature.class.js b/src/api/features/EditableFeature.class.js index 9330e4d4e1..989eac4c9e 100644 --- a/src/api/features/EditableFeature.class.js +++ b/src/api/features/EditableFeature.class.js @@ -1,6 +1,4 @@ -import { Feature } from 'ol' -import { LineString } from 'ol/geom' -import { Icon as olIcon, Stroke, Style } from 'ol/style' +import { Icon as olIcon } from 'ol/style' import { extractOlFeatureGeodesicCoordinates } from '@/api/features/features.api' import SelectableFeature from '@/api/features/SelectableFeature.class' @@ -220,42 +218,4 @@ export default class EditableFeature extends SelectableFeature { set geodesicCoordinates(coordinates) { this._geodesicCoordinates = coordinates } - - /** - * Converts this EditableFeature to an OpenLayers Feature - * - * @param {boolean} reverse If true, the geometry is reversed. Default is false. - * @returns {ol.Feature} - */ - toOlFeature(reverse = false) { - if (this._featureType !== EditableFeatureTypes.LINEPOLYGON) { - throw new Error('Feature type must be LINEPOLYGON') - } - // Create LineString geometry from coordinates - const coordinates = reverse ? [...this._coordinates].reverse() : this._coordinates - const lineGeom = new LineString(coordinates) - - // Create OpenLayers Feature - const olFeature = new Feature({ - geometry: lineGeom, - name: this._title, - description: this._description, - id: this._id, - }) - - // Add style - olFeature.setStyle( - new Style({ - stroke: new Stroke({ - color: this._fillColor, - width: 2, - }), - }) - ) - - // Set feature ID - olFeature.setId(this._id) - - return olFeature - } } diff --git a/src/modules/drawing/components/useDrawingModeInteraction.composable.js b/src/modules/drawing/components/useDrawingModeInteraction.composable.js index 15eecd5322..ceb85c5f76 100644 --- a/src/modules/drawing/components/useDrawingModeInteraction.composable.js +++ b/src/modules/drawing/components/useDrawingModeInteraction.composable.js @@ -12,7 +12,6 @@ import { EditableFeatureTypes } from '@/api/features/EditableFeature.class' import { DEFAULT_MARKER_TITLE_OFFSET } from '@/api/icon.api' import { editingFeatureStyleFunction } from '@/modules/drawing/lib/style' import useSaveKmlOnChange from '@/modules/drawing/useKmlDataManagement.composable' -import { getEditableFeatureWithId } from '@/store/modules/features.store' import { wrapXCoordinates } from '@/utils/coordinates/coordinateUtils' import { geoadminStyleFunction } from '@/utils/featureStyleUtils' import { GeodesicGeometries } from '@/utils/geodesicManager' @@ -39,7 +38,7 @@ export default function useDrawingModeInteraction({ const store = useStore() const projection = computed(() => store.state.position.projection) - const drawFromScratchInteraction = new DrawInteraction({ + const interaction = new DrawInteraction({ style: editingStyle, type: geometryType, source: drawingLayer.getSource(), @@ -49,38 +48,11 @@ export default function useDrawingModeInteraction({ condition: (e) => primaryAction(e), wrapX: true, }) - - const continueDrawingInteraction = new DrawInteraction({ - style: editingStyle, - type: 'LineString', // Only works for LineString - source: drawingLayer.getSource(), - minPoints: 2, - stopClick: true, - // only left-click to draw (primaryAction) - condition: (e) => primaryAction(e), - wrapX: true, - }) - - let interaction = drawFromScratchInteraction - const snapInteraction = new SnapInteraction({ source: drawingLayer.getSource(), }) - let selectedFeatureId = null - let selectedFeature = null onMounted(() => { - selectedFeatureId = store.state.features.selectedEditableFeatures[0]?.id - if (selectedFeatureId) { - selectedFeature = getEditableFeatureWithId(store.state.features, selectedFeatureId) - if (selectedFeature) { - interaction = continueDrawingInteraction - const reverse = store.state.drawing.reverseLineStringExtension - const lineFeature = selectedFeature.toOlFeature(reverse) - interaction.extend(lineFeature) - } - } - interaction.setActive(true) interaction.getOverlay().getSource().on('addfeature', onAddFeature) @@ -211,10 +183,6 @@ export default function useDrawingModeInteraction({ interaction.finishDrawing() store.dispatch('addDrawingFeature', { featureId: feature.getId(), ...dispatcher }) store.dispatch('setDrawingMode', { mode: null, ...dispatcher }) - store.dispatch('setReverseLineStringExtension', { - reverseLineStringExtension: null, - ...dispatcher, - }) if (drawEndCallback) { drawEndCallback(feature) } diff --git a/src/store/modules/features.store.js b/src/store/modules/features.store.js index 6d2898da3d..a0bdf4c276 100644 --- a/src/store/modules/features.store.js +++ b/src/store/modules/features.store.js @@ -22,7 +22,7 @@ export function canFeatureShowProfile(feature) { return feature?.geometry?.type && !['Point'].includes(feature.geometry.type) } -export const getEditableFeatureWithId = (state, featureId) => { +const getEditableFeatureWithId = (state, featureId) => { return state.selectedEditableFeatures.find( (selectedFeature) => selectedFeature.id === featureId ) From 101fb7b922372049198cfb4634d6f7edd1da817e Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Wed, 20 Nov 2024 15:16:57 +0700 Subject: [PATCH 17/29] PB-199: Add edit mode for better handling the add vertex buttons. --- src/modules/drawing/DrawingModule.vue | 18 ++++++++----- .../drawing/components/AddVertexButton.vue | 3 ++- .../useModifyInteraction.composable.js | 12 ++++----- src/store/modules/drawing.store.js | 26 ++++++++++++++----- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/modules/drawing/DrawingModule.vue b/src/modules/drawing/DrawingModule.vue index bf3f48bf88..899343e1a4 100644 --- a/src/modules/drawing/DrawingModule.vue +++ b/src/modules/drawing/DrawingModule.vue @@ -13,6 +13,7 @@ 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' @@ -37,7 +38,7 @@ const online = computed(() => store.state.drawing.online) const selectedEditableFeatures = computed(() => store.state.features.selectedEditableFeatures) const selectedLineString = computed(() => { // eslint-disable-next-line no-unused-vars - const x = store.state.drawing.extendingLineString + const currentEditingMode = store.state.drawing.editingMode if (selectedEditableFeatures.value && selectedEditableFeatures.value.length > 0) { const selectedFeature = selectedEditableFeatures.value[0] if ( @@ -53,10 +54,7 @@ const selectedLineString = computed(() => { } }) const showAddVertexButton = computed(() => { - if (store.state.drawing.extendingLineString) { - return false - } - return !!selectedLineString.value && store.state.drawing.mode === null + return store.state.drawing.editingMode === EditMode.MODIFY && !!selectedLineString.value }) const hasKml = computed(() => { @@ -134,7 +132,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 diff --git a/src/modules/drawing/components/AddVertexButton.vue b/src/modules/drawing/components/AddVertexButton.vue index e186d81fc9..50e8686fe8 100644 --- a/src/modules/drawing/components/AddVertexButton.vue +++ b/src/modules/drawing/components/AddVertexButton.vue @@ -4,6 +4,7 @@ import { onMounted, ref } from 'vue' import { useI18n } from 'vue-i18n' import { useStore } from 'vuex' +import { EditMode } from '@/store/modules/drawing.store' // import { EditableFeatureTypes } from '@/api/features/EditableFeature.class' import { useTippyTooltip } from '@/utils/composables/useTippyTooltip' const dispatcher = { dispatcher: 'AddVertexButton.vue' } @@ -31,7 +32,7 @@ function addVertex() { reverseLineStringExtension: props.reverse, ...dispatcher, }) - store.dispatch('setExtendingLineString', { extendingLineString: true, ...dispatcher }) + store.dispatch('setEditingMode', { mode: EditMode.EXTEND, ...dispatcher }) } onMounted(() => { diff --git a/src/modules/drawing/components/useModifyInteraction.composable.js b/src/modules/drawing/components/useModifyInteraction.composable.js index b2a6803b32..03a56ad0fa 100644 --- a/src/modules/drawing/components/useModifyInteraction.composable.js +++ b/src/modules/drawing/components/useModifyInteraction.composable.js @@ -12,6 +12,7 @@ import { import { DRAWING_HIT_TOLERANCE } from '@/config/map.config' import { drawLineStyle, editingVertexStyleFunction } from '@/modules/drawing/lib/style' import useSaveKmlOnChange from '@/modules/drawing/useKmlDataManagement.composable' +import { EditMode } from '@/store/modules/drawing.store' import { segmentExtent, subsegments } from '@/utils/geodesicManager' import log from '@/utils/logging' @@ -29,7 +30,6 @@ export default function useModifyInteraction(features) { const store = useStore() const olMap = inject('olMap') - const { willModify, debounceSaveDrawing } = useSaveKmlOnChange() const modifyInteraction = new ModifyInteraction({ @@ -67,9 +67,9 @@ export default function useModifyInteraction(features) { }) watch( - () => store.state.drawing.extendingLineString, + () => store.state.drawing.editingMode, (newValue) => { - if (newValue && features.getArray().length > 0) { + if (newValue === EditMode.EXTEND && features.getArray().length > 0) { const selectedFeature = features.getArray()[0] if (store.state.drawing.reverseLineStringExtension) { selectedFeature @@ -97,6 +97,7 @@ export default function useModifyInteraction(features) { continueDrawingInteraction.setActive(false) }) onBeforeUnmount(() => { + store.dispatch('setEditingMode', { mode: EditMode.OFF, ...dispatcher }) olMap.removeInteraction(modifyInteraction) olMap.removeInteraction(continueDrawingInteraction) modifyInteraction.un('modifyend', onModifyEnd) @@ -152,10 +153,7 @@ export default function useModifyInteraction(features) { const newCoords = event.feature.getGeometry().getCoordinates() log.debug('drawend coordinate', newCoords) log.debug('selectedFeature', features) - store.dispatch('setExtendingLineString', { - extendingLineString: false, - ...dispatcher, - }) + store.dispatch('setEditingMode', { mode: EditMode.MODIFY, ...dispatcher }) debounceSaveDrawing() } } diff --git a/src/store/modules/drawing.store.js b/src/store/modules/drawing.store.js index 0f40c39b4c..2843433bdf 100644 --- a/src/store/modules/drawing.store.js +++ b/src/store/modules/drawing.store.js @@ -9,6 +9,13 @@ const defaultDrawingTitle = 'draw_mode_title' * @property {string} featureId */ +/** @enum */ +export const EditMode = { + OFF: 'OFF', + MODIFY: 'MODIFY', // Mode for modifying existing features + EXTEND: 'EXTEND', // Mode for extending existing features (for line only) +} + export default { state: { /** @@ -77,7 +84,12 @@ export default { */ reverseLineStringExtension: false, - extendingLineString: false, + /** + * Current editing mode. See {@link EditMode} + * + * @type {String | null} + */ + editingMode: EditMode.OFF, }, getters: { isDrawingEmpty(state) { @@ -139,8 +151,12 @@ export default { setReverseLineStringExtension({ commit }, { reverseLineStringExtension, dispatcher }) { commit('setReverseLineStringExtension', { reverseLineStringExtension, dispatcher }) }, - setExtendingLineString({ commit }, { extendingLineString, dispatcher }) { - commit('setExtendingLineString', { extendingLineString, dispatcher }) + setEditingMode({ commit }, { mode, dispatcher }) { + if (mode in EditMode) { + commit('setEditingMode', { mode, dispatcher }) + } else { + commit('setEditingMode', { mode: EditMode.OFF, dispatcher }) + } }, }, mutations: { @@ -162,8 +178,6 @@ export default { setReverseLineStringExtension(state, { reverseLineStringExtension }) { state.reverseLineStringExtension = reverseLineStringExtension }, - setExtendingLineString(state, { extendingLineString }) { - state.extendingLineString = extendingLineString - }, + setEditingMode: (state, { mode }) => (state.editingMode = mode), }, } From 96a8856817cb5ab38b24d6ddee867873bb998543 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Wed, 20 Nov 2024 15:36:58 +0700 Subject: [PATCH 18/29] PB-199: Update store selected feature to update the add vertex button position. --- src/modules/drawing/DrawingModule.vue | 2 -- .../useModifyInteraction.composable.js | 21 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/modules/drawing/DrawingModule.vue b/src/modules/drawing/DrawingModule.vue index 899343e1a4..1aa53d6928 100644 --- a/src/modules/drawing/DrawingModule.vue +++ b/src/modules/drawing/DrawingModule.vue @@ -37,8 +37,6 @@ const noFeatureInfo = computed(() => store.getters.noFeatureInfo) const online = computed(() => store.state.drawing.online) const selectedEditableFeatures = computed(() => store.state.features.selectedEditableFeatures) const selectedLineString = computed(() => { - // eslint-disable-next-line no-unused-vars - const currentEditingMode = store.state.drawing.editingMode if (selectedEditableFeatures.value && selectedEditableFeatures.value.length > 0) { const selectedFeature = selectedEditableFeatures.value[0] if ( diff --git a/src/modules/drawing/components/useModifyInteraction.composable.js b/src/modules/drawing/components/useModifyInteraction.composable.js index 03a56ad0fa..dbe6b5180a 100644 --- a/src/modules/drawing/components/useModifyInteraction.composable.js +++ b/src/modules/drawing/components/useModifyInteraction.composable.js @@ -149,11 +149,22 @@ export default function useModifyInteraction(features) { function onExtendEnd(event) { log.debug('onExtendEnd', event) + const feature = event.feature // Update the original feature with new coordinates - const newCoords = event.feature.getGeometry().getCoordinates() - log.debug('drawend coordinate', newCoords) - log.debug('selectedFeature', features) - store.dispatch('setEditingMode', { mode: EditMode.MODIFY, ...dispatcher }) - debounceSaveDrawing() + if (feature) { + const storeFeature = feature.get('editableFeature') + store.dispatch('changeFeatureCoordinates', { + feature: storeFeature, + coordinates: extractOlFeatureCoordinates(feature), + geodesicCoordinates: extractOlFeatureGeodesicCoordinates(feature), + ...dispatcher, + }) + store.dispatch('changeFeatureGeometry', { + feature: storeFeature, + geometry: new GeoJSON().writeGeometryObject(feature.getGeometry()), + }) + store.dispatch('setEditingMode', { mode: EditMode.MODIFY, ...dispatcher }) + debounceSaveDrawing() + } } } From 87dd1edf68cd40696e4ce307164148acab794ac7 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Wed, 20 Nov 2024 15:39:12 +0700 Subject: [PATCH 19/29] PB-199: Remove unused comment. --- src/modules/drawing/components/AddVertexButtonOverlay.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/drawing/components/AddVertexButtonOverlay.vue b/src/modules/drawing/components/AddVertexButtonOverlay.vue index 169088e964..33184862e6 100644 --- a/src/modules/drawing/components/AddVertexButtonOverlay.vue +++ b/src/modules/drawing/components/AddVertexButtonOverlay.vue @@ -69,7 +69,7 @@ const onFirstButtonMounted = (buttonElement) => { element: buttonElement, positioning: 'center-center', stopEvent: true, - offset: [-25, -25], // TODO: make this dynamic according to the next point + offset: [-25, -25], }) olMap.addOverlay(firstButtonOverlay.value) updateButtonPositions() @@ -80,7 +80,7 @@ const onLastButtonMounted = (buttonElement) => { element: buttonElement, positioning: 'center-center', stopEvent: true, - offset: [-25, -25], // TODO: make this dynamic according to the next point + offset: [-25, -25], }) olMap.addOverlay(lastButtonOverlay.value) updateButtonPositions() From 13d820d9c29ab77feef6b3b5fa40f96b78dfbafd Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Thu, 21 Nov 2024 05:16:02 +0700 Subject: [PATCH 20/29] PB-199: remove last point with right click on extend line mode. --- .../drawing/components/useModifyInteraction.composable.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/drawing/components/useModifyInteraction.composable.js b/src/modules/drawing/components/useModifyInteraction.composable.js index dbe6b5180a..09adfbc52e 100644 --- a/src/modules/drawing/components/useModifyInteraction.composable.js +++ b/src/modules/drawing/components/useModifyInteraction.composable.js @@ -79,9 +79,11 @@ export default function useModifyInteraction(features) { continueDrawingInteraction.extend(selectedFeature) continueDrawingInteraction.setActive(true) modifyInteraction.setActive(false) + olMap.on('contextmenu', onMapRightClick) } else { modifyInteraction.setActive(true) continueDrawingInteraction.setActive(false) + olMap.un('contextmenu', onMapRightClick) } }, { immediate: true } @@ -105,6 +107,10 @@ export default function useModifyInteraction(features) { continueDrawingInteraction.un('drawend', onExtendEnd) }) + function onMapRightClick(_event) { + continueDrawingInteraction.removeLastPoint() + } + function onModifyStart(event) { const [feature] = event.features.getArray() From b9e9d1f1a667663550a6cae2613d47fd8f12e562 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Thu, 21 Nov 2024 05:41:34 +0700 Subject: [PATCH 21/29] PB-199: Remove last point on right click on modify mode. --- .../useModifyInteraction.composable.js | 58 ++++++++++++------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/modules/drawing/components/useModifyInteraction.composable.js b/src/modules/drawing/components/useModifyInteraction.composable.js index 09adfbc52e..464b118237 100644 --- a/src/modules/drawing/components/useModifyInteraction.composable.js +++ b/src/modules/drawing/components/useModifyInteraction.composable.js @@ -80,6 +80,10 @@ export default function useModifyInteraction(features) { continueDrawingInteraction.setActive(true) modifyInteraction.setActive(false) olMap.on('contextmenu', onMapRightClick) + } else if (newValue === EditMode.MODIFY) { + modifyInteraction.setActive(true) + continueDrawingInteraction.setActive(false) + olMap.on('contextmenu', onMapRightClick) // Keep right-click listener } else { modifyInteraction.setActive(true) continueDrawingInteraction.setActive(false) @@ -108,7 +112,20 @@ export default function useModifyInteraction(features) { }) function onMapRightClick(_event) { - continueDrawingInteraction.removeLastPoint() + if (continueDrawingInteraction.getActive()) { + continueDrawingInteraction.removeLastPoint() + } else if (modifyInteraction.getActive() && features.getArray().length > 0) { + const feature = features.getArray()[0] + const geometry = feature.getGeometry() + const coordinates = geometry.getCoordinates() + if (coordinates.length > 2) { + // Keep at least 2 points + coordinates.pop() + geometry.setCoordinates(coordinates) + } + // Updating the store feature + updateStoreFeatureCoordinatesGeometry(feature) + } } function onModifyStart(event) { @@ -138,16 +155,7 @@ export default function useModifyInteraction(features) { isDragged: false, ...dispatcher, }) - store.dispatch('changeFeatureCoordinates', { - feature: storeFeature, - coordinates: extractOlFeatureCoordinates(feature), - geodesicCoordinates: extractOlFeatureGeodesicCoordinates(feature), - ...dispatcher, - }) - store.dispatch('changeFeatureGeometry', { - feature: storeFeature, - geometry: new GeoJSON().writeGeometryObject(feature.getGeometry()), - }) + updateStoreFeatureCoordinatesGeometry(feature) olMap.getTarget().classList.remove(cursorGrabbingClass) debounceSaveDrawing() } @@ -158,19 +166,25 @@ export default function useModifyInteraction(features) { const feature = event.feature // Update the original feature with new coordinates if (feature) { - const storeFeature = feature.get('editableFeature') - store.dispatch('changeFeatureCoordinates', { - feature: storeFeature, - coordinates: extractOlFeatureCoordinates(feature), - geodesicCoordinates: extractOlFeatureGeodesicCoordinates(feature), - ...dispatcher, - }) - store.dispatch('changeFeatureGeometry', { - feature: storeFeature, - geometry: new GeoJSON().writeGeometryObject(feature.getGeometry()), - }) + updateStoreFeatureCoordinatesGeometry(feature) store.dispatch('setEditingMode', { mode: EditMode.MODIFY, ...dispatcher }) debounceSaveDrawing() } } + + // Update the store feature with the new coordinates and geometry + function updateStoreFeatureCoordinatesGeometry(feature) { + const storeFeature = feature.get('editableFeature') + store.dispatch('changeFeatureCoordinates', { + feature: storeFeature, + coordinates: extractOlFeatureCoordinates(feature), + geodesicCoordinates: extractOlFeatureGeodesicCoordinates(feature), + ...dispatcher, + }) + store.dispatch('changeFeatureGeometry', { + feature: storeFeature, + geometry: new GeoJSON().writeGeometryObject(feature.getGeometry()), + ...dispatcher, + }) + } } From d80e856180b6ec28e30b434ac5316cda7e22e410 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Thu, 21 Nov 2024 15:29:59 +0700 Subject: [PATCH 22/29] PB-199: Address PR review. --- src/modules/drawing/DrawingModule.vue | 7 ++----- .../drawing/components/AddVertexButton.vue | 20 ++++++++++--------- .../components/AddVertexButtonOverlay.vue | 2 +- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/modules/drawing/DrawingModule.vue b/src/modules/drawing/DrawingModule.vue index 1aa53d6928..077523ebc2 100644 --- a/src/modules/drawing/DrawingModule.vue +++ b/src/modules/drawing/DrawingModule.vue @@ -44,12 +44,9 @@ const selectedLineString = computed(() => { selectedFeature.featureType === EditableFeatureTypes.LINEPOLYGON ) { return selectedFeature - } else { - return null } - } else { - return null } + return null }) const showAddVertexButton = computed(() => { return store.state.drawing.editingMode === EditMode.MODIFY && !!selectedLineString.value @@ -245,6 +242,6 @@ async function closeDrawing() { + /> diff --git a/src/modules/drawing/components/AddVertexButton.vue b/src/modules/drawing/components/AddVertexButton.vue index 50e8686fe8..2056070c1b 100644 --- a/src/modules/drawing/components/AddVertexButton.vue +++ b/src/modules/drawing/components/AddVertexButton.vue @@ -5,11 +5,8 @@ import { useI18n } from 'vue-i18n' import { useStore } from 'vuex' import { EditMode } from '@/store/modules/drawing.store' -// import { EditableFeatureTypes } from '@/api/features/EditableFeature.class' import { useTippyTooltip } from '@/utils/composables/useTippyTooltip' const dispatcher = { dispatcher: 'AddVertexButton.vue' } -const i18n = useI18n() -const store = useStore() const props = defineProps({ tooltipText: { @@ -22,11 +19,21 @@ const props = defineProps({ default: false, }, }) -useTippyTooltip('#addVertexButton [data-tippy-content]', { placement: 'left' }) + 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('setReverseLineStringExtension', { reverseLineStringExtension: props.reverse, @@ -34,11 +41,6 @@ function addVertex() { }) store.dispatch('setEditingMode', { mode: EditMode.EXTEND, ...dispatcher }) } - -onMounted(() => { - // Emit an event to notify the parent component that the button is mounted - emit('button-mounted', buttonRef.value) -})