|
@@ -0,0 +1,160 @@
|
|
|
+import { watchEffect, nextTick } from 'vue'
|
|
|
+import { fuseModelsLoaded, SceneType } from '@/store'
|
|
|
+import { fuseModel } from './'
|
|
|
+import { initialSDK, initialed as fuseInitialed, sdk as fuseSDK } from '@/sdk'
|
|
|
+import { asyncTimeout } from '@/utils'
|
|
|
+
|
|
|
+import type { ModelType } from './'
|
|
|
+
|
|
|
+export async function modelSDKFactory (
|
|
|
+ type: ModelType,
|
|
|
+ dom: HTMLDivElement | HTMLIFrameElement
|
|
|
+): Promise<ModelExpose> {
|
|
|
+ if (type === fuseModel) {
|
|
|
+ if (!fuseInitialed) {
|
|
|
+ await initialSDK({ layout: dom })
|
|
|
+ }
|
|
|
+ return exposeFactory(fuseModel)
|
|
|
+ } else {
|
|
|
+ const iframe = dom as HTMLIFrameElement
|
|
|
+ const win = await new Promise<Window | null>((resolve, reject) => {
|
|
|
+ const loadedHandler = () => {
|
|
|
+ resolve(iframe.contentWindow)
|
|
|
+ cleanup()
|
|
|
+ }
|
|
|
+ const errorHandler = (err: any) => {
|
|
|
+ reject(err)
|
|
|
+ cleanup()
|
|
|
+ }
|
|
|
+ const cleanup = () => {
|
|
|
+ iframe.removeEventListener('load', loadedHandler)
|
|
|
+ iframe.removeEventListener('error', errorHandler)
|
|
|
+ }
|
|
|
+ iframe.addEventListener('load', loadedHandler)
|
|
|
+ iframe.addEventListener('error', errorHandler)
|
|
|
+ })
|
|
|
+
|
|
|
+ if (!win) {
|
|
|
+ throw new Error('场景加载失败')
|
|
|
+ }
|
|
|
+ return await exposeFactory(type, win)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const findObjectAttr = <T, K extends keyof T>(data: T, key: K): Promise<T[K]> => {
|
|
|
+ return new Promise<T[K]>(resolve => {
|
|
|
+ const query = () => {
|
|
|
+ if (key in data) {
|
|
|
+ resolve(data[key])
|
|
|
+ } else {
|
|
|
+ setTimeout(query, 6)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ query()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const fuseLoaded = new Promise<void>(resolve => {
|
|
|
+ const stop = watchEffect(() => {
|
|
|
+ if (fuseModelsLoaded.value) {
|
|
|
+ resolve()
|
|
|
+ nextTick(() => stop())
|
|
|
+ }
|
|
|
+ })
|
|
|
+})
|
|
|
+
|
|
|
+export interface ModelExpose {
|
|
|
+ getView: () => Promise<{ image: Blob, flyData: string }>
|
|
|
+ setView: (flyData: string) => void
|
|
|
+}
|
|
|
+
|
|
|
+export async function exposeFactory(type: ModelType, win?: any): Promise<ModelExpose> {
|
|
|
+ const sceneType = type === fuseModel ? fuseModel : type.type
|
|
|
+ const platforms: {[key in any]: {getSDK: () => Promise<void>, expose: ModelExpose}} = {
|
|
|
+ [fuseModel]: {
|
|
|
+ getSDK: () => fuseLoaded,
|
|
|
+ expose: {
|
|
|
+ async getView() {
|
|
|
+ const dataURL = await fuseSDK.screenshot(260, 160)
|
|
|
+ const res = await fetch(dataURL)
|
|
|
+ const image = await res.blob()
|
|
|
+ const pose = fuseSDK.getPose()
|
|
|
+ return {
|
|
|
+ image,
|
|
|
+ flyData: JSON.stringify(pose)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async setView(flyData: string) {
|
|
|
+ const pose = JSON.parse(flyData)
|
|
|
+ fuseSDK.comeTo({ dur: 300, ...pose })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [SceneType.SWKK]: {
|
|
|
+ getSDK: async () => {
|
|
|
+ const sdk = await findObjectAttr(win , '__sdk')
|
|
|
+ if (!sdk.Scene.loaded) {
|
|
|
+ await new Promise(reoslve => sdk.Scene.on('loaded', reoslve))
|
|
|
+ }
|
|
|
+ return sdk
|
|
|
+ },
|
|
|
+ expose: {
|
|
|
+ async getView() {
|
|
|
+ const pose = sdk.Camera.getPose()
|
|
|
+ const images = await sdk.Camera.screenshot(
|
|
|
+ [{ width: 260, height: 160, name: '2k' }],
|
|
|
+ true
|
|
|
+ )
|
|
|
+ return {
|
|
|
+ image: images[0].data,
|
|
|
+ flyData: JSON.stringify(pose)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async setView(flyData: string) {
|
|
|
+ const pose = JSON.parse(flyData)
|
|
|
+ console.log('===>?', pose)
|
|
|
+ sdk.Camera.setPose({ dur: 300, ...pose })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [SceneType.SWSS]: {
|
|
|
+ getSDK: async () => {
|
|
|
+ await findObjectAttr(win, 'laserLoaded')
|
|
|
+ return await findObjectAttr(win, '__sdk')
|
|
|
+ },
|
|
|
+ expose: {
|
|
|
+ async getView() {
|
|
|
+ const dataURL = await sdk.scene.screenshot(260, 160)
|
|
|
+ const res = await fetch(dataURL)
|
|
|
+ const image = await res.blob()
|
|
|
+ const pose = await sdk.scene.getPose()
|
|
|
+ const mode = sdk.customMap.mode
|
|
|
+
|
|
|
+ return {
|
|
|
+ image,
|
|
|
+ flyData: JSON.stringify({ pose, mode })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async setView(flyData: string) {
|
|
|
+ const { pose, mode } = JSON.parse(flyData)
|
|
|
+ sdk.customMap.mode = mode
|
|
|
+ sdk.scene.setPose(pose, 300)
|
|
|
+ console.error('setView')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ platforms[SceneType.SWKJ] = platforms[SceneType.SWKK]
|
|
|
+
|
|
|
+ if (!(sceneType in platforms)) {
|
|
|
+ throw new Error('不支持该类型场景!')
|
|
|
+ }
|
|
|
+
|
|
|
+ const sdk: any = await Promise.race([
|
|
|
+ asyncTimeout(10000)
|
|
|
+ .then(() => Promise.reject(new Error('加载超时'))),
|
|
|
+ platforms[sceneType].getSDK()
|
|
|
+ ])
|
|
|
+ return platforms[sceneType].expose
|
|
|
+}
|