@netless/window-manager 1.0.0-canary.7 → 1.0.0-canary.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -6
- package/dist/index.js +13625 -0
- package/dist/index.mjs +13622 -0
- package/dist/index.umd.js +13620 -46
- package/dist/{App → src/App}/AppContext.d.ts +16 -14
- package/dist/{App → src/App}/AppPageStateImpl.d.ts +0 -0
- package/dist/{App → src/App}/AppProxy.d.ts +30 -11
- package/dist/{App → src/App}/MagixEvent/index.d.ts +0 -0
- package/dist/src/App/WhiteboardView.d.ts +27 -0
- package/dist/{App → src/App}/index.d.ts +1 -0
- package/dist/src/App/type.d.ts +21 -0
- package/dist/{AppListener.d.ts → src/AppListener.d.ts} +2 -2
- package/dist/{AppManager.d.ts → src/AppManager.d.ts} +12 -7
- package/dist/{AttributesDelegate.d.ts → src/AttributesDelegate.d.ts} +5 -2
- package/dist/{BoxEmitter.d.ts → src/BoxEmitter.d.ts} +0 -0
- package/dist/{BoxManager.d.ts → src/BoxManager.d.ts} +12 -6
- package/dist/{BuiltinApps.d.ts → src/BuiltinApps.d.ts} +3 -0
- package/dist/{Cursor → src/Cursor}/Cursor.d.ts +0 -0
- package/dist/{Cursor → src/Cursor}/icons.d.ts +0 -0
- package/dist/{Cursor → src/Cursor}/index.d.ts +4 -3
- package/dist/{Helper.d.ts → src/Helper.d.ts} +4 -8
- package/dist/{InternalEmitter.d.ts → src/InternalEmitter.d.ts} +1 -4
- package/dist/{Page → src/Page}/PageController.d.ts +3 -1
- package/dist/{Page → src/Page}/index.d.ts +0 -0
- package/dist/{PageState.d.ts → src/PageState.d.ts} +1 -0
- package/dist/{ReconnectRefresher.d.ts → src/ReconnectRefresher.d.ts} +0 -0
- package/dist/{RedoUndo.d.ts → src/RedoUndo.d.ts} +0 -0
- package/dist/{Register → src/Register}/index.d.ts +4 -2
- package/dist/{Register → src/Register}/loader.d.ts +1 -1
- package/dist/src/Register/storage.d.ts +11 -0
- package/dist/{Utils → src/Utils}/AppCreateQueue.d.ts +0 -0
- package/dist/{Utils → src/Utils}/Common.d.ts +0 -0
- package/dist/{Utils → src/Utils}/Reactive.d.ts +1 -1
- package/dist/{Utils → src/Utils}/RoomHacker.d.ts +0 -0
- package/dist/{Utils → src/Utils}/error.d.ts +4 -1
- package/dist/{Utils → src/Utils}/log.d.ts +0 -0
- package/dist/src/View/CameraSynchronizer.d.ts +21 -0
- package/dist/{View → src/View}/MainView.d.ts +25 -7
- package/dist/src/View/ScrollMode.d.ts +32 -0
- package/dist/{View → src/View}/ViewManager.d.ts +0 -0
- package/dist/src/View/ViewSync.d.ts +32 -0
- package/dist/{callback.d.ts → src/callback.d.ts} +12 -1
- package/dist/{constants.d.ts → src/constants.d.ts} +12 -5
- package/dist/src/image.d.ts +19 -0
- package/dist/{index.d.ts → src/index.d.ts} +63 -17
- package/dist/src/shim.d.ts +11 -0
- package/dist/src/storage.d.ts +7 -0
- package/dist/{typings.d.ts → src/typings.d.ts} +21 -8
- package/dist/style.css +810 -1
- package/docs/api.md +10 -0
- package/docs/app-context.md +155 -27
- package/docs/mirgrate-to-1.0.md +68 -0
- package/package.json +27 -22
- package/playwright.config.ts +29 -0
- package/src/App/AppContext.ts +81 -46
- package/src/App/AppPageStateImpl.ts +3 -0
- package/src/App/AppProxy.ts +249 -141
- package/src/App/WhiteboardView.ts +37 -14
- package/src/App/index.ts +1 -0
- package/src/App/type.ts +22 -0
- package/src/AppListener.ts +27 -21
- package/src/AppManager.ts +96 -50
- package/src/AttributesDelegate.ts +6 -3
- package/src/BoxManager.ts +76 -38
- package/src/BuiltinApps.ts +9 -8
- package/src/Cursor/Cursor.svelte +6 -2
- package/src/Cursor/Cursor.ts +15 -4
- package/src/Cursor/icons.ts +6 -0
- package/src/Cursor/index.ts +16 -11
- package/src/Helper.ts +25 -7
- package/src/InternalEmitter.ts +1 -4
- package/src/Page/PageController.ts +3 -1
- package/src/PageState.ts +8 -1
- package/src/ReconnectRefresher.ts +7 -3
- package/src/Register/index.ts +36 -14
- package/src/Register/loader.ts +20 -9
- package/src/Register/storage.ts +26 -5
- package/src/Utils/Common.ts +3 -0
- package/src/Utils/Reactive.ts +29 -27
- package/src/Utils/RoomHacker.ts +3 -0
- package/src/Utils/error.ts +6 -2
- package/src/View/CameraSynchronizer.ts +55 -36
- package/src/View/MainView.ts +162 -76
- package/src/View/ScrollMode.ts +240 -0
- package/src/View/ViewSync.ts +138 -6
- package/src/callback.ts +8 -1
- package/src/constants.ts +11 -3
- package/src/image/pencil-eraser-1.svg +3 -0
- package/src/image/pencil-eraser-2.svg +3 -0
- package/src/image/pencil-eraser-3.svg +3 -0
- package/src/index.ts +197 -60
- package/src/storage.ts +15 -0
- package/src/style.css +18 -47
- package/src/typings.ts +24 -7
- package/vite.config.js +12 -7
- package/dist/App/AppViewSync.d.ts +0 -11
- package/dist/App/Storage/StorageEvent.d.ts +0 -8
- package/dist/App/Storage/index.d.ts +0 -39
- package/dist/App/Storage/typings.d.ts +0 -22
- package/dist/App/Storage/utils.d.ts +0 -5
- package/dist/App/WhiteboardView.d.ts +0 -21
- package/dist/Register/storage.d.ts +0 -8
- package/dist/View/CameraSynchronizer.d.ts +0 -17
- package/dist/View/ViewSync.d.ts +0 -7
- package/dist/index.cjs.js +0 -46
- package/dist/index.es.js +0 -16161
- package/pnpm-lock.yaml +0 -6302
- package/src/App/AppViewSync.ts +0 -68
- package/src/App/Storage/StorageEvent.ts +0 -21
- package/src/App/Storage/index.ts +0 -295
- package/src/App/Storage/typings.ts +0 -23
- package/src/App/Storage/utils.ts +0 -17
package/src/Register/index.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import Emittery from "emittery";
|
2
2
|
import { loadApp } from "./loader";
|
3
3
|
import type { NetlessApp, RegisterEvents, RegisterParams } from "../typings";
|
4
|
+
import { removeItem } from "./storage";
|
4
5
|
|
5
6
|
export type LoadAppEvent = {
|
6
7
|
kind: string;
|
@@ -11,11 +12,12 @@ export type LoadAppEvent = {
|
|
11
12
|
export type SyncRegisterAppPayload = { kind: string, src: string, name: string | undefined };
|
12
13
|
export type SyncRegisterApp = (payload: SyncRegisterAppPayload) => void;
|
13
14
|
|
14
|
-
class AppRegister {
|
15
|
+
export class AppRegister {
|
15
16
|
public kindEmitters: Map<string, Emittery<RegisterEvents>> = new Map();
|
16
17
|
public registered: Map<string, RegisterParams> = new Map();
|
17
18
|
public appClassesCache: Map<string, Promise<NetlessApp>> = new Map();
|
18
19
|
public appClasses: Map<string, () => Promise<NetlessApp>> = new Map();
|
20
|
+
public downloaded: Map<string, string> = new Map();
|
19
21
|
|
20
22
|
private syncRegisterApp: SyncRegisterApp | null = null;
|
21
23
|
|
@@ -31,32 +33,39 @@ class AppRegister {
|
|
31
33
|
this.appClassesCache.delete(params.kind);
|
32
34
|
this.registered.set(params.kind, params);
|
33
35
|
|
34
|
-
const
|
36
|
+
const paramSrc = params.src;
|
35
37
|
let downloadApp: () => Promise<NetlessApp>;
|
36
38
|
|
37
|
-
if (typeof
|
39
|
+
if (typeof paramSrc === "string") {
|
38
40
|
downloadApp = async () => {
|
39
|
-
|
41
|
+
const result = await loadApp(paramSrc, params.kind, params.name) as any;
|
42
|
+
if (result.__esModule) {
|
43
|
+
return result.default;
|
44
|
+
}
|
45
|
+
return result;
|
46
|
+
};
|
47
|
+
if (this.syncRegisterApp) {
|
48
|
+
this.syncRegisterApp({ kind: params.kind, src: paramSrc, name: params.name });
|
49
|
+
}
|
50
|
+
}
|
51
|
+
if (typeof paramSrc === "function") {
|
52
|
+
downloadApp = async () => {
|
53
|
+
let appClass = await paramSrc() as any;
|
40
54
|
if (appClass) {
|
41
|
-
if (appClass.__esModule) {
|
55
|
+
if (appClass.__esModule || appClass.default) {
|
42
56
|
appClass = appClass.default;
|
43
57
|
}
|
44
58
|
return appClass;
|
45
59
|
} else {
|
46
60
|
throw new Error(
|
47
|
-
`[WindowManager]: load remote script failed, ${
|
61
|
+
`[WindowManager]: load remote script failed, ${paramSrc}`
|
48
62
|
);
|
49
63
|
}
|
50
64
|
};
|
51
|
-
if (this.syncRegisterApp) {
|
52
|
-
this.syncRegisterApp({ kind: params.kind, src: srcOrAppOrFunction, name: params.name });
|
53
|
-
}
|
54
|
-
} else if (typeof srcOrAppOrFunction === "function") {
|
55
|
-
downloadApp = srcOrAppOrFunction;
|
56
|
-
} else {
|
57
|
-
downloadApp = async () => srcOrAppOrFunction;
|
58
65
|
}
|
59
|
-
|
66
|
+
if (typeof paramSrc === "object") {
|
67
|
+
downloadApp = async () => paramSrc;
|
68
|
+
}
|
60
69
|
this.appClasses.set(params.kind, async () => {
|
61
70
|
let app = this.appClassesCache.get(params.kind);
|
62
71
|
if (!app) {
|
@@ -74,10 +83,23 @@ class AppRegister {
|
|
74
83
|
}
|
75
84
|
}
|
76
85
|
|
86
|
+
public downloadApp(kind: string) {
|
87
|
+
const src = this.registered.get(kind);
|
88
|
+
if (src && typeof src.src === "string") {
|
89
|
+
return loadApp(src.src, src.kind, src.name)
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
public async removeDownloaded(kind: string) {
|
94
|
+
await removeItem(kind);
|
95
|
+
this.downloaded.delete(kind);
|
96
|
+
}
|
97
|
+
|
77
98
|
public unregister(kind: string) {
|
78
99
|
this.appClasses.delete(kind);
|
79
100
|
this.appClassesCache.delete(kind);
|
80
101
|
this.registered.delete(kind);
|
102
|
+
this.removeDownloaded(kind);
|
81
103
|
const kindEmitter = this.kindEmitters.get(kind);
|
82
104
|
if (kindEmitter) {
|
83
105
|
kindEmitter.clearListeners();
|
package/src/Register/loader.ts
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
import { callbacks } from "../callback";
|
2
2
|
import { getItem, setItem } from "./storage";
|
3
3
|
import type { NetlessApp } from "../typings";
|
4
|
+
import { appRegister } from ".";
|
4
5
|
|
5
6
|
const Prefix = "NetlessApp";
|
6
7
|
|
7
8
|
const TIMEOUT = 10000; // 下载 script 10 秒超时
|
8
9
|
|
9
|
-
export const getScript = async (url: string): Promise<string> => {
|
10
|
-
const item = await getItem(
|
10
|
+
export const getScript = async (kind: string, url: string): Promise<string> => {
|
11
|
+
const item = await getItem(kind);
|
11
12
|
if (item) {
|
12
13
|
return item.sourceCode;
|
13
14
|
} else {
|
14
15
|
const result = await fetchWithTimeout(url, { timeout: TIMEOUT });
|
15
16
|
const text = await result.text();
|
16
|
-
await setItem(url, text);
|
17
|
+
await setItem(kind, url, text);
|
17
18
|
return text;
|
18
19
|
}
|
19
20
|
};
|
@@ -28,6 +29,15 @@ export const executeScript = (text: string, appName: string): NetlessApp => {
|
|
28
29
|
return result;
|
29
30
|
};
|
30
31
|
|
32
|
+
const emitSuccess = (kind: string, url: string) => {
|
33
|
+
callbacks.emit("loadApp", { kind, status: "success" });
|
34
|
+
appRegister.downloaded.set(kind, url);
|
35
|
+
};
|
36
|
+
|
37
|
+
const emitFailed = (kind: string, reason: string) => {
|
38
|
+
callbacks.emit("loadApp", { kind, status: "failed", reason, });
|
39
|
+
};
|
40
|
+
|
31
41
|
export const loadApp = async (
|
32
42
|
url: string,
|
33
43
|
key: string,
|
@@ -36,14 +46,14 @@ export const loadApp = async (
|
|
36
46
|
const appName = name || Prefix + key;
|
37
47
|
callbacks.emit("loadApp", { kind: key, status: "start" });
|
38
48
|
try {
|
39
|
-
const text = await getScript(url);
|
49
|
+
const text = await getScript(key, url);
|
40
50
|
if (!text || text.length === 0) {
|
41
|
-
|
51
|
+
emitFailed(key, "script is empty");
|
42
52
|
return;
|
43
53
|
}
|
44
54
|
try {
|
45
55
|
const result = executeScript(text, appName);
|
46
|
-
|
56
|
+
emitSuccess(key, url);
|
47
57
|
return result;
|
48
58
|
} catch (error: any) {
|
49
59
|
if (error.message.includes("Can only have one anonymous define call per script file")) {
|
@@ -54,16 +64,17 @@ export const loadApp = async (
|
|
54
64
|
delete define.amd;
|
55
65
|
}
|
56
66
|
const result = executeScript(text, appName);
|
57
|
-
|
67
|
+
emitSuccess(key, url);
|
58
68
|
return result;
|
59
69
|
}
|
60
|
-
|
70
|
+
emitFailed(key, error.message);
|
61
71
|
}
|
62
72
|
} catch (error: any) {
|
63
|
-
|
73
|
+
emitFailed(key, error.message);
|
64
74
|
}
|
65
75
|
};
|
66
76
|
|
77
|
+
|
67
78
|
async function fetchWithTimeout(resource: string, options: RequestInit & { timeout: number }) {
|
68
79
|
const { timeout = 10000 } = options;
|
69
80
|
|
package/src/Register/storage.ts
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import type { AppRegister } from "./index";
|
2
|
+
|
1
3
|
const DatabaseName = "__WindowManagerAppCache";
|
2
4
|
|
3
5
|
let db: IDBDatabase;
|
@@ -5,21 +7,26 @@ let store: IDBObjectStore;
|
|
5
7
|
|
6
8
|
export type Item = {
|
7
9
|
kind: string;
|
10
|
+
url: string;
|
8
11
|
sourceCode: string;
|
9
12
|
}
|
10
13
|
|
11
|
-
export const initDb = async () => {
|
14
|
+
export const initDb = async (appRegister: AppRegister) => {
|
12
15
|
db = await createDb();
|
16
|
+
const items = await queryAll(db);
|
17
|
+
items.forEach(item => {
|
18
|
+
appRegister.downloaded.set(item.kind, item.url);
|
19
|
+
});
|
13
20
|
}
|
14
21
|
|
15
|
-
export const setItem = (
|
22
|
+
export const setItem = (kind: string, url: string, val: any) => {
|
16
23
|
if (!db) return;
|
17
|
-
return addRecord(db, { kind
|
24
|
+
return addRecord(db, { kind, url, sourceCode: val })
|
18
25
|
};
|
19
26
|
|
20
|
-
export const getItem = async (
|
27
|
+
export const getItem = async (kind: string): Promise<Item | null> => {
|
21
28
|
if (!db) return null;
|
22
|
-
return await query(db,
|
29
|
+
return await query(db, kind);
|
23
30
|
};
|
24
31
|
|
25
32
|
export const removeItem = (key: string) => {
|
@@ -27,6 +34,11 @@ export const removeItem = (key: string) => {
|
|
27
34
|
return deleteRecord(db, key);
|
28
35
|
};
|
29
36
|
|
37
|
+
export const getAll = () => {
|
38
|
+
if (!db) return;
|
39
|
+
return queryAll(db);
|
40
|
+
}
|
41
|
+
|
30
42
|
function createDb(): Promise<IDBDatabase> {
|
31
43
|
return new Promise((resolve, reject) => {
|
32
44
|
const request = indexedDB.open(DatabaseName, 2);
|
@@ -64,6 +76,15 @@ function query<T>(db: IDBDatabase, val: string): Promise<T | null> {
|
|
64
76
|
})
|
65
77
|
}
|
66
78
|
|
79
|
+
function queryAll(db: IDBDatabase): Promise<Item[]> {
|
80
|
+
return new Promise((resolve, reject) => {
|
81
|
+
const index = db.transaction(["apps"]).objectStore("apps").index("kind");
|
82
|
+
const request = index.getAll();
|
83
|
+
request.onerror = e => reject(e);
|
84
|
+
request.onsuccess = () => resolve(request.result);
|
85
|
+
});
|
86
|
+
}
|
87
|
+
|
67
88
|
function addRecord(db: IDBDatabase, payload: any): Promise<void> {
|
68
89
|
return new Promise((resolve, reject) => {
|
69
90
|
const request = db.transaction(["apps"], "readwrite").objectStore("apps").add(payload);
|
package/src/Utils/Common.ts
CHANGED
@@ -17,6 +17,9 @@ export const genAppId = async (kind: string) => {
|
|
17
17
|
};
|
18
18
|
|
19
19
|
export const setViewFocusScenePath = (view: View, focusScenePath: string) => {
|
20
|
+
if ((view as any).didRelease) {
|
21
|
+
return;
|
22
|
+
}
|
20
23
|
if (view.focusScenePath !== focusScenePath) {
|
21
24
|
view.focusScenePath = focusScenePath;
|
22
25
|
return view;
|
package/src/Utils/Reactive.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
import { listenUpdated, unlistenUpdated, reaction, UpdateEventKind } from "white-web-sdk";
|
2
|
-
import type { AkkoObjectUpdatedProperty , AkkoObjectUpdatedListener } from "white-web-sdk";
|
3
1
|
import { isObject } from "lodash";
|
2
|
+
import { listenUpdated, reaction, unlistenUpdated, UpdateEventKind } from "white-web-sdk";
|
3
|
+
import type { AkkoObjectUpdatedProperty, AkkoObjectUpdatedListener } from "white-web-sdk";
|
4
4
|
|
5
5
|
// 兼容 13 和 14 版本 SDK
|
6
6
|
export const onObjectByEvent = (event: UpdateEventKind) => {
|
@@ -12,7 +12,7 @@ export const onObjectByEvent = (event: UpdateEventKind) => {
|
|
12
12
|
if (kinds.includes(event)) {
|
13
13
|
func();
|
14
14
|
}
|
15
|
-
}
|
15
|
+
};
|
16
16
|
listenUpdated(object, listener);
|
17
17
|
func();
|
18
18
|
return () => unlistenUpdated(object, listener);
|
@@ -21,43 +21,45 @@ export const onObjectByEvent = (event: UpdateEventKind) => {
|
|
21
21
|
() => object,
|
22
22
|
() => {
|
23
23
|
func();
|
24
|
-
},
|
24
|
+
},
|
25
|
+
{
|
25
26
|
fireImmediately: true,
|
26
27
|
}
|
27
|
-
)
|
28
|
+
);
|
28
29
|
}
|
29
|
-
}
|
30
|
-
}
|
30
|
+
};
|
31
|
+
};
|
31
32
|
|
32
|
-
|
33
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
34
|
+
export const safeListenPropsUpdated = <T extends Object>(
|
33
35
|
getProps: () => T,
|
34
36
|
callback: AkkoObjectUpdatedListener<T>,
|
35
37
|
onDestroyed?: (props: unknown) => void
|
36
|
-
|
38
|
+
) => {
|
37
39
|
let disposeListenUpdated: (() => void) | null = null;
|
38
40
|
const disposeReaction = reaction(
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
41
|
+
getProps,
|
42
|
+
() => {
|
43
|
+
if (disposeListenUpdated) {
|
44
|
+
disposeListenUpdated();
|
45
|
+
disposeListenUpdated = null;
|
46
|
+
}
|
47
|
+
const props = getProps();
|
48
|
+
if (isObject(props)) {
|
49
|
+
disposeListenUpdated = () => unlistenUpdated(props, callback);
|
50
|
+
listenUpdated(props, callback);
|
51
|
+
} else {
|
52
|
+
onDestroyed?.(props);
|
53
|
+
}
|
54
|
+
},
|
55
|
+
{ fireImmediately: true }
|
54
56
|
);
|
55
57
|
|
56
58
|
return () => {
|
57
|
-
|
58
|
-
|
59
|
+
disposeListenUpdated?.();
|
60
|
+
disposeReaction();
|
59
61
|
};
|
60
|
-
}
|
62
|
+
};
|
61
63
|
|
62
64
|
export const onObjectRemoved = onObjectByEvent(UpdateEventKind.Removed);
|
63
65
|
export const onObjectInserted = onObjectByEvent(UpdateEventKind.Inserted);
|
package/src/Utils/RoomHacker.ts
CHANGED
@@ -56,6 +56,9 @@ export const replaceRoomFunction = (room: Room | Player, manager: WindowManager)
|
|
56
56
|
room.lockImages = (...args) => manager.lockImages(...args);
|
57
57
|
|
58
58
|
delegateRemoveScenes(room, manager);
|
59
|
+
if (!(room as any).dynamicPpt.slideStateAdapter.pptHandler) {
|
60
|
+
(room as any).dynamicPpt.slideStateAdapter.pptHandler = manager.createPPTHandler();
|
61
|
+
}
|
59
62
|
}
|
60
63
|
};
|
61
64
|
|
package/src/Utils/error.ts
CHANGED
@@ -31,10 +31,14 @@ export class InvalidScenePath extends Error {
|
|
31
31
|
override message = `[WindowManager]: ScenePath should start with "/"`;
|
32
32
|
}
|
33
33
|
|
34
|
-
export class
|
35
|
-
override message = "[WindowManager]: boxManager
|
34
|
+
export class BoxManagerNotInitializeError extends Error {
|
35
|
+
override message = "[WindowManager]: boxManager need initialize";
|
36
36
|
}
|
37
37
|
|
38
38
|
export class BindContainerRoomPhaseInvalidError extends Error {
|
39
39
|
override message = "[WindowManager]: room phase only Connected can be bindContainer";
|
40
40
|
}
|
41
|
+
|
42
|
+
export class InvalidViewModeError extends Error {
|
43
|
+
override message = "[WindowManager]: scroll mode cannot be switched to other viewMode";
|
44
|
+
}
|
@@ -1,22 +1,24 @@
|
|
1
1
|
import { AnimationMode } from "white-web-sdk";
|
2
|
-
import {
|
2
|
+
import { isEmpty, isEqual, pick, throttle } from "lodash";
|
3
3
|
import type { TeleBoxRect } from "@netless/telebox-insider";
|
4
|
-
import type {
|
5
|
-
import type { ISize } from "../AttributesDelegate";
|
4
|
+
import type { View, Size } from "white-web-sdk";
|
5
|
+
import type { ICamera, ISize } from "../AttributesDelegate";
|
6
6
|
|
7
|
-
export type SaveCamera = (camera:
|
7
|
+
export type SaveCamera = (camera: ICamera) => void;
|
8
8
|
|
9
9
|
export class CameraSynchronizer {
|
10
|
-
public remoteCamera?:
|
10
|
+
public remoteCamera?: ICamera;
|
11
11
|
public remoteSize?: ISize;
|
12
12
|
protected rect?: TeleBoxRect;
|
13
13
|
protected view?: View;
|
14
|
+
protected scale = 1;
|
15
|
+
protected cameraUpdating = false;
|
14
16
|
|
15
17
|
constructor(protected saveCamera: SaveCamera) {}
|
16
18
|
|
17
|
-
public setRect(rect: TeleBoxRect) {
|
19
|
+
public setRect = (rect: TeleBoxRect, updateCamera = true) => {
|
18
20
|
this.rect = rect;
|
19
|
-
if (this.remoteCamera && this.remoteSize) {
|
21
|
+
if (this.remoteCamera && this.remoteSize && updateCamera) {
|
20
22
|
this.onRemoteUpdate(this.remoteCamera, this.remoteSize);
|
21
23
|
}
|
22
24
|
}
|
@@ -26,48 +28,65 @@ export class CameraSynchronizer {
|
|
26
28
|
}
|
27
29
|
|
28
30
|
// 远端 Camera 或者 size 更新
|
29
|
-
public onRemoteUpdate = throttle((camera:
|
31
|
+
public onRemoteUpdate = throttle((camera: ICamera, size: ISize, skipUpdate = false) => {
|
30
32
|
this.remoteCamera = camera;
|
31
33
|
this.remoteSize = size;
|
32
|
-
if (
|
33
|
-
|
34
|
-
if (
|
35
|
-
|
36
|
-
|
37
|
-
scale = this.rect.height / size.height;
|
34
|
+
if (skipUpdate) return;;
|
35
|
+
requestAnimationFrame(() => {
|
36
|
+
if (this.remoteSize && this.rect) {
|
37
|
+
this.moveCameraToContian(this.remoteSize);
|
38
|
+
this.moveCamera(camera);
|
38
39
|
}
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
});
|
41
|
+
}, 32);
|
42
|
+
|
43
|
+
public onRemoteSizeUpdate(size: ISize) {
|
44
|
+
this.remoteSize = size;
|
45
|
+
const needMoveCamera = !isEqual(pick(this.rect, ["width", "height"]), pick(size, ["width", "height"]));
|
46
|
+
if (this.rect && this.remoteCamera && needMoveCamera) {
|
47
|
+
if (!this.view) return;
|
48
|
+
const currentCamera = this.view.camera;
|
49
|
+
this.view?.moveCameraToContain({
|
50
|
+
width: size.width,
|
51
|
+
height: size.height,
|
52
|
+
originX: currentCamera.centerX - (size.width / 2),
|
53
|
+
originY: currentCamera.centerY - (size.height / 2),
|
44
54
|
animationMode: AnimationMode.Immediately,
|
45
55
|
});
|
46
|
-
|
47
|
-
delay(moveCamera, 50);
|
56
|
+
this.moveCamera(this.remoteCamera);
|
48
57
|
}
|
49
|
-
}
|
50
|
-
|
58
|
+
}
|
51
59
|
|
52
|
-
public onLocalCameraUpdate(camera:
|
60
|
+
public onLocalCameraUpdate(camera: ICamera) {
|
53
61
|
this.saveCamera(camera);
|
54
62
|
this.remoteCamera = camera;
|
55
63
|
}
|
56
64
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
}
|
66
|
-
|
65
|
+
private moveCameraToContian(size: Size): void {
|
66
|
+
if (!isEmpty(size) && this.view) {
|
67
|
+
this.view.moveCameraToContain({
|
68
|
+
width: size.width,
|
69
|
+
height: size.height,
|
70
|
+
originX: -size.width / 2,
|
71
|
+
originY: -size.height / 2,
|
72
|
+
animationMode: AnimationMode.Immediately,
|
73
|
+
});
|
74
|
+
this.scale = this.view.camera.scale;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
private moveCamera(camera: ICamera): void {
|
79
|
+
if (!isEmpty(camera) && this.view && camera.centerX != null && camera.centerY != null) {
|
80
|
+
if (isEqual(camera, this.view.camera)) return;
|
81
|
+
const { centerX, centerY, scale } = camera;
|
82
|
+
const needScale = scale * (this.scale || 1);
|
67
83
|
this.view.moveCamera({
|
68
|
-
|
69
|
-
|
84
|
+
centerX: centerX,
|
85
|
+
centerY: centerY,
|
86
|
+
scale: needScale,
|
87
|
+
animationMode: AnimationMode.Immediately,
|
70
88
|
});
|
71
89
|
}
|
72
90
|
}
|
73
91
|
}
|
92
|
+
|