index.html 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Document</title>
  7. <style>
  8. * {
  9. padding: 0;
  10. margin: 0;
  11. }
  12. html, body, main {
  13. width: 100%;
  14. height: 100%;
  15. }
  16. main {
  17. display: flex;
  18. flex-direction: row;
  19. }
  20. main > div {
  21. position: relative;
  22. width: 85%;
  23. }
  24. #list {
  25. width: 15%;
  26. /* height: 100%; */
  27. overflow-y: scroll;
  28. padding: 10px;
  29. }
  30. #list li {
  31. position: relative;
  32. }
  33. #list li img {
  34. width: 100%;
  35. }
  36. #selectBorder {
  37. position: absolute;
  38. top: -2px;
  39. left: -3px;
  40. background: none;
  41. border: 3px solid #00FFFF;
  42. border-radius: 5px;
  43. width: 100%;
  44. height: 97%;
  45. }
  46. #label {
  47. padding: 2%;
  48. width: 96%;
  49. height: 15%;
  50. overflow-y: scroll;
  51. }
  52. #label li {
  53. display: inline-block;
  54. width: 33%;
  55. height: 20px;
  56. margin: 5px 0;
  57. }
  58. main div button {
  59. position: absolute;
  60. bottom: 30px;
  61. padding: 7px;
  62. width: 150px;
  63. display: none;
  64. }
  65. #download {
  66. left: 37%;
  67. }
  68. #uploadTxt {
  69. left: 50%;
  70. }
  71. </style>
  72. </head>
  73. <body>
  74. <main>
  75. <ul id="list"></ul>
  76. <div>
  77. <div id="scene3d"></div>
  78. <ul id="label"></ul>
  79. <button id="download" class="button">下载全景图</button>
  80. <button id="uploadTxt" class="button">
  81. 上传纠正数据(txt)
  82. <input type="file" name="" id="uploadInput" style="display: none;">
  83. </button>
  84. </div>
  85. </main>
  86. <script src="./lib/three.min.js"></script>
  87. <script src="./lib/OrbitControls.js"></script>
  88. <script src="./lib/axios.min.js"></script>
  89. <script src="./lib/base64.min.js"></script>
  90. <script src="./lib/bytebuffer.min.js"></script>
  91. <script src="./lib/protobuf.min.js"></script>
  92. <script type="module">
  93. import Scene3d from './core/Scene3d.js'
  94. let sceneCode, currentPanoId
  95. // 读取场景码
  96. let querys = window.location.search.substr(1).split('&')
  97. for (let i = 0; i < querys.length; i++) {
  98. let keypair = querys[i].split('=')
  99. if (keypair.length === 2 && keypair[0] === "m") {
  100. sceneCode = keypair[1]
  101. break
  102. }
  103. }
  104. if(!sceneCode) alert("没有场景码")
  105. else start()
  106. function start() {
  107. // 初始化3d场景
  108. let scene3d = new Scene3d({
  109. dom: document.getElementById('scene3d'),
  110. width: window.innerWidth * 0.85,
  111. height: window.innerHeight * 0.75,
  112. sceneCode: sceneCode
  113. })
  114. let load = async (panoId) => {
  115. currentPanoId = panoId
  116. let labels = await scene3d.load(panoId)
  117. document.getElementById('label').innerHTML = labels
  118. }
  119. // 读取点位信息
  120. ;(async () => {
  121. const content = await axios.get(`https://4dkk.4dage.com/scene_view_data/${sceneCode}/images/vision.modeldata`, { responseType: 'arraybuffer', })
  122. let visionmodeldataPro = Base64.decode(
  123. 'Ly8KLy8gUHJvdG9jb2wgQnVmZmVyIGZvciBwdWNrIHZpc2liaWxpdHkgYW5kIHJlbGF0ZWQgZGF0YQovLwovL3BhY2thZ2UgZW9zLnN0b3JhZ2U7CgovLyBpbXBvcnQgImVvcy9pbmZyYS9jb21tb24ucHJvdG8iOwovLyBUaGUgZm9sbG93aW5nIHdlcmUgbWFudWFsbHkgZXh0cmFjdGVkIGhlcmUsIEpTIGRvZXMgbm90IGxpa2UgcHJvdG9idWYgaW1wb3J0cwoKbWVzc2FnZSBBZmZpbmUzZiB7CglvcHRpb25hbCBRdWF0ZXJuaW9uZiByb3RhdGlvbiA9IDE7CglvcHRpb25hbCBWZWN0b3IzZiB0cmFuc2xhdGlvbiA9IDI7Cn0KCm1lc3NhZ2UgUXVhdGVybmlvbmYgewoJb3B0aW9uYWwgZmxvYXQgdyA9IDE7CglvcHRpb25hbCBmbG9hdCB4ID0gMjsKCW9wdGlvbmFsIGZsb2F0IHkgPSAzOwoJb3B0aW9uYWwgZmxvYXQgeiA9IDQ7Cn0KCm1lc3NhZ2UgVmVjdG9yM2YgewoJb3B0aW9uYWwgZmxvYXQgeCA9IDE7CglvcHRpb25hbCBmbG9hdCB5ID0gMjsKCW9wdGlvbmFsIGZsb2F0IHogPSAzOwp9CgovLwovLyBPbmUgc3dlZXAgLyBwYW5vCi8vCm1lc3NhZ2UgU3dlZXBMb2NhdGlvbiB7CglvcHRpb25hbCBieXRlcyB1dWlkID0gMTsgIC8qIHV1aWQgKi8KCW9wdGlvbmFsIEFmZmluZTNmIHBvc2UgPSAyOyAgLyogY2FtZXJhIHBvc2UgKHgsIHkseikgaW4gbWV0ZXIgYW5kIGEgcXVhdGVybmlvbiovCglvcHRpb25hbCBWZWN0b3IzZiBwdWNrID0gMzsgIC8qIHB1Y2sgbG9jYXRpb24gLSB4IGFueSBpcyBnZW5lcmFsbHkgdGhlIHNhbWUgYXMgcG9zZSwgeiBpcyB0aGUgaGVpZ2h0IG9mIHRoZSBjbG9zZXN0IGZsb29yIHVuZGVyIHRoZSBjYW1lcmEgKi8KCW9wdGlvbmFsIGludDMyIGdyb3VwID0gNDsgIC8qIGZsb29yIGluZGV4ICovCglvcHRpb25hbCBpbnQzMiBzdWJncm91cCA9IDU7ICAvKiByb29tIGluZGV4ICovCglyZXBlYXRlZCBpbnQzMiB2aXNpYmxlcyA9IDY7ICAvKiBsaXN0IG9mIGluZGljZXMgdG8gYWxsIHB1Y2tzIHZpc2libGUgZnJvbSB0aGlzIHB1Y2sgKi8KCXJlcGVhdGVkIGludDMyIHZpc2libGVzMiA9IDc7IAoJcmVwZWF0ZWQgaW50MzIgdmlzaWJsZXMzID0gODsKfQoKLy8KLy8gQWxsIHB1Y2tzIGluIGEgbW9kZWwuIFB1Y2tzIGFyZSBzdG9yZWQgaW4gc2Nhbm5pbmcgb3JkZXIuCi8vCm1lc3NhZ2UgTmF2aWdhdGlvbkluZm8gewoJcmVwZWF0ZWQgU3dlZXBMb2NhdGlvbiBzd2VlcExvY2F0aW9ucyA9IDE7Cn0='
  124. )
  125. function decoderModeldata() {
  126. var builderModeldata = dcodeIO.ProtoBuf.loadProto(visionmodeldataPro)
  127. return builderModeldata.build('NavigationInfo')
  128. }
  129. let data = decoderModeldata().decode(content.data)
  130. let uuids = data.sweepLocations.map(n => n.uuid.toUTF8().replace(/-/g, ''))
  131. // 选中框
  132. let border = document.createElement("div")
  133. border.id = "selectBorder"
  134. // 创建点位列表
  135. uuids.forEach(panoId => {
  136. let pano = document.createElement("li")
  137. pano.innerHTML = `<img id="${panoId}" src="https://4dkk.4dage.com/scene_view_data/${sceneCode}/images/pan/low/${panoId}.jpg"/>`
  138. document.getElementById("list").appendChild(pano)
  139. // 点位切换事件
  140. pano.addEventListener("click", (e) => {
  141. Array.from(document.getElementsByClassName("button")).forEach(button => button.style.display = "block") // 显示两个button
  142. e.srcElement.parentNode.appendChild(border) // 显示线框
  143. load(e.srcElement.id) // 加载点位数据
  144. })
  145. })
  146. })()
  147. // 下载全景图
  148. document.getElementById("download").addEventListener("click", () => {
  149. const a_link = document.createElement("a")
  150. fetch(`https://4dkk.4dage.com/scene_view_data/${sceneCode}/images/pan/high/${currentPanoId}.jpg`)
  151. .then(res => res.blob())
  152. .then(blob => {
  153. a_link.href = URL.createObjectURL(blob)
  154. a_link.download = currentPanoId + ".jpg"
  155. a_link.click()
  156. })
  157. })
  158. // 上传txt
  159. document.getElementById("uploadTxt").addEventListener("click", () => {
  160. document.getElementById("uploadInput").click()
  161. })
  162. document.getElementById("uploadInput").addEventListener("change", (e) => {
  163. let file = e.target.files[0]
  164. const formData = new FormData()
  165. formData.append("num", sceneCode)
  166. formData.append("imgPath", currentPanoId + ".jpg")
  167. formData.append("file", file)
  168. axios.post(
  169. "/service/scene/sceneMarkShape/editLabel",
  170. formData,
  171. {
  172. 'Content-Type': 'multipart/form-data',
  173. }
  174. ).then(res => {
  175. if(res.data.success) {
  176. alert("上传成功")
  177. load(currentPanoId)
  178. } else {
  179. alert("上传失败")
  180. }
  181. }, err => {
  182. console.error(err)
  183. })
  184. })
  185. }
  186. </script>
  187. </body>
  188. </html>