platform.ts 5.5 KB

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