GalleryMap.vue 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <template>
  2. <div class="gallery-map wh-100">
  3. <div class="gallery-map-wrapper" :style="`--max: ${max}px;`">
  4. <div class="rows" v-if="dots && max">
  5. <div
  6. v-for="(row, y) in dots" :key="y"
  7. class="row"
  8. :class="{ sub: y % 2 === 0 }"
  9. >
  10. <div
  11. v-for="(dot, x) in row" :key="`${y}-${x}`"
  12. class="dot" :class="{ current: dot === node }"
  13. >
  14. <img
  15. v-if="dot"
  16. :src="dot.image.url"
  17. :alt="dot.image.alt"
  18. @click="$emit('open-creation', dot.id)"
  19. >
  20. </div>
  21. </div>
  22. </div>
  23. </div>
  24. </div>
  25. </template>
  26. <script>
  27. import { shuffle } from '@/helpers/common'
  28. export default {
  29. name: 'GalleryMap',
  30. props: {
  31. nodes: { type: Array, required: true },
  32. node: { type: Object, required: true },
  33. visible: { type: Boolean, required: true }
  34. },
  35. data () {
  36. return {
  37. dots: undefined,
  38. size: [0, 0],
  39. max: undefined
  40. }
  41. },
  42. watch: {
  43. visible (visible) {
  44. if (visible) {
  45. this.defineSize()
  46. }
  47. }
  48. },
  49. methods: {
  50. setDots () {
  51. const nodesLen = this.nodes.length
  52. const sqrt = Math.ceil(Math.sqrt(nodesLen))
  53. const rows = Math.floor(Math.sqrt(Math.pow(sqrt, 2) / 2))
  54. const len = rows + 1
  55. let max = rows * len * 2
  56. let extra = 0
  57. while (max - nodesLen < 0) {
  58. extra += 1
  59. max += extra % 2 === 0 ? rows : len
  60. }
  61. const nodes = shuffle([...this.nodes, ...Array(max - nodesLen).fill(undefined)])
  62. const dots = []
  63. for (var y = 0; y < len + rows + extra; y++) {
  64. const x = y % 2 === 0 ? rows : len
  65. dots.push(nodes.splice(0, x))
  66. }
  67. this.size = [len, len + rows + extra]
  68. this.dots = dots
  69. },
  70. defineSize () {
  71. const [x, y] = this.size
  72. const { offsetWidth, offsetHeight } = document.querySelector('.gallery-map-wrapper')
  73. const h = offsetHeight / (y * 2 - 1)
  74. const w = offsetWidth / (x * 2 - 1)
  75. this.max = Math.min(Math.min(h, w), 100)
  76. }
  77. },
  78. created () {
  79. this.setDots()
  80. }
  81. }
  82. </script>
  83. <style lang="scss" scoped>
  84. .gallery-map {
  85. &-wrapper {
  86. width: 100%;
  87. position: relative;
  88. height: 100%;
  89. }
  90. .rows {
  91. position: absolute;
  92. display: flex;
  93. flex-direction: column;
  94. justify-content: space-between;
  95. align-items: center;
  96. height: 100%;
  97. width: 100%;
  98. }
  99. .row {
  100. display: flex;
  101. justify-content: space-between;
  102. width: 100%;
  103. &.sub {
  104. justify-content: space-around;
  105. }
  106. }
  107. .dot {
  108. display: flex;
  109. width: var(--max);
  110. height: var(--max);
  111. img {
  112. width: 100%;
  113. height: 100%;
  114. object-fit: cover;
  115. margin: auto;
  116. cursor: pointer;
  117. }
  118. &.current img {
  119. border: 5px solid theme-color('creation');
  120. }
  121. }
  122. }
  123. </style>