photo.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <template>
  2. <img :src="tempPhoto" class="face-animation" v-if="tempPhoto" ref="coverRef">
  3. <div class="photo-layout">
  4. <ButtonPane class="photo-btn fun-ctrl" size="80" @click="photo">
  5. <ui-icon type="photo" class="icon" />
  6. </ButtonPane>
  7. <img
  8. :src="showCoverUrl"
  9. class="cover"
  10. :style="{opacity: showCoverUrl ? '1' : 0}"
  11. @click="router.push(writeRouteName.photos)"
  12. >
  13. </div>
  14. </template>
  15. <script setup lang="ts">
  16. import UiIcon from "@/components/base/components/icon/index.vue";
  17. import ButtonPane from "@/components/button-pane/index.vue";
  18. import {list} from '@/store/measure'
  19. import {fixPoints} from '@/store/fixPoint'
  20. import {baseLines} from '@/store/baseLine'
  21. import {basePoints} from '@/store/basePoint'
  22. import {photos} from '@/store/photos'
  23. import { useSDK } from '@/hook/useLaser'
  24. import {genUseLoading} from "@/hook";
  25. import {base64ToBlob, getId} from "@/utils";
  26. import {nextTick, ref} from "vue";
  27. import {api, uploadImage} from "@/store/sync";
  28. import {router, writeRouteName} from "@/router";
  29. import {Pos, Pos3D} from "@/sdk";
  30. const showCoverUrl = ref<string>()
  31. if (photos.value[photos.value.length - 1]?.url) {
  32. api.getFile(photos.value[photos.value.length - 1]?.url)
  33. .then(url => showCoverUrl.value = url)
  34. }
  35. const tempPhoto = ref<string>();
  36. const coverRef = ref<HTMLImageElement>()
  37. const getCurrentScreen = (pos: Pos3D): Pos => {
  38. const sdk = useSDK()
  39. const data = sdk.scene.getScreenByPoint(pos)
  40. return data.trueSide ? data.pos : null
  41. }
  42. const getCurrentScreens = (poss: Array<Pos3D>): Array<Pos> =>
  43. poss.map(getCurrentScreen).filter(pos => !!pos);
  44. const photo = genUseLoading(async () => {
  45. const sdk = useSDK()
  46. const dom = sdk.scene.el
  47. dom.style.pointerEvents = "none"
  48. const data = sdk.scene.screenshot(
  49. dom.offsetWidth,
  50. dom.offsetHeight
  51. )
  52. const {dataUrl: base64} = await data.finishPromise
  53. const blob = base64ToBlob(base64)
  54. tempPhoto.value = URL.createObjectURL(blob)
  55. const upload = uploadImage(blob)
  56. await nextTick();
  57. const handler = async () => {
  58. coverRef.value.removeEventListener("animationend", handler)
  59. showCoverUrl.value = tempPhoto.value
  60. tempPhoto.value = null
  61. baseLines.value.concat(list.value).forEach(item => {
  62. item.show = false
  63. })
  64. await nextTick()
  65. const url = await upload
  66. photos.value.push({
  67. id: getId(),
  68. url: url,
  69. time: new Date().getTime(),
  70. meterPerPixel: data.meterPerPixel,
  71. measures: list.value
  72. .map(data => {
  73. const pos = getCurrentScreens(data.points)
  74. if (pos.length) {
  75. return { pos, dis: sdk.carry.measureMap.get(data).getDistance().value }
  76. } else {
  77. return null
  78. }
  79. })
  80. .filter(poss => poss),
  81. baseLines: baseLines.value
  82. .map(data => getCurrentScreens(data.points))
  83. .filter(poss => poss.length),
  84. fixPoints: fixPoints.value.map(data => ({ text: data.text, pos: getCurrentScreen(data.pos) })),
  85. basePoints: getCurrentScreens(basePoints.value.map(data => data.pos))
  86. })
  87. showCoverUrl.value = await api.getFile(url)
  88. dom.style.pointerEvents = "all"
  89. baseLines.value.concat(list.value).forEach(item => {
  90. item.show = true
  91. })
  92. }
  93. coverRef.value.addEventListener("animationend", handler)
  94. })
  95. </script>
  96. <style scoped lang="scss">
  97. .photo-layout {
  98. position: absolute;
  99. z-index: 2;
  100. right: var(--boundMargin);
  101. top: 50%;
  102. transform: translateY(-50%);
  103. text-align: center;
  104. color: #fff;
  105. font-size: 20px;
  106. .icon {
  107. position: absolute;
  108. transform: translateX(-50%);
  109. }
  110. }
  111. .photo-btn {
  112. position: static;
  113. margin-bottom: 16px;
  114. .icon {
  115. font-size: 28px;
  116. }
  117. }
  118. .cover {
  119. width: 48px;
  120. height: 48px;
  121. border: 1px solid #fff;
  122. object-fit: cover;
  123. border-radius: 24px;
  124. overflow: hidden;
  125. }
  126. .face-animation {
  127. pointer-events: none;
  128. position: absolute;
  129. left: 0;
  130. right: 0;
  131. top: 0;
  132. bottom: 0;
  133. animation: 1s linear 1 both photo-face;
  134. }
  135. .face-animation.start {
  136. }
  137. @keyframes photo-face {
  138. from {
  139. left: 0;
  140. top: 0;
  141. width: 100vw;
  142. height: 100vh;
  143. margin-left: 0;
  144. margin-top: 0;
  145. border-radius: 0;
  146. }
  147. 30%,
  148. 40%,
  149. to {
  150. left: 50vw;
  151. top: 100px;
  152. width: 48px;
  153. height: 48px;
  154. margin-left: -24px;
  155. border-radius: 50%;
  156. z-index: 3
  157. }
  158. 70% {
  159. left: calc(80vw - 60px);
  160. top: calc(calc(50% - 48px) / 1.5);
  161. }
  162. to {
  163. left: calc(100vw - 63px);
  164. top: calc(calc(50%) + 20px);
  165. }
  166. }
  167. </style>