Structures.vue 3.5 KB

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