diff --git a/src/components/Map/EditingToolbar.vue b/src/components/Map/EditingToolbar.vue index 1f4d19aa178dca42f6435eba8659e12464bce79b..35a54ee19495ce5710fbf81a99aa2f5b04a8d892 100644 --- a/src/components/Map/EditingToolbar.vue +++ b/src/components/Map/EditingToolbar.vue @@ -1,35 +1,44 @@ <template> <div class="editionToolbar"> - <div v-if="showDrawTool"> - <div class="leaflet-bar"> - <a - class="leaflet-draw-draw-polygon active" - :title=" - editionService.geom_type === 'polygon' ? 'Dessiner un polygone' : - editionService.geom_type === 'linestring' ? 'Dessiner une ligne' : - 'Dessiner un point' - " + <div class="leaflet-bar"> + <a + v-if="showDrawTool || isEditing" + :class="{ active: isSnapEnabled }" + :data-tooltip="`${ isSnapEnabled ? 'Désactiver' : 'Activer' } l'accrochage aux points`" + data-position="top right" + @click="toggleSnap" + > + <i class="magnet icon" /> + <span class="sr-only">{{ isSnapEnabled ? 'Désactiver' : 'Activer' }} l'accrochage aux points</span> + </a> + + <a + v-if="showDrawTool" + class="leaflet-draw-draw-polygon active" + :title=" + editionService.geom_type === 'polygon' ? 'Dessiner un polygone' : + editionService.geom_type === 'linestring' ? 'Dessiner une ligne' : + 'Dessiner un point' + " + > + <img + v-if="editionService.geom_type === 'linestring'" + class="list-image-type" + src="@/assets/img/line.png" > - <img - v-if="editionService.geom_type === 'linestring'" - class="list-image-type" - src="@/assets/img/line.png" - > - <img - v-if="editionService.geom_type === 'point'" - class="list-image-type" - src="@/assets/img/marker.png" - > - <img - v-if="editionService.geom_type === 'polygon'" - class="list-image-type" - src="@/assets/img/polygon.png" - > - </a> - </div> - </div> - <div v-if="!showDrawTool"> - <div class="leaflet-bar"> + <img + v-if="editionService.geom_type === 'point'" + class="list-image-type" + src="@/assets/img/marker.png" + > + <img + v-if="editionService.geom_type === 'polygon'" + class="list-image-type" + src="@/assets/img/polygon.png" + > + </a> + + <div v-else> <a :class="{ active: isEditing }" @click="update" @@ -56,11 +65,19 @@ export default { name: 'EditingToolbar', + props: { + map: { + type: Object, + default: null, + }, + }, + data() { return { editionService: editionService, isEditing: false, - isDeleting: false + isDeleting: false, + isSnapEnabled: false, }; }, @@ -70,14 +87,6 @@ export default { }, }, - watch: { - showDrawTool(newValue) { - if (!newValue && !this.isEditing && !this.isDeleting) { - this.isEditing = true; - } - } - }, - methods: { update() { editionService.activeUpdateFeature(); @@ -89,7 +98,14 @@ export default { this.isEditing = false; this.isDeleting = true; }, - + toggleSnap() { + if (this.isSnapEnabled) { + editionService.removeSnapInteraction(this.map); + } else { + editionService.addSnapInteraction(this.map); + } + this.isSnapEnabled = !this.isSnapEnabled; + } } }; </script> @@ -135,6 +151,15 @@ export default { i { margin: 0; vertical-align: middle; + &.magnet { + transform: rotate(90deg); + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + opacity: .85; + } } } diff --git a/src/services/edition-service.js b/src/services/edition-service.js index 850bc21f9808eaf4082f4e122c9084955d0ed913..2d4ccdea73e74f53786dec122bf9396add15fe99 100644 --- a/src/services/edition-service.js +++ b/src/services/edition-service.js @@ -1,4 +1,4 @@ -import { Draw } from 'ol/interaction'; +import { Draw, Snap } from 'ol/interaction'; import GeometryType from 'ol/geom/GeometryType'; import Modify from 'ol/interaction/Modify'; import Select from 'ol/interaction/Select'; @@ -267,8 +267,44 @@ const editionService = { removeActiveFeatures() { this.drawnFeature = null; this.featureToEdit = null; - } + }, + + addSnapInteraction(map) { + // The snap interaction must be added after the Modify and Draw interactions + // in order for its map browser event handlers to be fired first. Its handlers + // are responsible of doing the snapping. + + // Since we can't give a list of source to snap, + // we use this workaround, an interaction collection: https://github.com/openlayers/openlayers/issues/7100 + let interactions = []; + map.getLayers().forEach((layer) => { + if (layer instanceof VectorLayer) { + let interaction = new Snap({ + source: layer.getSource() + }); + interactions.push(interaction); + } + }); + + for(let snap of interactions ) { + map.addInteraction(snap); + } + }, + removeSnapInteraction(map) { + // Find the double click interaction that is on the map. + let interactions = []; + map.getInteractions().forEach(function (interaction) { + if (interaction instanceof Snap) { + interactions.push(interaction); + } + }); + + // Remove the interaction from the map. + for(let snap of interactions ) { + map.removeInteraction(snap); + } + } }; diff --git a/src/services/map-service.js b/src/services/map-service.js index 63e4204c00689cba3b4120faf5aa77b7abc72ef1..c162d4009364724e3a9900b79e0f348b4330c0e4 100644 --- a/src/services/map-service.js +++ b/src/services/map-service.js @@ -144,7 +144,7 @@ const mapService = { layerFilter: (l) => l === this.mvtLayer || this.olLayer }); //* prepare popup content - if (features && features.length > 0) { + if (features && features.length > 0 && features[0].id_) { const popupContent = this._createContentPopup(features[0], this.featureTypes); this.content.innerHTML = popupContent.html; this.overlay.setPosition(event.coordinate); @@ -554,7 +554,7 @@ const mapService = { Statut : ${status} </div> <div> - Type : <a id="goToFeatureTypeDetail" class="pointer"> ${feature_type.title} </a> + Type : ${ feature_type ? '<a id="goToFeatureTypeDetail" class="pointer">' + feature_type.title + '</a>' : 'Type de signalement inconnu' } </div> <div> Dernière mise à jour : ${date_maj} diff --git a/src/views/Feature/FeatureEdit.vue b/src/views/Feature/FeatureEdit.vue index d671473992d8d529bb0eb0fdc0c915b6e78647bc..b8b41516a577af7dbc2ca4c1c312463c9a778fcc 100644 --- a/src/views/Feature/FeatureEdit.vue +++ b/src/views/Feature/FeatureEdit.vue @@ -265,7 +265,10 @@ </div> <SidebarLayers v-if="basemaps && map" /> - <EditingToolbar v-if="basemaps && map && (feature_type && !feature_type.geom_type.includes('multi'))" /> + <EditingToolbar + v-if="basemaps && map && (feature_type && !feature_type.geom_type.includes('multi'))" + :map="map" + /> </div> </div> @@ -985,6 +988,14 @@ export default { }); }, + enableSnap() { + editionService.addSnapInteraction(this.map); + }, + + disableSnap() { + editionService.removeSnapInteraction(this.map); + }, + getFeatureAttachments() { featureAPI .getFeatureAttachments(this.$route.params.slug_signal)