Structures.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <template>
  2. <LayoutContainer>
  3. <v-responsive :aspect-ratio="1" width="100%">
  4. <no-ssr>
  5. <l-map
  6. id="map"
  7. ref="vMap"
  8. :zoom="zoom"
  9. :center="center"
  10. :bounds="bounds"
  11. :options="{scrollWheelZoom: false, zoomSnap: 0.25}"
  12. @update:bounds="boundsUpdated"
  13. >
  14. <l-tile-layer
  15. url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"
  16. attribution="&copy; <a href='http://osm.org/copyright'>OpenStreetMap</a> contributors"
  17. />
  18. <v-marker-cluster>
  19. <l-marker
  20. v-for="structure in structures"
  21. :key="structure.id"
  22. :lat-lng="[structure.latitude, structure.longitude]"
  23. >
  24. <l-popup>
  25. <b>{{ structure.name }}</b><br>
  26. {{ structure.postalCode }} {{ structure.addressCity }}<br>
  27. <a :href="structure.website" target="_blank">{{ structure.website }}</a>
  28. </l-popup>
  29. </l-marker>
  30. </v-marker-cluster>
  31. </l-map>
  32. </no-ssr>
  33. </v-responsive>
  34. <div class="advice">
  35. {{ $t("click_on_land_to_go_there") }}
  36. </div>
  37. <v-row class="map-shortcuts">
  38. <v-col v-for="shortcut in shortcuts" :key="shortcut.src" cols="2">
  39. <div @click="setMapBounds(shortcut.bounds)">
  40. <nuxt-img
  41. :src="shortcut.src"
  42. :alt="shortcut.alt"
  43. />
  44. </div>
  45. </v-col>
  46. </v-row>
  47. </LayoutContainer>
  48. </template>
  49. <script>
  50. export default {
  51. props: {
  52. structures: {
  53. type: Array,
  54. required: false,
  55. default: () => []
  56. }
  57. },
  58. data () {
  59. const defaultCenter = [46.71, 1.94]
  60. const defaultZoom = 5.75
  61. const defaultBounds = [[51.03, -5.78], [41.2, 9.70]]
  62. return {
  63. defaultCenter,
  64. defaultZoom,
  65. defaultBounds,
  66. center: defaultCenter,
  67. zoom: defaultZoom,
  68. bounds: defaultBounds,
  69. isFirstRendering: true,
  70. shortcuts: [
  71. { src: '/images/metropole.png', alt: 'Metropole', bounds: [[51.03, -5.78], [41.2, 9.70]] },
  72. { src: '/images/guadeloupe.png', alt: 'Guadeloupe', bounds: [[16.62, -62.03], [15.74, -60.97]] },
  73. { src: '/images/martinique.png', alt: 'Martinique', bounds: [[14.95, -61.43], [14.28, -60.60]] },
  74. { src: '/images/mayotte.png', alt: 'Mayotte', bounds: [[-12.51, 44.86], [-13.19, 45.45]] },
  75. { src: '/images/la_reunion.png', alt: 'La Réunion', bounds: [[-20.65, 54.92], [-21.65, 56.15]] },
  76. { src: '/images/guyane.png', alt: 'Guyane', bounds: [[6.24, -54.62], [1.87, -50.59]] }
  77. ],
  78. zoomRequired: false
  79. }
  80. },
  81. watch: {
  82. structures () {
  83. if (this.zoomRequired) {
  84. this._fitBoundsToMarkers()
  85. this.zoomRequired = false
  86. }
  87. }
  88. },
  89. methods: {
  90. setMapBounds (bounds) {
  91. this.bounds = bounds
  92. this.$refs.vMap.mapObject.fitBounds(bounds) // << without this, the new bounds may not be properly set when the current view overlaps the new bounds.
  93. },
  94. resetBounds () {
  95. this.setMapBounds(this.defaultBounds)
  96. },
  97. zoomOnResults () {
  98. this.zoomRequired = true
  99. },
  100. _fitBoundsToMarkers () {
  101. const coords = this.structures.filter(
  102. (s) => { return s.latitude && s.longitude }
  103. ).map(
  104. (s) => { return [s.latitude, s.longitude] })
  105. if (!coords.length > 0) {
  106. return
  107. }
  108. this.$refs.vMap.mapObject.fitBounds(coords)
  109. },
  110. boundsUpdated (newBounds) {
  111. // do not send and event on first automatic rendering
  112. if (this.isFirstRendering) {
  113. this.isFirstRendering = false
  114. return
  115. }
  116. this.$emit('boundsUpdated', newBounds)
  117. }
  118. }
  119. }
  120. </script>
  121. <style scoped>
  122. #map {
  123. height: 100%;
  124. width: 100%;
  125. }
  126. .advice {
  127. margin: 1rem 0;
  128. color: #262626;
  129. font-weight: 750;
  130. text-align: center;
  131. font-size: 0.9rem;
  132. width: 100%;
  133. }
  134. .map-shortcuts .col {
  135. padding: 12px 6px;
  136. }
  137. .map-shortcuts img {
  138. border: solid 1px #000;
  139. width: 75px;
  140. height: 75px;
  141. }
  142. </style>