platform.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. import { watchEffect, nextTick } from "vue";
  2. import {
  3. fuseModelsLoaded,
  4. scenes,
  5. SceneType,
  6. setting,
  7. caseProject,
  8. } from "@/store";
  9. import { fuseModel } from "./";
  10. import {
  11. initialSDK,
  12. initialed as fuseInitialed,
  13. sdk as fuseSDK,
  14. analysisPose,
  15. analysisPoseInfo,
  16. setPose,
  17. } from "@/sdk";
  18. import { asyncTimeout } from "@/utils";
  19. import { aMapToWgs84 } from "@/utils/coord";
  20. import type { ModelType } from "./";
  21. import { offlinePrev } from "@/api/offline";
  22. export async function modelSDKFactory(
  23. type: ModelType,
  24. dom: HTMLDivElement | HTMLIFrameElement
  25. ): Promise<ModelExpose> {
  26. let center: number[] | undefined = undefined;
  27. if (caseProject.value) {
  28. const lonlatStr = caseProject.value?.latAndLong || "22.364093,113.600356";
  29. const lonlat = lonlatStr.split(",").map(Number);
  30. const gcenter = aMapToWgs84({
  31. x: lonlat[1],
  32. y: lonlat[0],
  33. });
  34. center = [gcenter.x, gcenter.y];
  35. }
  36. if (type === fuseModel) {
  37. if (!fuseInitialed) {
  38. await initialSDK({
  39. laserRoot: offline ? offlinePrev : import.meta.env.VITE_LASER_HOST,
  40. panoOSSRoot: offline ? offlinePrev : import.meta.env.VITE_PANO_OSS,
  41. laserOSSRoot: offline ? offlinePrev : import.meta.env.VITE_LASER_OSS,
  42. layout: dom,
  43. scenes: scenes.value,
  44. lonlat: center,
  45. });
  46. }
  47. return exposeFactory(fuseModel);
  48. } else {
  49. const iframe = dom as HTMLIFrameElement;
  50. const win = await new Promise<Window | null>((resolve, reject) => {
  51. const loadedHandler = () => {
  52. resolve(iframe.contentWindow);
  53. cleanup();
  54. };
  55. const errorHandler = (err: any) => {
  56. reject(err);
  57. cleanup();
  58. };
  59. const cleanup = () => {
  60. iframe.removeEventListener("load", loadedHandler);
  61. iframe.removeEventListener("error", errorHandler);
  62. };
  63. iframe.addEventListener("load", loadedHandler);
  64. iframe.addEventListener("error", errorHandler);
  65. });
  66. if (!win) {
  67. throw new Error("场景加载失败");
  68. }
  69. return await exposeFactory(type, win);
  70. }
  71. }
  72. const findObjectAttr = <T extends {}, K extends keyof T>(
  73. data: T,
  74. key: K
  75. ): Promise<T[K]> => {
  76. return new Promise<T[K]>((resolve) => {
  77. const query = () => {
  78. if (key in data) {
  79. resolve(data[key]);
  80. } else {
  81. setTimeout(query, 6);
  82. }
  83. };
  84. query();
  85. });
  86. };
  87. const fuseLoaded = new Promise<void>((resolve) => {
  88. const stop = watchEffect(() => {
  89. if (fuseModelsLoaded.value) {
  90. resolve();
  91. nextTick(() => stop());
  92. }
  93. });
  94. });
  95. export interface ModelExpose {
  96. getView: () => Promise<{ image: Blob; flyData: string }>;
  97. setView: (flyData: string) => void;
  98. }
  99. export async function exposeFactory(
  100. type: ModelType,
  101. win?: any
  102. ): Promise<ModelExpose> {
  103. const sceneType = type === fuseModel ? fuseModel : type.type;
  104. const platforms: {
  105. [key in any]: { getSDK: () => Promise<any>; expose: ModelExpose };
  106. } = {
  107. [fuseModel]: {
  108. getSDK: async () => {
  109. await fuseLoaded;
  110. return fuseSDK;
  111. },
  112. expose: {
  113. async getView() {
  114. const dataURL = await sdk.screenshot(260, 160);
  115. const res = await fetch(dataURL);
  116. const image = await res.blob();
  117. const pose = analysisPose(sdk.getPose());
  118. return {
  119. image,
  120. flyData: JSON.stringify(pose),
  121. };
  122. },
  123. async setView(flyData: string) {
  124. console.error(JSON.parse(flyData));
  125. setPose(JSON.parse(flyData), sdk);
  126. },
  127. },
  128. },
  129. [SceneType.SWKK]: {
  130. getSDK: async () => {
  131. const sdk = await findObjectAttr(win, "__sdk");
  132. if (!sdk.Scene.loaded) {
  133. await new Promise((reoslve) => sdk.Scene.on("loaded", reoslve));
  134. }
  135. return sdk;
  136. },
  137. expose: {
  138. async getView() {
  139. const pose = sdk.Camera.getPose();
  140. const images = await sdk.Camera.screenshot(
  141. [{ width: 260, height: 160, name: "2k" }],
  142. true
  143. );
  144. return {
  145. image: images[0].data,
  146. flyData: JSON.stringify(pose),
  147. };
  148. },
  149. async setView(flyData: string) {
  150. const pose = JSON.parse(flyData);
  151. sdk.Camera.setPose({ dur: 300, ...pose });
  152. },
  153. },
  154. },
  155. [SceneType.SWSS]: {
  156. getSDK: async () => {
  157. await findObjectAttr(win, "laserLoaded");
  158. return await findObjectAttr(win, "__sdk");
  159. },
  160. expose: {
  161. async getView() {
  162. const dataURL = await sdk.scene.screenshot(260, 160);
  163. const res = await fetch(dataURL.dataUrl);
  164. const image = await res.blob();
  165. const pose = await sdk.scene.getPose();
  166. const mode = sdk.customMap.mode;
  167. return {
  168. image,
  169. flyData: JSON.stringify({ pose, mode }),
  170. };
  171. },
  172. async setView(flyData: string) {
  173. const { pose, mode } = JSON.parse(flyData);
  174. sdk.customMap.mode = mode;
  175. sdk.scene.setPose(pose, 300);
  176. },
  177. },
  178. },
  179. };
  180. platforms[SceneType.SWYDSS] = platforms[SceneType.SWSS];
  181. platforms[SceneType.SWYDMX] =
  182. platforms[SceneType.SWSSMX] =
  183. platforms[SceneType.SWKJ] =
  184. platforms[SceneType.SWKK];
  185. platforms[SceneType.SWMX] = {
  186. getSDK: async () => findObjectAttr(win, "__sdk"),
  187. expose: platforms[fuseModel].expose,
  188. };
  189. if (!(sceneType in platforms)) {
  190. throw new Error("不支持该类型场景!");
  191. }
  192. const sdk: any = await Promise.race([
  193. asyncTimeout(100000).then(() => Promise.reject(new Error("加载超时"))),
  194. platforms[sceneType].getSDK(),
  195. ]);
  196. return platforms[sceneType].expose;
  197. }