pano.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. <template>
  2. <div class="pano-layout" v-loading="loading">
  3. <canvas ref="panoDomRef"></canvas>
  4. <div class="btns">
  5. <el-button
  6. size="large"
  7. type="primary"
  8. style="margin-right: 20px; width: 100px"
  9. @click="photo"
  10. >
  11. 屏幕拍照
  12. </el-button>
  13. <el-button
  14. size="large"
  15. style="margin-right: 20px; width: 100px"
  16. @click="copyGis"
  17. v-if="point?.pos"
  18. >
  19. 复制经纬度
  20. </el-button>
  21. <el-button
  22. size="large"
  23. type="primary"
  24. style="width: 100px"
  25. @click="update = true"
  26. v-if="router.currentRoute.value.name === 'pano'"
  27. >
  28. 修改名称
  29. </el-button>
  30. </div>
  31. </div>
  32. <SingleInput
  33. v-if="point"
  34. :visible="update"
  35. @update:visible="update = false"
  36. :value="point.name || ''"
  37. :update-value="tex => updateScenePointName(point!, tex)"
  38. title="修改点位名称"
  39. />
  40. </template>
  41. <script setup lang="ts">
  42. import SingleInput from "@/components/single-input.vue";
  43. import { router, setDocTitle } from "@/router";
  44. import { mergeFuns } from "@/util";
  45. import { computed, onMounted, onUnmounted, ref, watchEffect } from "vue";
  46. import { init } from "./env";
  47. import {
  48. scenePoints,
  49. updateScenePointName,
  50. getPointPano,
  51. ScenePoint,
  52. } from "@/store/scene";
  53. import { copyText, toDegrees } from "@/util";
  54. import { ElMessage } from "element-plus";
  55. import { relicsScenePosInfoFetch } from "@/request";
  56. import saveAs from "@/util/file-serve";
  57. type Params = { pid?: string } | null;
  58. const params = computed(() => router.currentRoute.value.params as Params);
  59. const panoDomRef = ref<HTMLCanvasElement>();
  60. const destroyFns: (() => void)[] = [];
  61. const point = ref<ScenePoint>();
  62. watchEffect(() => {
  63. if (params.value?.pid) {
  64. const pid = Number(params.value!.pid);
  65. const cachePoint = scenePoints.value.find((point) => point.id === pid);
  66. if (!cachePoint) {
  67. relicsScenePosInfoFetch(pid).then((data) => (point.value = data));
  68. } else {
  69. point.value = cachePoint;
  70. }
  71. }
  72. });
  73. const panoUrls = computed(
  74. () => point.value && getPointPano(point.value.sceneCode, Number(point.value.uuid))
  75. );
  76. const update = ref(false);
  77. const loading = ref(false);
  78. const copyGis = async () => {
  79. const pos = point.value!.pos;
  80. await copyText(
  81. `经度:${toDegrees(pos[0])}, 纬度: ${toDegrees(pos[1])}, 高程: ${pos[2]}`
  82. );
  83. ElMessage.success("经纬度高程复制成功");
  84. };
  85. const photo = () => {
  86. panoDomRef.value!.toBlob(async (blob) => {
  87. if (blob) {
  88. await saveAs(blob, "pano.png");
  89. ElMessage.success("图片导出成功");
  90. }
  91. }, "image/png");
  92. };
  93. onMounted(() => {
  94. if (!panoDomRef.value) throw "没有canvas DOM";
  95. const canvas = panoDomRef.value;
  96. canvas.width = canvas.offsetWidth * 4;
  97. canvas.height = canvas.offsetHeight * 4;
  98. const pano = init(canvas);
  99. destroyFns.push(
  100. watchEffect(() => {
  101. if (panoUrls.value) {
  102. loading.value = true;
  103. pano.changeUrls(panoUrls.value).then(() => (loading.value = false));
  104. }
  105. }),
  106. pano.destory
  107. );
  108. });
  109. onUnmounted(() => mergeFuns(...destroyFns)());
  110. watchEffect(() => {
  111. if (router.currentRoute.value.name === "pano" && point.value) {
  112. setDocTitle(point.value.name);
  113. }
  114. });
  115. </script>
  116. <style scoped lang="scss">
  117. .pano-layout,
  118. canvas {
  119. width: 100%;
  120. height: 100%;
  121. }
  122. .pano-layout {
  123. position: relative;
  124. .btns {
  125. position: absolute;
  126. left: 50%;
  127. transform: translateX(-50%);
  128. bottom: 40px;
  129. z-index: 1;
  130. }
  131. }
  132. </style>