Przeglądaj źródła

fix map zoom behavior

Olivier Massot 4 lat temu
rodzic
commit
ae778824be
2 zmienionych plików z 55 dodań i 40 usunięć
  1. 32 23
      components/Ui/Map/Structures.vue
  2. 23 17
      pages/structures/index.vue

+ 32 - 23
components/Ui/Map/Structures.vue

@@ -57,23 +57,20 @@ declare module 'vue/types/vue' {
   }
 }
 
+const METROPOLE_BOUNDS = new L.LatLngBounds([51.03, -5.78], [41.2, 9.70])
+
 export default Vue.extend({
   props: {
     structures: {
       type: Array as () => Array<Structure>,
       required: false,
       default: () => []
-    },
-    zoomAtStart: {
-      type: Boolean,
-      required: false,
-      default: false
     }
   },
   data () {
     return {
       map: null,
-      defaultBounds: new L.LatLngBounds([51.03, -5.78], [41.2, 9.70]),
+      defaultBounds: METROPOLE_BOUNDS,
       shortcuts: [
         { src: '/images/metropole.png', alt: 'Metropole', bounds: [[51.03, -5.78], [41.2, 9.70]] },
         { src: '/images/guadeloupe.png', alt: 'Guadeloupe', bounds: [[16.62, -62.03], [15.74, -60.97]] },
@@ -82,7 +79,9 @@ export default Vue.extend({
         { src: '/images/la_reunion.png', alt: 'La Réunion', bounds: [[-20.65, 54.92], [-21.65, 56.15]] },
         { src: '/images/guyane.png', alt: 'Guyane', bounds: [[6.24, -54.62], [1.87, -50.59]] }
       ],
-      zoomRequired: this.zoomAtStart
+      zoomRequired: false,
+      nextZoomIsDefault: false,
+      firstPopulate: true
     }
   },
   watch: {
@@ -90,13 +89,12 @@ export default Vue.extend({
       if (oldVal !== newVal) {
         this.populateMarkers()
       }
-
       if (this.zoomRequired) {
-        this._applyZoom()
+        this.fitBoundsToMarkers()
       }
     }
   },
-  mounted () {
+  async mounted () {
     const defaultCenter: L.LatLngTuple = [46.71, 1.94]
     const defaultZoom: number = 5.5
     const layerSource: string = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png'
@@ -108,14 +106,14 @@ export default Vue.extend({
     this.map.setView(defaultCenter, defaultZoom)
     L.tileLayer(layerSource, { attribution }).addTo(this.map)
 
-    this.populateMarkers()
+    await this.populateMarkers()
 
     this.map.on('zoomend moveend', () => {
       this.$emit('boundsUpdated', this.map.getBounds())
     })
 
     if (this.zoomRequired) {
-      this._applyZoom()
+      this.fitBoundsToMarkers()
     }
   },
   beforeDestroy (): void {
@@ -124,7 +122,7 @@ export default Vue.extend({
     }
   },
   methods: {
-    populateMarkers (): void {
+    populateMarkers () {
       // remove any existant marker layers
       this.map.eachLayer((layer: L.Layer) => {
         if (layer instanceof L.MarkerClusterGroup) {
@@ -142,17 +140,30 @@ export default Vue.extend({
         clusters.addLayer(marker)
       }
       this.map.addLayer(clusters)
+
+      if (this.firstPopulate) {
+        if (this.structures.length > 0) { // map is considered as mounted only when the first results are diplayed on it
+          this.$emit('mounted')
+          this.firstPopulate = false
+        }
+      } else {
+        this.$emit('populated')
+      }
     },
     setMapBounds (bounds: L.LatLngBoundsExpression, padding: [number, number] = [0, 0]): void {
       this.map.fitBounds(bounds, { padding }) // << without this, the new bounds may not be properly set when the current view overlaps the new bounds.
     },
     resetBounds (): void {
-      this.setMapBounds(this.defaultBounds)
+      this.setMapBounds(
+        this.defaultBounds,
+        (this.defaultBounds === METROPOLE_BOUNDS ? [0, 0] : [80, 80]) as [number, number]
+      )
     },
-    zoomOnResults (): void {
+    fitNextResults (setAsDefault = false) {
       this.zoomRequired = true
+      this.nextZoomIsDefault = setAsDefault
     },
-    _fitBoundsToMarkers (): boolean {
+    fitBoundsToMarkers (): boolean {
       const coords: L.LatLngBoundsLiteral = this.structures.filter(
         (s: Structure) => {
           return (
@@ -167,15 +178,13 @@ export default Vue.extend({
       if (!(coords.length > 0)) {
         return false
       }
+
       this.setMapBounds(coords, [80, 80])
-      return true
-    },
-    _applyZoom (): void {
-      const zoomed = this._fitBoundsToMarkers()
-      if (!zoomed) {
-        this.setMapBounds(this.defaultBounds)
+
+      if (this.nextZoomIsDefault) {
+        this.defaultBounds = coords
       }
-      this.zoomRequired = false
+      return true
     }
   }
 })

+ 23 - 17
pages/structures/index.vue

@@ -30,7 +30,8 @@
           <UiMapStructures
             ref="map"
             :structures="filteredStructures"
-            :zoom-at-start="mapZoomAtStart"
+            @mounted="mapMounted"
+            @populated="mapPopulated"
             @boundsUpdated="mapBoundsFilterChanged"
           />
         </no-ssr>
@@ -352,7 +353,7 @@ export default Vue.extend({
       distanceFilter: null as number | null,
       mapBoundsFilter: null as LatLngBounds | null,
       mapBoundsFilterStarted: false, // map bounds filter is only activated when the map bounds are updated
-      mapZoomAtStart: false
+      mapZoomExpected: false
     }
   },
   async fetch () {
@@ -371,14 +372,12 @@ export default Vue.extend({
             this.federations.push(f)
           }
         }
-
-        // zoom on map markers (except if the parent structure is the CMF)
-        if (this.parent !== CMF_ID) {
-          this.mapZoomAtStart = true
-        }
       })
   },
   computed: {
+    parentIsCmf (): Boolean {
+      return this.parent === CMF_ID
+    },
     onMapFilteredStructures (): Array<Structure> {
       if (this.mapview && this.mapBoundsFilterStarted) {
         return this.filteredStructures.filter((s) => {
@@ -411,8 +410,17 @@ export default Vue.extend({
   methods: {
     viewChanged (e: number) {
       this.view = (e === 0) ? 'map' : 'list'
-      if (this.mapview) {
-        this.mapZoomAtStart = true
+    },
+    mapMounted () {
+      // zoom on map markers and set it as the default view (except if the parent structure is the CMF)
+      if (!this.parentIsCmf) {
+        this.fitMapToResults(true)
+      }
+    },
+    mapPopulated () {
+      // zoom on map markers (except if the parent structure is the CMF)
+      if (!this.parentIsCmf) {
+        this.fitMapToResults()
       }
     },
     textFilterChanged (newVal: string) {
@@ -426,15 +434,11 @@ export default Vue.extend({
       this.search()
     },
     resetMap (): void {
-      const map = this.$refs.map as any
-      map.resetBounds()
-      if (this.parent !== CMF_ID) {
-        this.fitMapToResults()
-      }
+      (this.$refs.map as any).resetBounds()
       this.mapBoundsFilterStarted = false
     },
-    fitMapToResults (): void {
-      (this.$refs.map as any).zoomOnResults()
+    fitMapToResults (setAsDefault = false): void {
+      (this.$refs.map as any).fitNextResults(setAsDefault)
     },
     mapBoundsFilterChanged (newBounds: LatLngBounds) {
       this.mapBoundsFilterStarted = true
@@ -450,7 +454,9 @@ export default Vue.extend({
       this.mapBoundsFilter = null
       const addressSearch = this.$refs.addressSearch as any
       addressSearch.clear()
-      this.resetMap()
+      if (this.mapview) {
+        this.resetMap()
+      }
       this.filteredStructures = this.structures
     },
     /**