From 1aec00958ac2e7077ccb6a84c8bb7b8d892ecf90 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timoth=C3=A9e=20Poussard?= <tpoussard@neogeo.fr>
Date: Tue, 22 Aug 2023 18:39:10 +0200
Subject: [PATCH 1/4] add geolocation tracking to feature edit

---
 src/services/map-service.js       | 73 ++++++++++++++++++++++++++++++-
 src/views/Feature/FeatureEdit.vue | 50 +++++++++++++++++++--
 2 files changed, 118 insertions(+), 5 deletions(-)

diff --git a/src/services/map-service.js b/src/services/map-service.js
index 5aefb5ea..e936cc9f 100644
--- a/src/services/map-service.js
+++ b/src/services/map-service.js
@@ -2,7 +2,7 @@ import TileWMS from 'ol/source/TileWMS';
 import { View, Map } from 'ol';
 import { ScaleLine, Zoom, Attribution, FullScreen } from 'ol/control';
 import TileLayer from 'ol/layer/Tile';
-import { transform, transformExtent } from 'ol/proj.js';
+import { transform, transformExtent, fromLonLat } from 'ol/proj.js';
 import { defaults } from 'ol/interaction';
 import XYZ from 'ol/source/XYZ';
 import VectorTileLayer from 'ol/layer/VectorTile';
@@ -16,8 +16,10 @@ import {
 import { asArray } from 'ol/color';
 import VectorSource from 'ol/source/Vector';
 import VectorLayer from 'ol/layer/Vector';
-import { fromLonLat } from 'ol/proj.js';
 import OverlayPositioning from 'ol/OverlayPositioning';
+import Geolocation from 'ol/Geolocation.js';
+import Feature from 'ol/Feature.js';
+import Point from 'ol/geom/Point.js';
 
 import axios from '@/axios-client.js';
 import router from '@/router';
@@ -39,6 +41,8 @@ const mapService = {
 
   queryParams: {},
 
+  geolocation: undefined,
+
 
   getMap() {
     return this.map;
@@ -58,6 +62,7 @@ const mapService = {
       zoom,
       zoomControl = true,
       fullScreenControl = false,
+      geolocationControl = false,
       interactions = { doubleClickZoom: false, mouseWheelZoom: false, dragPan: true },
       controls = [
         new Attribution({ collapsible: false }),
@@ -92,6 +97,10 @@ const mapService = {
     if (zoomControl) {
       this.map.addControl(new Zoom({ zoomInTipLabel: 'Zoomer', zoomOutTipLabel: 'Dézoomer' }));
     }
+    if (geolocationControl) {
+      this.initGeolocation();
+    }
+
     this.map.once('rendercomplete', () => {
       this.map.updateSize();
     });
@@ -120,6 +129,66 @@ const mapService = {
     return this.map;
   },
 
+  initGeolocation() {
+    this.geolocation = new Geolocation({
+      // enableHighAccuracy must be set to true to have the heading value.
+      trackingOptions: {
+        enableHighAccuracy: true,
+      },
+      projection: this.map.getView().getProjection(),
+    });
+    
+    // handle this.geolocation error.
+    this.geolocation.on('error', (error) =>  {
+      console.error(error.message);
+    });
+    
+    /* const accuracyFeature = new Feature();
+    this.geolocation.on('change:accuracyGeometry', () => {
+      accuracyFeature.setGeometry(this.geolocation.getAccuracyGeometry());
+    }); */
+    
+    const positionFeature = new Feature();
+    positionFeature.setStyle(
+      new Style({
+        image: new Circle({
+          radius: 6,
+          fill: new Fill({
+            color: '#3399CC',
+          }),
+          stroke: new Stroke({
+            color: '#fff',
+            width: 2,
+          }),
+        }),
+      })
+    );
+    
+    this.geolocation.on('change:position', () => {
+      const coordinates = this.geolocation.getPosition();
+      positionFeature.setGeometry(coordinates ? new Point(coordinates) : null);
+      if (coordinates) {
+        this.map.getView().animate(
+          { zoom: 16 },
+          { center: coordinates },
+          { duration: 1000 }
+        );
+      }
+    });
+    
+    new VectorLayer({
+      map: this.map,
+      source: new VectorSource({
+        features: [positionFeature],
+        //features: [accuracyFeature, positionFeature],
+      }),
+    });
+    console.log('initGeolocation');
+  },
+
+  toggleGeolocation(value) {
+    this.geolocation.setTracking(value);
+  },
 
   addRouterToPopup({ featureId, featureTypeSlug, index }) {
 
diff --git a/src/views/Feature/FeatureEdit.vue b/src/views/Feature/FeatureEdit.vue
index b156f07c..9e3f4533 100644
--- a/src/views/Feature/FeatureEdit.vue
+++ b/src/views/Feature/FeatureEdit.vue
@@ -15,8 +15,6 @@
 
     <form
       id="form-feature-edit"
-      action=""
-      method="post"
       enctype="multipart/form-data"
       class="ui form"
     >
@@ -252,6 +250,16 @@
             ref="map"
           >
             <SidebarLayers v-if="basemaps && map" />
+
+            <div class="geolocation-container">
+              <button
+                class="button-geolocation"
+                @click.prevent="toggleTracking"
+              >
+                <i class="crosshairs icon" />
+              </button>
+            </div>
+
             <Geocoder />
             <EditingToolbar
               v-if="isEditable"
@@ -445,6 +453,7 @@ export default {
           value: null,
         },
       },
+      tracking: false,
     };
   },
 
@@ -667,6 +676,11 @@ export default {
       this.showGeoRef = !this.showGeoRef;
     },
 
+    toggleTracking() {
+      this.tracking = !this.tracking;
+      mapService.toggleGeolocation(this.tracking);
+    },
+
     handleFileUpload() {
       this.erreurUploadMessage = '';
       this.file = this.$refs.file.files[0];
@@ -970,7 +984,8 @@ export default {
         mapDefaultViewZoom,
         maxZoom: this.project.map_max_zoom_level,
         interactions : { doubleClickZoom :false, mouseWheelZoom:true, dragPan:true },
-        fullScreenControl: true
+        fullScreenControl: true,
+        geolocationControl: true,
       });
       const currentFeatureId = this.$route.params.slug_signal;
       const url = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}v2/features/?feature_type__slug=${this.$route.params.slug_type_signal}&project__slug=${this.$route.params.slug}&output=geojson`;
@@ -1035,6 +1050,35 @@ export default {
   width: 100%;
   border: 1px solid grey;
 }
+
+
+div.geolocation-container {
+  position: absolute;
+  right: 0.5em;
+  /* each button have .5em space between, zoom buttons are 60px high and full screen button is 34px high */
+  top: calc(1.5em + 60px + 34px + 100px);
+  z-index: 1000;
+  border: 2px solid rgba(0,0,0,.2);
+  background-clip: padding-box;
+  padding: 0;
+  border-radius: 2px;
+  display: flex;
+}
+button.button-geolocation {
+  border: none;
+  padding: 0;
+  margin: 0;
+  text-align: center;
+  background-color: #fff;
+  color: rgb(39, 39, 39);
+  width: 28px;
+  height: 28px;
+  font: 700 18px Lucida Console,Monaco,monospace;
+  border-radius: 2px;
+  line-height: 1.15;
+  cursor: pointer;
+}
+
 #get-geom-from-image-file {
   margin-bottom: 5px;
 }
-- 
GitLab


From c5f84f22dc316be39a6f777eb5809e56f7475f89 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timoth=C3=A9e=20Poussard?= <tpoussard@neogeo.fr>
Date: Wed, 23 Aug 2023 12:03:44 +0200
Subject: [PATCH 2/4] toggel geolocation display, create component and style

---
 src/components/Map/Geolocation.vue | 68 ++++++++++++++++++++++++++++++
 src/services/map-service.js        | 58 +++++++++++++++----------
 src/views/Feature/FeatureEdit.vue  | 43 ++-----------------
 3 files changed, 108 insertions(+), 61 deletions(-)
 create mode 100644 src/components/Map/Geolocation.vue

diff --git a/src/components/Map/Geolocation.vue b/src/components/Map/Geolocation.vue
new file mode 100644
index 00000000..51cced95
--- /dev/null
+++ b/src/components/Map/Geolocation.vue
@@ -0,0 +1,68 @@
+<template>
+  <div class="geolocation-container">
+    <button
+      :class="['button-geolocation', { tracking }]"
+      @click.prevent="toggleTracking"
+    >
+      <i class="crosshairs icon" />
+    </button>
+  </div>
+</template>
+
+<script>
+
+import mapService from '@/services/map-service';
+
+export default {
+  name: 'Geolocation',
+
+  data() {
+    return {
+      tracking: false,
+    };
+  },
+
+  methods: {
+    toggleTracking() {
+      this.tracking = !this.tracking;
+      mapService.toggleGeolocation(this.tracking);
+    },
+  }
+};
+</script>
+
+<style>
+div.geolocation-container {
+  position: absolute;
+  right: 0.5em;
+  /* each button have .5em space between, zoom buttons are 60px high and full screen button is 34px high */
+  z-index: 1000;
+  border: 2px solid rgba(0,0,0,.2);
+  background-clip: padding-box;
+  padding: 0;
+  border-radius: 2px;
+  display: flex;
+}
+button.button-geolocation {
+  border: none;
+  padding: 0;
+  margin: 0;
+  text-align: center;
+  background-color: #fff;
+  color: rgb(39, 39, 39);
+  width: 28px;
+  height: 28px;
+  font: 700 18px Lucida Console,Monaco,monospace;
+  border-radius: 2px;
+  line-height: 1.15;
+  cursor: pointer;
+}
+button.button-geolocation.tracking {
+  background-color: rgba(255, 145, 0, 0.904);
+  color: #fff;
+}
+button.button-geolocation i {
+  margin: 0;
+  vertical-align: top; /* strangely top is the only value that center at middle */
+}
+</style>
diff --git a/src/services/map-service.js b/src/services/map-service.js
index e936cc9f..7d2330de 100644
--- a/src/services/map-service.js
+++ b/src/services/map-service.js
@@ -28,6 +28,19 @@ import { statusChoices } from '@/utils';
 
 let dictLayersToMap = {};
 
+const geolocationStyle = new Style({
+  image: new Circle({
+    radius: 6,
+    fill: new Fill({
+      color: '#3399CC',
+    }),
+    stroke: new Stroke({
+      color: '#fff',
+      width: 2,
+    }),
+  }),
+})
+
 const mapService = {
   layers: [],
 
@@ -43,6 +56,7 @@ const mapService = {
 
   geolocation: undefined,
 
+  geolocationSource: null,
 
   getMap() {
     return this.map;
@@ -149,20 +163,7 @@ const mapService = {
     }); */
     
     const positionFeature = new Feature();
-    positionFeature.setStyle(
-      new Style({
-        image: new Circle({
-          radius: 6,
-          fill: new Fill({
-            color: '#3399CC',
-          }),
-          stroke: new Stroke({
-            color: '#fff',
-            width: 2,
-          }),
-        }),
-      })
-    );
+    positionFeature.setStyle( geolocationStyle );
     
     this.geolocation.on('change:position', () => {
       const coordinates = this.geolocation.getPosition();
@@ -175,19 +176,32 @@ const mapService = {
         );
       }
     });
-    
+
+    this.geolocationSource = new VectorSource({
+      features: [positionFeature],
+      //features: [accuracyFeature, positionFeature],
+    });    
     new VectorLayer({
       map: this.map,
-      source: new VectorSource({
-        features: [positionFeature],
-        //features: [accuracyFeature, positionFeature],
-      }),
+      source: this.geolocationSource,
     });
-    console.log('initGeolocation');
   },
 
-  toggleGeolocation(value) {
-    this.geolocation.setTracking(value);
+  displayGeolocationPoint(isVisible) {
+    let features = this.geolocationSource.getFeatures();
+    if (!features) return;
+    const hiddenStyle = new Style(); // hide the feature
+    for (let i = 0; i < features.length; i++) {
+      features[i].setStyle(isVisible ? geolocationStyle : hiddenStyle);
+    }
+  },
+
+
+  toggleGeolocation(isTracking) {
+    this.geolocation.setTracking(isTracking);
+    if (this.geolocationSource) {
+      this.displayGeolocationPoint(isTracking);
+    } 
   },
 
   addRouterToPopup({ featureId, featureTypeSlug, index }) {
diff --git a/src/views/Feature/FeatureEdit.vue b/src/views/Feature/FeatureEdit.vue
index 9e3f4533..f61a17c8 100644
--- a/src/views/Feature/FeatureEdit.vue
+++ b/src/views/Feature/FeatureEdit.vue
@@ -250,16 +250,7 @@
             ref="map"
           >
             <SidebarLayers v-if="basemaps && map" />
-
-            <div class="geolocation-container">
-              <button
-                class="button-geolocation"
-                @click.prevent="toggleTracking"
-              >
-                <i class="crosshairs icon" />
-              </button>
-            </div>
-
+            <Geolocation />
             <Geocoder />
             <EditingToolbar
               v-if="isEditable"
@@ -383,6 +374,7 @@ import Dropdown from '@/components/Dropdown.vue';
 import SidebarLayers from '@/components/Map/SidebarLayers';
 import EditingToolbar from '@/components/Map/EditingToolbar';
 import Geocoder from '@/components/Map/Geocoder';
+import Geolocation from '@/components/Map/Geolocation';
 import featureAPI from '@/services/feature-api';
 
 import mapService from '@/services/map-service';
@@ -402,6 +394,7 @@ export default {
     Dropdown,
     SidebarLayers,
     Geocoder,
+    Geolocation,
     EditingToolbar,
     FeatureExtraForm,
   },
@@ -453,7 +446,6 @@ export default {
           value: null,
         },
       },
-      tracking: false,
     };
   },
 
@@ -676,11 +668,6 @@ export default {
       this.showGeoRef = !this.showGeoRef;
     },
 
-    toggleTracking() {
-      this.tracking = !this.tracking;
-      mapService.toggleGeolocation(this.tracking);
-    },
-
     handleFileUpload() {
       this.erreurUploadMessage = '';
       this.file = this.$refs.file.files[0];
@@ -1053,32 +1040,10 @@ export default {
 
 
 div.geolocation-container {
-  position: absolute;
-  right: 0.5em;
   /* each button have .5em space between, zoom buttons are 60px high and full screen button is 34px high */
   top: calc(1.5em + 60px + 34px + 100px);
-  z-index: 1000;
-  border: 2px solid rgba(0,0,0,.2);
-  background-clip: padding-box;
-  padding: 0;
-  border-radius: 2px;
-  display: flex;
-}
-button.button-geolocation {
-  border: none;
-  padding: 0;
-  margin: 0;
-  text-align: center;
-  background-color: #fff;
-  color: rgb(39, 39, 39);
-  width: 28px;
-  height: 28px;
-  font: 700 18px Lucida Console,Monaco,monospace;
-  border-radius: 2px;
-  line-height: 1.15;
-  cursor: pointer;
 }
-
+  
 #get-geom-from-image-file {
   margin-bottom: 5px;
 }
-- 
GitLab


From 331f5bbcddd5c9917d8b0b8af9b9a0b904cea131 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timoth=C3=A9e=20Poussard?= <tpoussard@neogeo.fr>
Date: Wed, 23 Aug 2023 13:01:24 +0200
Subject: [PATCH 3/4] adapt geolocation to other map pages

---
 src/components/Map/EditingToolbar.vue    |  5 +++--
 src/components/Map/Geocoder.vue          |  5 +++--
 src/components/Map/Geolocation.vue       | 12 +++++-------
 src/services/map-service.js              | 10 ++++++----
 src/store/modules/map.store.js           |  3 ++-
 src/views/Feature/FeatureDetail.vue      | 12 +++++++++++-
 src/views/Feature/FeatureEdit.vue        |  3 +--
 src/views/Project/FeaturesListAndMap.vue | 13 +++++++++++--
 src/views/Project/ProjectDetail.vue      |  8 ++++++++
 9 files changed, 50 insertions(+), 21 deletions(-)

diff --git a/src/components/Map/EditingToolbar.vue b/src/components/Map/EditingToolbar.vue
index 97c86db1..33c86323 100644
--- a/src/components/Map/EditingToolbar.vue
+++ b/src/components/Map/EditingToolbar.vue
@@ -117,8 +117,9 @@ export default {
 
 .editionToolbar{
   position: absolute;
-  // each button have .5em space between, zoom buttons are 60px high and full screen button is 34px high
-  top: calc(2em + 60px + 34px + 28px);
+  // each button have (more or less depends on borders) .5em space between
+  // zoom buttons are 60px high, geolocation and full screen button is 34px high with borders
+  top: calc(2em + 60px + 34px + 64px);
   right: 6px;
   border: 2px solid rgba(0,0,0,.2);
   border-radius: 4px;
diff --git a/src/components/Map/Geocoder.vue b/src/components/Map/Geocoder.vue
index d4644cb9..028a6a75 100644
--- a/src/components/Map/Geocoder.vue
+++ b/src/components/Map/Geocoder.vue
@@ -143,8 +143,9 @@ export default {
 .geocoder-container {
   position: absolute;
   right: 0.5em;
-  // each button have .5em space between, zoom buttons are 60px high and full screen button is 34px high
-  top: calc(1.5em + 60px + 34px);
+  // each button have (more or less depends on borders) .5em space between
+  // zoom buttons are 60px high, geolocation and full screen button is 34px high with borders
+  top: calc(1.6em + 60px + 34px + 34px);
   pointer-events: auto;
   z-index: 1000;
   border: 2px solid rgba(0,0,0,.2);
diff --git a/src/components/Map/Geolocation.vue b/src/components/Map/Geolocation.vue
index 51cced95..cc83f8c9 100644
--- a/src/components/Map/Geolocation.vue
+++ b/src/components/Map/Geolocation.vue
@@ -34,14 +34,12 @@ export default {
 <style>
 div.geolocation-container {
   position: absolute;
-  right: 0.5em;
-  /* each button have .5em space between, zoom buttons are 60px high and full screen button is 34px high */
+  right: 6px;
   z-index: 1000;
   border: 2px solid rgba(0,0,0,.2);
   background-clip: padding-box;
   padding: 0;
-  border-radius: 2px;
-  display: flex;
+  border-radius: 4px;
 }
 button.button-geolocation {
   border: none;
@@ -50,10 +48,10 @@ button.button-geolocation {
   text-align: center;
   background-color: #fff;
   color: rgb(39, 39, 39);
-  width: 28px;
-  height: 28px;
+  width: 30px;
+  height: 30px;
   font: 700 18px Lucida Console,Monaco,monospace;
-  border-radius: 2px;
+  border-radius: 4px;
   line-height: 1.15;
   cursor: pointer;
 }
diff --git a/src/services/map-service.js b/src/services/map-service.js
index 7d2330de..53c3acff 100644
--- a/src/services/map-service.js
+++ b/src/services/map-service.js
@@ -198,10 +198,12 @@ const mapService = {
 
 
   toggleGeolocation(isTracking) {
-    this.geolocation.setTracking(isTracking);
-    if (this.geolocationSource) {
-      this.displayGeolocationPoint(isTracking);
-    } 
+    if (this.geolocation) {
+      this.geolocation.setTracking(isTracking);
+      if (this.geolocationSource) {
+        this.displayGeolocationPoint(isTracking);
+      } 
+    }
   },
 
   addRouterToPopup({ featureId, featureTypeSlug, index }) {
diff --git a/src/store/modules/map.store.js b/src/store/modules/map.store.js
index f20bf643..8421ef36 100644
--- a/src/store/modules/map.store.js
+++ b/src/store/modules/map.store.js
@@ -111,7 +111,8 @@ const map = {
         maxZoom: options.maxZoom || rootState.projects.project.map_max_zoom_level,
         controls: options.controls,
         zoomControl: options.zoomControl,
-        interactions : { doubleClickZoom :false, mouseWheelZoom:true, dragPan:true }
+        interactions : { doubleClickZoom :false, mouseWheelZoom:true, dragPan:true },
+        geolocationControl: true,
       });
       const map = { ...mapService.getMap() };
       commit('SET_MAP', map);
diff --git a/src/views/Feature/FeatureDetail.vue b/src/views/Feature/FeatureDetail.vue
index a233e1b1..991bc5e1 100644
--- a/src/views/Feature/FeatureDetail.vue
+++ b/src/views/Feature/FeatureDetail.vue
@@ -42,6 +42,7 @@
                 v-if="basemaps && map"
                 ref="sidebar"
               />
+              <Geolocation />
             </div>
             <div
               id="popup"
@@ -182,6 +183,7 @@ import FeatureTable from '@/components/Feature/Detail/FeatureTable';
 import FeatureAttachements from '@/components/Feature/Detail/FeatureAttachements';
 import FeatureComments from '@/components/Feature/Detail/FeatureComments';
 import SidebarLayers from '@/components/Map/SidebarLayers';
+import Geolocation from '@/components/Map/Geolocation';
 
 import { buffer } from 'ol/extent';
 
@@ -194,6 +196,7 @@ export default {
     FeatureAttachements,
     FeatureComments,
     SidebarLayers,
+    Geolocation,
   },
 
   beforeRouteUpdate (to, from, next) {
@@ -482,7 +485,8 @@ export default {
             mouseWheelZoom: true,
             dragPan: true
           },
-          fullScreenControl: true
+          fullScreenControl: true,
+          geolocationControl: true,
         });
 
         // Update link to feature list with map zoom and center
@@ -600,6 +604,12 @@ export default {
   min-height: 250px;
   border: 1px solid grey;
 }
+div.geolocation-container {
+  /* each button have (more or less depends on borders) .5em space between */
+  /* zoom buttons are 60px high, geolocation and full screen button is 34px high with borders */
+  top: calc(1.3em + 60px + 34px);
+}
+
 .prewrap {
   white-space: pre-wrap;
 }
diff --git a/src/views/Feature/FeatureEdit.vue b/src/views/Feature/FeatureEdit.vue
index f61a17c8..92b6004a 100644
--- a/src/views/Feature/FeatureEdit.vue
+++ b/src/views/Feature/FeatureEdit.vue
@@ -384,7 +384,6 @@ import axios from '@/axios-client.js';
 import { GeoJSON } from 'ol/format';
 
 
-
 export default {
   name: 'FeatureEdit',
 
@@ -1041,7 +1040,7 @@ export default {
 
 div.geolocation-container {
   /* each button have .5em space between, zoom buttons are 60px high and full screen button is 34px high */
-  top: calc(1.5em + 60px + 34px + 100px);
+  top: calc(1.3em + 60px + 34px);
 }
   
 #get-geom-from-image-file {
diff --git a/src/views/Project/FeaturesListAndMap.vue b/src/views/Project/FeaturesListAndMap.vue
index 7d57794e..8bf9e85e 100644
--- a/src/views/Project/FeaturesListAndMap.vue
+++ b/src/views/Project/FeaturesListAndMap.vue
@@ -26,6 +26,7 @@
             v-if="basemaps && map"
             ref="sidebar"
           />
+          <Geolocation />
           <Geocoder />
         </div>
         <div 
@@ -106,8 +107,9 @@ import Geocoder from '@/components/Map/Geocoder';
 import featureAPI from '@/services/feature-api';
 
 import FeaturesListAndMapFilters from '@/components/Project/FeaturesListAndMap/FeaturesListAndMapFilters';
-import SidebarLayers from '@/components/Map/SidebarLayers';
 import FeatureListTable from '@/components/Project/FeaturesListAndMap/FeatureListTable';
+import SidebarLayers from '@/components/Map/SidebarLayers';
+import Geolocation from '@/components/Map/Geolocation';
 
 const initialPagination = {
   currentPage: 1,
@@ -123,6 +125,7 @@ export default {
     FeaturesListAndMapFilters,
     SidebarLayers,
     Geocoder,
+    Geolocation,
     FeatureListTable,
   },
 
@@ -332,7 +335,8 @@ export default {
         mapDefaultViewZoom,
         maxZoom: this.project.map_max_zoom_level,
         interactions : { doubleClickZoom :false, mouseWheelZoom:true, dragPan:true },
-        fullScreenControl: true
+        fullScreenControl: true,
+        geolocationControl: true,
       });
 
       document.addEventListener('change-layers-order', (event) => {
@@ -545,6 +549,11 @@ export default {
     z-index: 1;
   }
 }
+div.geolocation-container {
+  // each button have (more or less depends on borders) .5em space between
+  // zoom buttons are 60px high, geolocation and full screen button is 34px high with borders
+  top: calc(1.3em + 60px + 34px);
+}
 
 @media screen and (max-width: 767px) {
   #project-features {
diff --git a/src/views/Project/ProjectDetail.vue b/src/views/Project/ProjectDetail.vue
index 91aed089..ccbb8773 100644
--- a/src/views/Project/ProjectDetail.vue
+++ b/src/views/Project/ProjectDetail.vue
@@ -39,6 +39,7 @@
                 v-if="basemaps && map && !projectInfoLoading"
                 ref="sidebar"
               />
+              <Geolocation />
               <div
                 id="popup"
                 class="ol-popup"
@@ -127,6 +128,7 @@ import ProjectLastComments from '@/components/Project/Detail/ProjectLastComments
 import ProjectParameters from '@/components/Project/Detail/ProjectParameters';
 import ProjectModal from '@/components/Project/Detail/ProjectModal';
 import SidebarLayers from '@/components/Map/SidebarLayers';
+import Geolocation from '@/components/Map/Geolocation';
 
 export default {
   name: 'ProjectDetail',
@@ -139,6 +141,7 @@ export default {
     ProjectParameters,
     ProjectModal,
     SidebarLayers,
+    Geolocation,
   },
 
   filters: {
@@ -483,4 +486,9 @@ export default {
     margin-top: 0.5em;
   }
 }
+
+div.geolocation-container {
+  /* each button have .5em space between, zoom buttons are 60px high and full screen button is 34px high */
+  top: calc(1.1em + 60px);
+}
 </style>
-- 
GitLab


From 640f8493930856b9b6068633cb186435d7eff8b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timoth=C3=A9e=20Poussard?= <tpoussard@neogeo.fr>
Date: Wed, 23 Aug 2023 14:18:23 +0200
Subject: [PATCH 4/4] adapt geolocation to other map pages (fix eslint)

---
 src/services/map-service.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/services/map-service.js b/src/services/map-service.js
index 53c3acff..01d6cd8b 100644
--- a/src/services/map-service.js
+++ b/src/services/map-service.js
@@ -39,7 +39,7 @@ const geolocationStyle = new Style({
       width: 2,
     }),
   }),
-})
+});
 
 const mapService = {
   layers: [],
-- 
GitLab