@netless/window-manager 1.0.11 → 1.0.13-bate.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/window-manager",
3
- "version": "1.0.11",
3
+ "version": "1.0.13-bate.0",
4
4
  "description": "Multi-window mode for Netless Whiteboard",
5
5
  "author": "l1shen <lishen1635@gmail.com> (https://github.com/l1shen)",
6
6
  "license": "MIT",
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "peerDependencies": {
25
25
  "jspdf": "2.5.1",
26
- "white-web-sdk": "^2.16.52"
26
+ "white-web-sdk": "^2.16.53"
27
27
  },
28
28
  "peerDependenciesMeta": {
29
29
  "jspdf": {
@@ -72,6 +72,6 @@
72
72
  "typescript": "^4.5.5",
73
73
  "vite": "^2.9.9",
74
74
  "vitest": "^0.14.1",
75
- "white-web-sdk": "^2.16.52"
75
+ "white-web-sdk": "^2.16.53"
76
76
  }
77
77
  }
@@ -120,6 +120,10 @@ export class AppProxy implements PageRemoveService {
120
120
  return this.store.getAppAttributes(this.id);
121
121
  }
122
122
 
123
+ public get Logger() {
124
+ return this.manager.windowManger.Logger;
125
+ }
126
+
123
127
  public getFullScenePath(): string | undefined {
124
128
  if (this.scenePath) {
125
129
  return get(this.appAttributes, [Fields.FullPath]) || this.getFullScenePathFromScenes();
@@ -145,6 +149,7 @@ export class AppProxy implements PageRemoveService {
145
149
  ): Promise<{ appId: string; app: NetlessApp }> {
146
150
  const params = this.params;
147
151
  if (!params.kind) {
152
+ this.Logger && this.Logger.error(`[WindowManager]: kind require`);
148
153
  throw new Error("[WindowManager]: kind require");
149
154
  }
150
155
  const appImpl = await appRegister.appClasses.get(params.kind)?.();
@@ -162,6 +167,7 @@ export class AppProxy implements PageRemoveService {
162
167
  params.isDragContent
163
168
  );
164
169
  } else {
170
+ this.Logger && this.Logger.error(`[WindowManager]: app load failed ${params.kind} ${params.src}`);
165
171
  throw new Error(`[WindowManager]: app load failed ${params.kind} ${params.src}`);
166
172
  }
167
173
  internalEmitter.emit("updateManagerRect");
@@ -210,7 +216,7 @@ export class AppProxy implements PageRemoveService {
210
216
  }
211
217
  setTimeout(async () => {
212
218
  // 延迟执行 setup, 防止初始化的属性没有更新成功
213
- console.log("setup app", app);
219
+ this.Logger && this.Logger.info(`[WindowManager]: setup app ${this.kind}, appId: ${appId}`);
214
220
  const result = await app.setup(context);
215
221
  this.appResult = result;
216
222
  appRegister.notifyApp(this.kind, "created", { appId, result });
@@ -245,7 +251,7 @@ export class AppProxy implements PageRemoveService {
245
251
  this.boxManager.focusBox({ appId }, false);
246
252
  }
247
253
  } catch (error: any) {
248
- console.error(error);
254
+ this.Logger && this.Logger.error(`[WindowManager]: app setup error: ${error.message}`);
249
255
  throw new Error(`[WindowManager]: app setup error: ${error.message}`);
250
256
  }
251
257
  }
@@ -532,6 +538,7 @@ export class AppProxy implements PageRemoveService {
532
538
  await appRegister.notifyApp(this.kind, "destroy", { appId: this.id });
533
539
  await this.appEmitter.emit("destroy", { error });
534
540
  } catch (error) {
541
+ this.Logger && this.Logger.error(`[WindowManager]: notifyApp error: ${error.message}`);
535
542
  console.error("[WindowManager]: notifyApp error", error.message, error.stack);
536
543
  }
537
544
  this.appEmitter.clearListeners();
@@ -554,6 +561,7 @@ export class AppProxy implements PageRemoveService {
554
561
  this.manager.refresher.remove(this.stateKey);
555
562
  this.manager.refresher.remove(`${this.id}-fullPath`);
556
563
  this._prevFullPath = undefined;
564
+ this.Logger && this.Logger.info(`[WindowManager]: destroy app ${this.kind} appId: ${this.id}`);
557
565
  }
558
566
 
559
567
  public close(): Promise<void> {
@@ -50,14 +50,6 @@ export class AppListeners {
50
50
  this.setMainViewScenePathHandler(data.payload);
51
51
  break;
52
52
  }
53
- // case Events.MoveCamera: {
54
- // this.moveCameraHandler(data.payload);
55
- // break;
56
- // }
57
- // case Events.MoveCameraToContain: {
58
- // this.moveCameraToContainHandler(data.payload);
59
- // break;
60
- // }
61
53
  case Events.CursorMove: {
62
54
  this.cursorMoveHandler(data.payload);
63
55
  break;
@@ -102,17 +94,6 @@ export class AppListeners {
102
94
  callbacks.emit("mainViewScenePathChange", nextScenePath);
103
95
  };
104
96
 
105
- // private moveCameraHandler = (
106
- // payload: Camera & { animationMode?: AnimationMode | undefined }
107
- // ) => {
108
- // if (isEqual(omit(payload, ["animationMode"]), { ...this.manager.mainView.camera })) return;
109
- // this.manager.mainView.moveCamera(payload);
110
- // };
111
-
112
- // private moveCameraToContainHandler = (payload: any) => {
113
- // this.manager.mainView.moveCameraToContain(payload);
114
- // };
115
-
116
97
  private cursorMoveHandler = (payload: any) => {
117
98
  internalEmitter.emit("cursorMove", payload);
118
99
  };
package/src/AppManager.ts CHANGED
@@ -94,11 +94,6 @@ export class AppManager {
94
94
 
95
95
  constructor(public windowManger: WindowManager) {
96
96
  this.displayer = windowManger.displayer;
97
- // this.store.setContext({
98
- // getAttributes: () => this.attributes,
99
- // safeSetAttributes: attributes => this.safeSetAttributes(attributes),
100
- // safeUpdateAttributes: (keys, val) => this.safeUpdateAttributes(keys, val),
101
- // });
102
97
  this.store = createAttributesDelegate(WindowManager.extendClass, {
103
98
  getAttributes: () => this.attributes,
104
99
  safeSetAttributes: attributes => this.safeSetAttributes(attributes),
@@ -150,6 +145,7 @@ export class AppManager {
150
145
  const { scenePath } = params;
151
146
  // 如果移除根目录就把 scenePath 设置为初始值
152
147
  if (scenePath === ROOT_DIR) {
148
+ console.log("[window-manager] onRemoveScenes ROOT_DIR");
153
149
  await this.onRootDirRemoved();
154
150
  this.dispatchInternalEvent(Events.RootDirRemoved);
155
151
  return;
@@ -162,6 +158,7 @@ export class AppManager {
162
158
  sceneName = this.callbacksNode?.scenes[nextIndex];
163
159
  }
164
160
  if (sceneName) {
161
+ console.log(`[window-manager] onRemoveScenes setMainViewScenePath ${ROOT_DIR}${sceneName}`);
165
162
  this.setMainViewScenePath(`${ROOT_DIR}${sceneName}`);
166
163
  }
167
164
  await this.setMainViewSceneIndex(nextIndex);
@@ -333,6 +330,10 @@ export class AppManager {
333
330
  return this.room?.uid || "";
334
331
  }
335
332
 
333
+ public get Logger() {
334
+ return this.windowManger.Logger;
335
+ }
336
+
336
337
  public getMainViewSceneDir() {
337
338
  const scenePath = this.store.getMainViewScenePath();
338
339
  if (scenePath) {
@@ -603,6 +604,9 @@ export class AppManager {
603
604
  try {
604
605
  const appAttributes = this.attributes[id];
605
606
  if (!appAttributes) {
607
+ this.Logger && this.Logger.error(
608
+ `[WindowManager]: appAttributes is undefined, appId: ${id}`
609
+ );
606
610
  throw new Error("appAttributes is undefined");
607
611
  }
608
612
 
@@ -706,6 +710,31 @@ export class AppManager {
706
710
  }
707
711
  internalEmitter.emit("mainViewMounted");
708
712
  callbacks.emit("onMainViewMounted", mainView);
713
+ const hasRoot = this.hasRoot(mainView.divElement);
714
+ const rect = this.getRectByDivElement(mainView.divElement);
715
+ let log = `[window-manager] bindMainView hasRoot:${hasRoot}, rect:${JSON.stringify(rect)}, outerHeight:${window.outerHeight}, outerWidth:${window.outerWidth}`;
716
+ const visualViewport = window.visualViewport;
717
+ if (visualViewport) {
718
+ log += `, visualViewportWidth:${visualViewport.width}, visualViewportHeight:${visualViewport.height}, visualViewportOffsetLeft:${visualViewport.offsetLeft}, visualViewportOffsetTop:${visualViewport.offsetTop}`;
719
+ }
720
+ console.log(log);
721
+ }
722
+
723
+ private hasRoot(divElement: HTMLDivElement){
724
+ let current = divElement;
725
+ while (current) {
726
+ if (current.parentElement === document.body) {
727
+ return true;
728
+ }
729
+ current = current.parentElement as HTMLDivElement;
730
+ }
731
+ return false;
732
+ }
733
+
734
+ private getRectByDivElement(divElement: HTMLDivElement){
735
+ // 获取当前divElement的矩形区域
736
+ const rect = divElement.getBoundingClientRect();
737
+ return rect;
709
738
  }
710
739
 
711
740
  public setMainViewFocusPath(scenePath?: string) {
@@ -725,6 +754,9 @@ export class AppManager {
725
754
 
726
755
  public async addApp(params: AddAppParams, isDynamicPPT: boolean): Promise<string | undefined> {
727
756
  log("addApp", params);
757
+ this.windowManger.Logger?.info(
758
+ `[WindowManager]: addApp ${params.kind}, isDynamicPPT: ${isDynamicPPT}`
759
+ );
728
760
  const { appId, needFocus } = await this.beforeAddApp(params, isDynamicPPT);
729
761
  const appProxy = await this.baseInsertApp(params, appId, true, needFocus);
730
762
  this.afterAddApp(appProxy);
@@ -762,7 +794,7 @@ export class AppManager {
762
794
  public async closeApp(appId: string, needClose = true) {
763
795
  const appProxy = this.appProxies.get(appId);
764
796
  if (appProxy) {
765
- appProxy.destroy(true, needClose, false);
797
+ await appProxy.destroy(true, needClose, false);
766
798
  }
767
799
  }
768
800
 
@@ -773,7 +805,9 @@ export class AppManager {
773
805
  focus?: boolean
774
806
  ) {
775
807
  if (this.appProxies.has(appId)) {
776
- console.warn("[WindowManager]: app duplicate exists and cannot be created again");
808
+ this.windowManger.Logger?.warn(
809
+ `[WindowManager]: app duplicate exists and cannot be created again, appId: ${appId}`
810
+ );
777
811
  return;
778
812
  }
779
813
  const AppProxyClass = getExtendClass(AppProxy, WindowManager.extendClass);
@@ -784,6 +818,7 @@ export class AppManager {
784
818
  return appProxy;
785
819
  } else {
786
820
  this.appStatus.delete(appId);
821
+ this.Logger && this.Logger.error(`[WindowManager]: initialize AppProxy failed, appId: ${appId}`);
787
822
  throw new Error("[WindowManger]: initialize AppProxy failed");
788
823
  }
789
824
  }
@@ -823,12 +858,15 @@ export class AppManager {
823
858
  const scenePathType = this.displayer.scenePathType(scenePath);
824
859
  const sceneDir = parseSceneDir(scenePath);
825
860
  if (sceneDir !== ROOT_DIR) {
861
+ this.Logger && this.Logger.error(`[WindowManager]: main view scenePath must in root dir "/"`);
826
862
  throw new Error(`[WindowManager]: main view scenePath must in root dir "/"`);
827
863
  }
828
864
  if (scenePathType === ScenePathType.None) {
865
+ this.Logger && this.Logger.error(`[WindowManager]: ${scenePath} not valid scene`);
829
866
  throw new Error(`[WindowManager]: ${scenePath} not valid scene`);
830
867
  } else if (scenePathType === ScenePathType.Page) {
831
868
  await this._setMainViewScenePath(scenePath);
869
+
832
870
  } else if (scenePathType === ScenePathType.Dir) {
833
871
  const validScenePath = makeValidScenePath(this.displayer, scenePath);
834
872
  if (validScenePath) {
@@ -875,6 +913,7 @@ export class AppManager {
875
913
  this.dispatchSetMainViewScenePath(scenePath);
876
914
  }
877
915
  } else {
916
+ this.Logger && this.Logger.error(`[WindowManager]: ${index} not valid index`);
878
917
  throw new Error(`[WindowManager]: ${index} not valid index`);
879
918
  }
880
919
  }
@@ -961,3 +1000,4 @@ export class AppManager {
961
1000
  this._resolveTimer = undefined;
962
1001
  }
963
1002
  }
1003
+
@@ -7,6 +7,7 @@ import type { Cursor } from "./Cursor/Cursor";
7
7
  import { getExtendClass } from "./Utils/extendClass";
8
8
  import type { ExtendClass } from "./Utils/extendClass";
9
9
  import type { NotMinimizedBoxState, TeleBoxState } from "@netless/telebox-insider";
10
+ import { LocalConsole } from "./Utils/log";
10
11
 
11
12
  export enum Fields {
12
13
  Apps = "apps",
@@ -54,6 +55,7 @@ export type ISize = Size & { id: string };
54
55
 
55
56
  export class AttributesDelegate {
56
57
  static readonly kind = "AttributesDelegate";
58
+ private setMainViewCameraConsole = new LocalConsole("setMainViewCamera", 30);
57
59
  constructor(private context: StoreContext) {}
58
60
 
59
61
  public setContext(context: StoreContext) {
@@ -210,6 +212,7 @@ export class AttributesDelegate {
210
212
  }
211
213
 
212
214
  public setMainViewCamera(camera: ICamera) {
215
+ this.setMainViewCameraConsole.log(JSON.stringify(camera));
213
216
  this.context.safeSetAttributes({ [Fields.MainViewCamera]: { ...camera } });
214
217
  }
215
218
 
@@ -3,12 +3,15 @@ import { isFunction } from "lodash";
3
3
  import { WindowManager } from "./index";
4
4
  import type { EmitterType } from "./InternalEmitter";
5
5
  import type { UnsubscribeFn } from "emittery";
6
+ import { LocalConsole } from "./Utils/log";
6
7
 
7
8
  const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
8
9
 
9
10
  export class ContainerResizeObserver {
10
11
  private containerResizeObserver?: ResizeObserver;
11
12
  private disposer?: UnsubscribeFn;
13
+
14
+ private updateSizerLocalConsole = new LocalConsole("updateSizer", 30);
12
15
 
13
16
  constructor(private emitter: EmitterType) {}
14
17
 
@@ -28,19 +31,19 @@ export class ContainerResizeObserver {
28
31
  sizer: HTMLElement,
29
32
  wrapper: HTMLDivElement
30
33
  ) {
31
- this.updateSizer(container.getBoundingClientRect(), sizer, wrapper);
34
+ this.updateSizer(container.getBoundingClientRect(), sizer, wrapper, 'observePlaygroundSize');
32
35
 
33
36
  this.containerResizeObserver = new ResizeObserver(entries => {
34
37
  const containerRect = entries[0]?.contentRect;
35
38
  if (containerRect) {
36
- this.updateSizer(containerRect, sizer, wrapper);
39
+ this.updateSizer(containerRect, sizer, wrapper, 'containerResizeObserver');
37
40
  this.emitter.emit("playgroundSizeChange", containerRect);
38
41
  }
39
42
  });
40
43
 
41
44
  this.disposer = this.emitter.on("containerSizeRatioUpdate", () => {
42
45
  const containerRect = container.getBoundingClientRect();
43
- this.updateSizer(containerRect, sizer, wrapper);
46
+ this.updateSizer(containerRect, sizer, wrapper, 'containerSizeRatioUpdate');
44
47
  this.emitter.emit("playgroundSizeChange", containerRect);
45
48
  });
46
49
 
@@ -50,7 +53,8 @@ export class ContainerResizeObserver {
50
53
  public updateSizer(
51
54
  { width, height }: DOMRectReadOnly,
52
55
  sizer: HTMLElement,
53
- wrapper: HTMLDivElement
56
+ wrapper: HTMLDivElement,
57
+ origin?: string
54
58
  ) {
55
59
  if (width && height) {
56
60
  if (height / width > WindowManager.containerSizeRatio) {
@@ -62,6 +66,13 @@ export class ContainerResizeObserver {
62
66
  }
63
67
  wrapper.style.width = `${width}px`;
64
68
  wrapper.style.height = `${height}px`;
69
+ const wrapperRect = wrapper.getBoundingClientRect();
70
+ this.updateSizerLocalConsole.log(`from ${origin}, traget size: ${JSON.stringify({ width, height })}, wrapperRect: ${wrapperRect.width} ${wrapperRect.height}`);
71
+ this.emitter.emit("wrapperRectChange", {
72
+ width: wrapperRect.width,
73
+ height: wrapperRect.height,
74
+ origin,
75
+ });
65
76
  }
66
77
  }
67
78
 
@@ -29,6 +29,7 @@ export type EmitterEvent = {
29
29
  changePageState: undefined;
30
30
  writableChange: boolean;
31
31
  containerSizeRatioUpdate: number;
32
+ wrapperRectChange: { width: number; height: number; origin?: string };
32
33
  boxesStatusChange: Map<string, TeleBoxState>;
33
34
  lastNotMinimizedBoxesStatusChange: Map<string, NotMinimizedBoxState>;
34
35
  };
@@ -33,7 +33,28 @@ export const replaceRoomFunction = (room: Room | Player, manager: WindowManager)
33
33
  return manager.canRedoSteps;
34
34
  },
35
35
  });
36
-
36
+ const _scalePptToFit = room.scalePptToFit;
37
+ room.scalePptToFit = (...args) => {
38
+ _scalePptToFit.call(room, ...args);
39
+ if (manager.appManager?.mainViewProxy) {
40
+ manager.appManager.mainViewProxy.setCameraAndSize();
41
+ }
42
+ };
43
+ const _putScenes = room.putScenes;
44
+ room.putScenes = (...args) => {
45
+ const [path, scenes] = args;
46
+ const currentScenePath = manager.mainView.focusScenePath;
47
+ if (currentScenePath && path && scenes) {
48
+ console.log("[window-manager] putScenes " + JSON.stringify(args));
49
+ for (const scene of scenes) {
50
+ if (`${path}${scene.name}` === currentScenePath) {
51
+ console.error(`[window-manager] putScenes: scene name can not be the same as the current scene path: ${currentScenePath}`);
52
+ return;
53
+ }
54
+ }
55
+ }
56
+ return _putScenes.call(room, ...args);
57
+ };
37
58
  room.moveCamera = (camera: Camera) => manager.moveCamera(camera);
38
59
  room.moveCameraToContain = (...args) => manager.moveCameraToContain(...args);
39
60
  room.convertToPointInWorld = (...args) => manager.mainView.convertToPointInWorld(...args);
package/src/Utils/log.ts CHANGED
@@ -5,3 +5,40 @@ export const log = (...args: any[]): void => {
5
5
  console.log(`[WindowManager]:`, ...args);
6
6
  }
7
7
  };
8
+
9
+ /**
10
+ * 按 `[window-manager][tagName]` 前缀输出。
11
+ * 若传入 `debounceTime`(毫秒):窗口内多次 `log` 不立即输出,只在连续停止调用满 `debounceTime` 后输出**最后一次**的参数(尾部 debounce)。
12
+ */
13
+ export class LocalConsole {
14
+ private pendingArgs: unknown[] | null = null;
15
+ private flushTimer: ReturnType<typeof setTimeout> | null = null;
16
+
17
+ constructor(
18
+ private readonly name: string,
19
+ private readonly debounceTime?: number,
20
+ ) {}
21
+
22
+ private flush(): void {
23
+ this.flushTimer = null;
24
+ const args = this.pendingArgs;
25
+ this.pendingArgs = null;
26
+ if (args === null) {
27
+ return;
28
+ }
29
+ console.log(`[window-manager][${this.name}]: ${args.join(", ")}`);
30
+ }
31
+
32
+ log(...args: unknown[]): void {
33
+ const ms = this.debounceTime;
34
+ if (ms != null && ms > 0) {
35
+ this.pendingArgs = args;
36
+ if (this.flushTimer != null) {
37
+ clearTimeout(this.flushTimer);
38
+ }
39
+ this.flushTimer = setTimeout(() => this.flush(), ms);
40
+ return;
41
+ }
42
+ console.log(`[window-manager][${this.name}]: ${args.join(", ")}`);
43
+ }
44
+ }
@@ -9,6 +9,7 @@ import { SideEffectManager } from "side-effect-manager";
9
9
  import type { Camera, Room, Size, View } from "white-web-sdk";
10
10
  import type { AppManager } from "../AppManager";
11
11
  import { Events } from "../constants";
12
+ import { LocalConsole } from "../Utils/log";
12
13
 
13
14
  export class MainViewProxy {
14
15
  /** Refresh the view's camera in an interval of 1.5s. */
@@ -17,12 +18,19 @@ export class MainViewProxy {
17
18
  private scale?: number;
18
19
  private started = false;
19
20
  private mainViewIsAddListener = false;
21
+ private isForcingMainViewDivElement = false;
22
+ private wrapperRectWorkaroundFrame = 0;
23
+ private pendingWrapperRectChange?: { width: number; height: number; origin?: string };
20
24
  private mainView: View;
21
25
  private store = this.manager.store;
22
26
  private viewMode = this.manager.windowManger.viewMode;
23
27
 
24
28
  private sideEffectManager = new SideEffectManager();
25
29
 
30
+ private playgroundSizeChangeListenerLocalConsole = new LocalConsole("playgroundSizeChangeListener", 30);
31
+ private sizeUpdatedLocalConsole = new LocalConsole("sizeUpdated", 30);
32
+ private cameraUpdatedLocalConsole = new LocalConsole("cameraUpdated", 30);
33
+
26
34
  constructor(private manager: AppManager) {
27
35
  this.mainView = this.createMainView();
28
36
  this.moveCameraSizeByAttributes();
@@ -33,6 +41,15 @@ export class MainViewProxy {
33
41
  this.startListenWritableChange();
34
42
  });
35
43
  const playgroundSizeChangeListener = () => {
44
+ this.playgroundSizeChangeListenerLocalConsole.log(
45
+ JSON.stringify(this.mainView.camera),
46
+ JSON.stringify(this.mainView.size),
47
+ JSON.stringify(this.mainViewSize),
48
+ JSON.stringify(this.mainViewCamera),
49
+ window.outerHeight, window.outerWidth,
50
+ window.visualViewport?.width ?? "null", window.visualViewport?.height ?? "null",
51
+ window.visualViewport?.offsetLeft ?? "null", window.visualViewport?.offsetTop ?? "null",
52
+ );
36
53
  this.sizeChangeHandler(this.mainViewSize);
37
54
  };
38
55
  this.sideEffectManager.add(() => {
@@ -41,6 +58,9 @@ export class MainViewProxy {
41
58
  this.sideEffectManager.add(() => {
42
59
  return internalEmitter.on("containerSizeRatioUpdate", this.onUpdateContainerSizeRatio);
43
60
  });
61
+ this.sideEffectManager.add(() => {
62
+ return internalEmitter.on("wrapperRectChange", this.onWrapperRectChange);
63
+ });
44
64
  this.sideEffectManager.add(() => {
45
65
  return internalEmitter.on("startReconnect", () => {
46
66
  if (!this.didRelease) {
@@ -96,13 +116,85 @@ export class MainViewProxy {
96
116
  this.moveCamera(this.mainViewCamera);
97
117
  }
98
118
 
119
+ private onWrapperRectChange = (payload: { width: number; height: number; origin?: string }) => {
120
+ this.pendingWrapperRectChange = payload;
121
+ if (this.wrapperRectWorkaroundFrame) {
122
+ cancelAnimationFrame(this.wrapperRectWorkaroundFrame);
123
+ }
124
+ this.wrapperRectWorkaroundFrame = requestAnimationFrame(this.runWrapperRectWorkaround);
125
+ };
126
+
127
+ private runWrapperRectWorkaround = () => {
128
+ this.wrapperRectWorkaroundFrame = 0;
129
+ const payload = this.pendingWrapperRectChange;
130
+ const element = this.mainView.divElement;
131
+ this.pendingWrapperRectChange = undefined;
132
+ if (!payload || !element) return;
133
+
134
+ const rect = element.getBoundingClientRect();
135
+ const observedSize = { width: rect.width, height: rect.height };
136
+ const wrapperMatchesDom =
137
+ Math.abs(payload.width - observedSize.width) <= 0.5 &&
138
+ Math.abs(payload.height - observedSize.height) <= 0.5;
139
+ const viewIsStale =
140
+ Math.abs(this.mainView.size.width - observedSize.width) > 0.5 ||
141
+ Math.abs(this.mainView.size.height - observedSize.height) > 0.5;
142
+
143
+ if (wrapperMatchesDom && viewIsStale) {
144
+ this.forceSyncMainViewDivElement(
145
+ `wrapperRectChange:${payload.origin || "unknown"}`,
146
+ observedSize,
147
+ element
148
+ );
149
+ }
150
+ };
151
+
152
+ private forceSyncMainViewDivElement(
153
+ reason: string,
154
+ observedSize: Pick<Size, "width" | "height">,
155
+ element: HTMLDivElement
156
+ ) {
157
+ const { width: viewWidth, height: viewHeight } = this.mainView.size;
158
+ if (
159
+ Math.abs(viewWidth - observedSize.width) <= 0.5 &&
160
+ Math.abs(viewHeight - observedSize.height) <= 0.5
161
+ ) {
162
+ return;
163
+ }
164
+ if (this.isForcingMainViewDivElement) {
165
+ console.log("[window-manager] skipForceSyncMainViewDivElement " + JSON.stringify({
166
+ reason,
167
+ observedSize,
168
+ viewSize: this.mainView.size,
169
+ }));
170
+ return;
171
+ }
172
+ this.isForcingMainViewDivElement = true;
173
+ this.mainView.divElement = null;
174
+ this.mainView.divElement = element;
175
+ queueMicrotask(() => {
176
+ const rect = element.getBoundingClientRect();
177
+ console.log("[window-manager] forceSyncMainViewDivElementResult " + JSON.stringify({
178
+ reason,
179
+ viewSize: this.mainView.size,
180
+ rect: { width: rect.width, height: rect.height },
181
+ }));
182
+ this.isForcingMainViewDivElement = false;
183
+ });
184
+ }
185
+
99
186
  public start() {
187
+ console.log("[window-manager] start attributes size:" + JSON.stringify(this.mainViewSize));
100
188
  this.sizeChangeHandler(this.mainViewSize);
101
189
  if (this.started) return;
102
190
  this.addCameraListener();
103
191
  this.addCameraReaction();
104
192
  if (this.manager.room) this.syncMainView(this.manager.room);
105
193
  this.started = true;
194
+ if(this.mainView.focusScenePath) {
195
+ this.manager.windowManger.onMainViewScenePathChangeHandler(this.mainView.focusScenePath);
196
+ }
197
+ console.log("[window-manager] start end mainView size:" + JSON.stringify(this.mainView.size));
106
198
  }
107
199
 
108
200
  public addCameraReaction = () => {
@@ -120,6 +212,7 @@ export class MainViewProxy {
120
212
  () => this.mainViewCamera,
121
213
  camera => {
122
214
  if (camera && camera.id !== this.manager.uid) {
215
+ console.log("[window-manager] cameraReaction " + JSON.stringify(camera) + JSON.stringify(this.mainViewSize));
123
216
  this.moveCameraToContian(this.mainViewSize);
124
217
  this.moveCamera(camera);
125
218
  }
@@ -132,12 +225,15 @@ export class MainViewProxy {
132
225
  if (size) {
133
226
  this.moveCameraToContian(size);
134
227
  this.moveCamera(this.mainViewCamera);
228
+ console.log("[window-manager] sizeChangeHandler current size and camera" + JSON.stringify(size) + JSON.stringify(this.mainViewCamera) +
229
+ JSON.stringify(this.mainView.camera) + JSON.stringify(this.mainView.size));
135
230
  }
136
231
  this.ensureMainViewSize();
137
232
  }, 30);
138
233
 
139
234
  public onUpdateContainerSizeRatio = () => {
140
235
  const size = this.store.getMainViewSize();
236
+ console.log("[window-manager] onUpdateContainerSizeRatio " + JSON.stringify(size));
141
237
  this.sizeChangeHandler(size);
142
238
  };
143
239
 
@@ -230,18 +326,18 @@ export class MainViewProxy {
230
326
 
231
327
  private addCameraListener() {
232
328
  this.view.callbacks.on("onCameraUpdatedByDevice", this.onCameraUpdatedByDevice);
233
- this.view.callbacks.on("onCameraUpdated", this.onCameraOrSizeUpdated);
234
- this.view.callbacks.on("onSizeUpdated", this.onCameraOrSizeUpdated);
329
+ this.view.callbacks.on("onCameraUpdated", this.onCameraUpdated);
330
+ this.view.callbacks.on("onSizeUpdated", this.onSizeUpdated);
235
331
  }
236
332
 
237
333
  private removeCameraListener() {
238
334
  this.view.callbacks.off("onCameraUpdatedByDevice", this.onCameraUpdatedByDevice);
239
- this.view.callbacks.off("onCameraUpdated", this.onCameraOrSizeUpdated);
240
- this.view.callbacks.off("onSizeUpdated", this.onCameraOrSizeUpdated);
335
+ this.view.callbacks.off("onCameraUpdated", this.onCameraUpdated);
336
+ this.view.callbacks.off("onSizeUpdated", this.onSizeUpdated);
241
337
  }
242
338
 
243
339
  private _syncMainViewTimer = 0;
244
- private onCameraOrSizeUpdated = () => {
340
+ private handleCameraOrSizeUpdated = () => {
245
341
  callbacks.emit("cameraStateChange", this.cameraState);
246
342
  // sdk >= 2.16.43 的 syncMainView() 可以写入当前 main view 的 camera, 以修复复制粘贴元素的位置
247
343
  // 注意到这个操作会发送信令,应当避免频繁调用
@@ -252,6 +348,16 @@ export class MainViewProxy {
252
348
  this.ensureMainViewSize();
253
349
  };
254
350
 
351
+ private onCameraUpdated = (camera: Camera) => {
352
+ this.cameraUpdatedLocalConsole.log(JSON.stringify(camera));
353
+ this.handleCameraOrSizeUpdated();
354
+ };
355
+
356
+ private onSizeUpdated = (size: Size) => {
357
+ this.sizeUpdatedLocalConsole.log(JSON.stringify(size));
358
+ this.handleCameraOrSizeUpdated();
359
+ };
360
+
255
361
  private ensureMainViewSize() {
256
362
  if (
257
363
  (!this.mainViewSize ||
@@ -309,6 +415,11 @@ export class MainViewProxy {
309
415
  };
310
416
 
311
417
  public destroy() {
418
+ console.log("[window-manager] destroy ");
419
+ if (this.wrapperRectWorkaroundFrame) {
420
+ cancelAnimationFrame(this.wrapperRectWorkaroundFrame);
421
+ this.wrapperRectWorkaroundFrame = 0;
422
+ }
312
423
  this.removeMainViewListener();
313
424
  this.stop();
314
425
  this.sideEffectManager.flushAll();