@netless/window-manager 1.0.12 → 1.0.13-bate.1
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/dist/index.d.ts +69 -2
- package/dist/index.js +14 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +549 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/App/AppProxy.ts +10 -2
- package/src/AppListener.ts +0 -19
- package/src/AppManager.ts +46 -6
- package/src/ContainerResizeObserver.ts +18 -9
- package/src/InternalEmitter.ts +1 -0
- package/src/Utils/Reactive.ts +2 -2
- package/src/Utils/RoomHacker.ts +22 -1
- package/src/Utils/attributesLogStringify.ts +78 -0
- package/src/Utils/log.ts +265 -0
- package/src/View/MainView.ts +151 -7
- package/src/index.ts +71 -4
package/src/Utils/log.ts
CHANGED
|
@@ -1,7 +1,272 @@
|
|
|
1
|
+
import type { Logger } from "white-web-sdk";
|
|
2
|
+
import { isShallowMergeAttributesRecord, stringifyForAttributesLog } from "./attributesLogStringify";
|
|
1
3
|
import { WindowManager } from "../index";
|
|
2
4
|
|
|
5
|
+
/** ArgusLog 经 `logger.info` 上报的单条字符串上限(含前缀) */
|
|
6
|
+
const ARGUS_LOG_INFO_MAX_LENGTH = 1500;
|
|
7
|
+
|
|
8
|
+
function truncateArgusLogInfoMessage(message: string): string {
|
|
9
|
+
if (message.length <= ARGUS_LOG_INFO_MAX_LENGTH) {
|
|
10
|
+
return message;
|
|
11
|
+
}
|
|
12
|
+
const ellipsis = "…";
|
|
13
|
+
return message.slice(0, ARGUS_LOG_INFO_MAX_LENGTH - ellipsis.length) + ellipsis;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function keysPathEqual(a: string[], b: string[]): boolean {
|
|
17
|
+
if (a.length !== b.length) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
for (let i = 0; i < a.length; i++) {
|
|
21
|
+
if (a[i] !== b[i]) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
3
28
|
export const log = (...args: any[]): void => {
|
|
4
29
|
if (WindowManager.debug) {
|
|
5
30
|
console.log(`[WindowManager]:`, ...args);
|
|
6
31
|
}
|
|
7
32
|
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 按 `[window-manager][tagName]` 前缀输出。
|
|
36
|
+
* 若传入 `debounceTime`(毫秒):窗口内多次 `log` 不立即输出,只在连续停止调用满 `debounceTime` 后输出**最后一次**的参数(尾部 debounce)。
|
|
37
|
+
*/
|
|
38
|
+
export class LocalConsole {
|
|
39
|
+
private pendingArgs: unknown[] | null = null;
|
|
40
|
+
private flushTimer: ReturnType<typeof setTimeout> | null = null;
|
|
41
|
+
|
|
42
|
+
constructor(
|
|
43
|
+
private readonly name: string,
|
|
44
|
+
private readonly debounceTime?: number,
|
|
45
|
+
) {}
|
|
46
|
+
|
|
47
|
+
private flush(): void {
|
|
48
|
+
this.flushTimer = null;
|
|
49
|
+
const args = this.pendingArgs;
|
|
50
|
+
this.pendingArgs = null;
|
|
51
|
+
if (args === null) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
console.log(`[window-manager][${this.name}]: ${args.join(", ")}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
log(...args: unknown[]): void {
|
|
58
|
+
const ms = this.debounceTime;
|
|
59
|
+
if (ms != null && ms > 0) {
|
|
60
|
+
this.pendingArgs = args;
|
|
61
|
+
if (this.flushTimer != null) {
|
|
62
|
+
clearTimeout(this.flushTimer);
|
|
63
|
+
}
|
|
64
|
+
this.flushTimer = setTimeout(() => this.flush(), ms);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
console.log(`[window-manager][${this.name}]: ${args.join(", ")}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 销毁:清除 debounce 定时器与未输出的暂存参数。
|
|
72
|
+
* 持有 LocalConsole 的类在销毁时应调用。
|
|
73
|
+
*/
|
|
74
|
+
destroy(): void {
|
|
75
|
+
if (this.flushTimer != null) {
|
|
76
|
+
clearTimeout(this.flushTimer);
|
|
77
|
+
this.flushTimer = null;
|
|
78
|
+
}
|
|
79
|
+
this.pendingArgs = null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 按 `[WindowManager][tagName]` 前缀输出。
|
|
85
|
+
* 若传入 `debounceTime`(毫秒):窗口内多次 `log` 不立即输出,只在连续停止调用满 `debounceTime` 后输出**最后一次**的参数(尾部 debounce)。
|
|
86
|
+
*/
|
|
87
|
+
export class ArgusLog {
|
|
88
|
+
private pendingArgs: unknown[] | null = null;
|
|
89
|
+
private flushTimer: ReturnType<typeof setTimeout> | null = null;
|
|
90
|
+
|
|
91
|
+
/** debounce 窗口内按一层 key 合并;同 key 后者覆盖;非普通对象则整段待输出被本次值替换 */
|
|
92
|
+
private pendingShallowMerge:
|
|
93
|
+
| { kind: "record"; label: string; data: Record<string, unknown> }
|
|
94
|
+
| { kind: "atom"; label: string; value: unknown }
|
|
95
|
+
| null = null;
|
|
96
|
+
private shallowMergeTimer: ReturnType<typeof setTimeout> | null = null;
|
|
97
|
+
|
|
98
|
+
/** debounce 窗口内 safeUpdateAttributes:同 keys 数组则只更新 value,否则追加一段,flush 时拼成一条 */
|
|
99
|
+
private pendingUpdateSegments: { keys: string[]; value: unknown }[] | null = null;
|
|
100
|
+
private updateMergeTimer: ReturnType<typeof setTimeout> | null = null;
|
|
101
|
+
|
|
102
|
+
constructor(
|
|
103
|
+
private readonly logger: Logger,
|
|
104
|
+
private readonly name: string,
|
|
105
|
+
private readonly debounceTime?: number,
|
|
106
|
+
) {}
|
|
107
|
+
|
|
108
|
+
private emitInfo(message: string): void {
|
|
109
|
+
this.logger.info(truncateArgusLogInfoMessage(message));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private flush(): void {
|
|
113
|
+
this.flushTimer = null;
|
|
114
|
+
const args = this.pendingArgs;
|
|
115
|
+
this.pendingArgs = null;
|
|
116
|
+
if (args === null) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this.emitInfo(`[WindowManager][${this.name}]: ${args.join(", ")}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private flushShallowMerge(): void {
|
|
123
|
+
this.shallowMergeTimer = null;
|
|
124
|
+
const p = this.pendingShallowMerge;
|
|
125
|
+
this.pendingShallowMerge = null;
|
|
126
|
+
if (p === null) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const body =
|
|
130
|
+
p.kind === "record" ? stringifyForAttributesLog(p.data) : stringifyForAttributesLog(p.value);
|
|
131
|
+
this.emitInfo(`[WindowManager][${this.name}]: ${p.label} ${body}`);
|
|
132
|
+
// 输出后释放合并对象引用,避免长时间持有 attributes 快照
|
|
133
|
+
if (p.kind === "record") {
|
|
134
|
+
for (const k of Object.keys(p.data)) {
|
|
135
|
+
delete p.data[k];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
log(...args: unknown[]): void {
|
|
141
|
+
const ms = this.debounceTime;
|
|
142
|
+
if (ms != null && ms > 0) {
|
|
143
|
+
this.pendingArgs = args;
|
|
144
|
+
if (this.flushTimer != null) {
|
|
145
|
+
clearTimeout(this.flushTimer);
|
|
146
|
+
}
|
|
147
|
+
this.flushTimer = setTimeout(() => this.flush(), ms);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
this.emitInfo(`[WindowManager][${this.name}]: ${args.join(", ")}`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* 带 debounce 时:窗口内多次调用会把「一层 key」合并进同一条日志(不同 key 并存,同 key 取最后一次)。
|
|
155
|
+
* `payload` 为普通对象时做浅合并;否则视为原子值,覆盖当前待合并状态(丢弃此前累积的对象 key)。
|
|
156
|
+
* 无 debounce 或时间为 0 时立即输出。
|
|
157
|
+
*/
|
|
158
|
+
logDebouncedShallowMerge(label: string, payload: unknown): void {
|
|
159
|
+
const ms = this.debounceTime;
|
|
160
|
+
const debounced = ms != null && ms > 0;
|
|
161
|
+
|
|
162
|
+
const emit = (text: string): void => {
|
|
163
|
+
this.emitInfo(`[WindowManager][${this.name}]: ${label} ${text}`);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
if (!debounced) {
|
|
167
|
+
emit(stringifyForAttributesLog(payload));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (this.shallowMergeTimer != null) {
|
|
172
|
+
clearTimeout(this.shallowMergeTimer);
|
|
173
|
+
this.shallowMergeTimer = null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (isShallowMergeAttributesRecord(payload)) {
|
|
177
|
+
if (this.pendingShallowMerge?.kind === "record") {
|
|
178
|
+
this.pendingShallowMerge = {
|
|
179
|
+
kind: "record",
|
|
180
|
+
label,
|
|
181
|
+
data: { ...this.pendingShallowMerge.data, ...payload },
|
|
182
|
+
};
|
|
183
|
+
} else {
|
|
184
|
+
this.pendingShallowMerge = { kind: "record", label, data: { ...payload } };
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
this.pendingShallowMerge = { kind: "atom", label, value: payload };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
this.shallowMergeTimer = setTimeout(() => this.flushShallowMerge(), ms);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private flushUpdateAttributesMerge(): void {
|
|
194
|
+
this.updateMergeTimer = null;
|
|
195
|
+
const segments = this.pendingUpdateSegments;
|
|
196
|
+
this.pendingUpdateSegments = null;
|
|
197
|
+
if (segments === null || segments.length === 0) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const parts = segments.map(
|
|
201
|
+
(s) => `${s.keys.join(", ")} ${stringifyForAttributesLog(s.value)}`,
|
|
202
|
+
);
|
|
203
|
+
this.emitInfo(`[WindowManager][${this.name}]: safeUpdateAttributes ${parts.join(" | ")}`);
|
|
204
|
+
for (const s of segments) {
|
|
205
|
+
s.keys.length = 0;
|
|
206
|
+
s.value = undefined;
|
|
207
|
+
}
|
|
208
|
+
segments.length = 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* 带 debounce 时:连续调用若 `keys` 与上一段完全相同则覆盖该段的 `value`;否则追加一段。
|
|
213
|
+
* flush 时输出一条日志,多段用 ` | ` 连接。
|
|
214
|
+
*/
|
|
215
|
+
logDebouncedUpdateAttributes(keys: string[], value: unknown): void {
|
|
216
|
+
const ms = this.debounceTime;
|
|
217
|
+
const debounced = ms != null && ms > 0;
|
|
218
|
+
const keysCopy = [...keys];
|
|
219
|
+
|
|
220
|
+
if (!debounced) {
|
|
221
|
+
this.emitInfo(
|
|
222
|
+
`[WindowManager][${this.name}]: safeUpdateAttributes ${keysCopy.join(", ")} ${stringifyForAttributesLog(value)}`,
|
|
223
|
+
);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (this.updateMergeTimer != null) {
|
|
228
|
+
clearTimeout(this.updateMergeTimer);
|
|
229
|
+
this.updateMergeTimer = null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (this.pendingUpdateSegments === null || this.pendingUpdateSegments.length === 0) {
|
|
233
|
+
this.pendingUpdateSegments = [{ keys: keysCopy, value }];
|
|
234
|
+
} else {
|
|
235
|
+
const last = this.pendingUpdateSegments[this.pendingUpdateSegments.length - 1];
|
|
236
|
+
if (keysPathEqual(last.keys, keysCopy)) {
|
|
237
|
+
last.value = value;
|
|
238
|
+
} else {
|
|
239
|
+
this.pendingUpdateSegments.push({ keys: keysCopy, value });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
this.updateMergeTimer = setTimeout(() => this.flushUpdateAttributesMerge(), ms);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* 销毁:清除所有 `setTimeout` debounce 定时器,并丢弃尚未输出的暂存日志(不补打日志)。
|
|
248
|
+
* WindowManager 销毁时应调用,避免泄漏与销毁后仍触发 `logger.info`。
|
|
249
|
+
*/
|
|
250
|
+
destroy(): void {
|
|
251
|
+
if (this.flushTimer != null) {
|
|
252
|
+
clearTimeout(this.flushTimer);
|
|
253
|
+
this.flushTimer = null;
|
|
254
|
+
}
|
|
255
|
+
if (this.shallowMergeTimer != null) {
|
|
256
|
+
clearTimeout(this.shallowMergeTimer);
|
|
257
|
+
this.shallowMergeTimer = null;
|
|
258
|
+
}
|
|
259
|
+
if (this.updateMergeTimer != null) {
|
|
260
|
+
clearTimeout(this.updateMergeTimer);
|
|
261
|
+
this.updateMergeTimer = null;
|
|
262
|
+
}
|
|
263
|
+
this.pendingArgs = null;
|
|
264
|
+
this.pendingShallowMerge = null;
|
|
265
|
+
this.pendingUpdateSegments = null;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** 与 `destroy()` 相同,保留旧名以兼容 */
|
|
269
|
+
dispose(): void {
|
|
270
|
+
this.destroy();
|
|
271
|
+
}
|
|
272
|
+
}
|
package/src/View/MainView.ts
CHANGED
|
@@ -3,12 +3,21 @@ import { callbacks } from "../callback";
|
|
|
3
3
|
import { createView } from "./ViewManager";
|
|
4
4
|
import { debounce, get, isEmpty, isEqual } from "lodash";
|
|
5
5
|
import { internalEmitter } from "../InternalEmitter";
|
|
6
|
-
import { Fields } from "../AttributesDelegate";
|
|
6
|
+
import { Fields, type MainViewCamera } from "../AttributesDelegate";
|
|
7
7
|
import { setViewFocusScenePath } from "../Utils/Common";
|
|
8
8
|
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";
|
|
13
|
+
|
|
14
|
+
type MainViewScreenLike = {
|
|
15
|
+
refreshSize?: (width: number, height: number) => void;
|
|
16
|
+
resizeObserver?: {
|
|
17
|
+
disconnect?: () => void;
|
|
18
|
+
observe?: (target: Element) => void;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
12
21
|
|
|
13
22
|
export class MainViewProxy {
|
|
14
23
|
/** Refresh the view's camera in an interval of 1.5s. */
|
|
@@ -17,12 +26,20 @@ export class MainViewProxy {
|
|
|
17
26
|
private scale?: number;
|
|
18
27
|
private started = false;
|
|
19
28
|
private mainViewIsAddListener = false;
|
|
29
|
+
private isForcingMainViewDivElement = false;
|
|
30
|
+
private wrapperRectWorkaroundFrame = 0;
|
|
31
|
+
private pendingWrapperRectChange?: { width: number; height: number; origin?: string };
|
|
20
32
|
private mainView: View;
|
|
21
33
|
private store = this.manager.store;
|
|
22
34
|
private viewMode = this.manager.windowManger.viewMode;
|
|
23
35
|
|
|
24
36
|
private sideEffectManager = new SideEffectManager();
|
|
25
37
|
|
|
38
|
+
private playgroundSizeChangeListenerLocalConsole = new LocalConsole("playgroundSizeChangeListener", 100);
|
|
39
|
+
private sizeUpdatedLocalConsole = new LocalConsole("sizeUpdated", 100);
|
|
40
|
+
private cameraUpdatedLocalConsole = new LocalConsole("cameraUpdated", 100);
|
|
41
|
+
private cameraReactionLocalConsole = new LocalConsole("cameraReaction", 100);
|
|
42
|
+
|
|
26
43
|
constructor(private manager: AppManager) {
|
|
27
44
|
this.mainView = this.createMainView();
|
|
28
45
|
this.moveCameraSizeByAttributes();
|
|
@@ -33,6 +50,15 @@ export class MainViewProxy {
|
|
|
33
50
|
this.startListenWritableChange();
|
|
34
51
|
});
|
|
35
52
|
const playgroundSizeChangeListener = () => {
|
|
53
|
+
this.playgroundSizeChangeListenerLocalConsole.log(
|
|
54
|
+
JSON.stringify(this.mainView.camera),
|
|
55
|
+
JSON.stringify(this.mainView.size),
|
|
56
|
+
JSON.stringify(this.mainViewSize),
|
|
57
|
+
JSON.stringify(this.mainViewCamera),
|
|
58
|
+
window.outerHeight, window.outerWidth,
|
|
59
|
+
window.visualViewport?.width ?? "null", window.visualViewport?.height ?? "null",
|
|
60
|
+
window.visualViewport?.offsetLeft ?? "null", window.visualViewport?.offsetTop ?? "null",
|
|
61
|
+
);
|
|
36
62
|
this.sizeChangeHandler(this.mainViewSize);
|
|
37
63
|
};
|
|
38
64
|
this.sideEffectManager.add(() => {
|
|
@@ -41,6 +67,9 @@ export class MainViewProxy {
|
|
|
41
67
|
this.sideEffectManager.add(() => {
|
|
42
68
|
return internalEmitter.on("containerSizeRatioUpdate", this.onUpdateContainerSizeRatio);
|
|
43
69
|
});
|
|
70
|
+
this.sideEffectManager.add(() => {
|
|
71
|
+
return internalEmitter.on("wrapperRectChange", this.onWrapperRectChange);
|
|
72
|
+
});
|
|
44
73
|
this.sideEffectManager.add(() => {
|
|
45
74
|
return internalEmitter.on("startReconnect", () => {
|
|
46
75
|
if (!this.didRelease) {
|
|
@@ -96,13 +125,105 @@ export class MainViewProxy {
|
|
|
96
125
|
this.moveCamera(this.mainViewCamera);
|
|
97
126
|
}
|
|
98
127
|
|
|
128
|
+
private onWrapperRectChange = (payload: { width: number; height: number; origin?: string }) => {
|
|
129
|
+
this.pendingWrapperRectChange = payload;
|
|
130
|
+
if (this.wrapperRectWorkaroundFrame) {
|
|
131
|
+
cancelAnimationFrame(this.wrapperRectWorkaroundFrame);
|
|
132
|
+
}
|
|
133
|
+
this.wrapperRectWorkaroundFrame = requestAnimationFrame(this.runWrapperRectWorkaround);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
private runWrapperRectWorkaround = () => {
|
|
137
|
+
this.wrapperRectWorkaroundFrame = 0;
|
|
138
|
+
const payload = this.pendingWrapperRectChange;
|
|
139
|
+
const element = this.mainView.divElement;
|
|
140
|
+
this.pendingWrapperRectChange = undefined;
|
|
141
|
+
if (!payload || !element) return;
|
|
142
|
+
|
|
143
|
+
const rect = element.getBoundingClientRect();
|
|
144
|
+
const observedSize = { width: rect.width, height: rect.height };
|
|
145
|
+
const wrapperMatchesDom =
|
|
146
|
+
Math.abs(payload.width - observedSize.width) <= 0.5 &&
|
|
147
|
+
Math.abs(payload.height - observedSize.height) <= 0.5;
|
|
148
|
+
const viewIsStale =
|
|
149
|
+
Math.abs(this.mainView.size.width - observedSize.width) > 0.5 ||
|
|
150
|
+
Math.abs(this.mainView.size.height - observedSize.height) > 0.5;
|
|
151
|
+
|
|
152
|
+
if (wrapperMatchesDom && viewIsStale) {
|
|
153
|
+
this.forceSyncMainViewDivElement(
|
|
154
|
+
`wrapperRectChange:${payload.origin || "unknown"}`,
|
|
155
|
+
observedSize,
|
|
156
|
+
element
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
private forceSyncMainViewDivElement(
|
|
162
|
+
reason: string,
|
|
163
|
+
observedSize: Pick<Size, "width" | "height">,
|
|
164
|
+
element: HTMLDivElement
|
|
165
|
+
) {
|
|
166
|
+
const { width: viewWidth, height: viewHeight } = this.mainView.size;
|
|
167
|
+
let targetElement = element;
|
|
168
|
+
if (
|
|
169
|
+
Math.abs(viewWidth - observedSize.width) <= 0.5 &&
|
|
170
|
+
Math.abs(viewHeight - observedSize.height) <= 0.5
|
|
171
|
+
) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (this.isForcingMainViewDivElement) {
|
|
175
|
+
console.log("[window-manager] skipForceSyncMainViewDivElement " + JSON.stringify({
|
|
176
|
+
reason,
|
|
177
|
+
observedSize,
|
|
178
|
+
viewSize: this.mainView.size,
|
|
179
|
+
}));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
this.isForcingMainViewDivElement = true;
|
|
183
|
+
try {
|
|
184
|
+
const mainView = this.mainView as View & { screen?: MainViewScreenLike };
|
|
185
|
+
const screen = mainView.screen;
|
|
186
|
+
const resizeObserver = screen?.resizeObserver;
|
|
187
|
+
if (typeof screen?.refreshSize === "function") {
|
|
188
|
+
console.log(
|
|
189
|
+
"[window-manager] forceSyncMainViewDivElement observerReset " +
|
|
190
|
+
JSON.stringify({
|
|
191
|
+
reason,
|
|
192
|
+
viewSize: this.mainView.size,
|
|
193
|
+
observedSize,
|
|
194
|
+
})
|
|
195
|
+
);
|
|
196
|
+
// Reset the observer queue so we sync against the current DOM box,
|
|
197
|
+
// not a stale ResizeObserver entry from a rapid resize burst.
|
|
198
|
+
resizeObserver?.disconnect?.();
|
|
199
|
+
screen.refreshSize(observedSize.width, observedSize.height);
|
|
200
|
+
resizeObserver?.observe?.(element);
|
|
201
|
+
}
|
|
202
|
+
} finally {
|
|
203
|
+
queueMicrotask(() => {
|
|
204
|
+
const rect = targetElement.getBoundingClientRect();
|
|
205
|
+
console.log("[window-manager] forceSyncMainViewDivElementResult " + JSON.stringify({
|
|
206
|
+
reason,
|
|
207
|
+
viewSize: this.mainView.size,
|
|
208
|
+
rect: { width: rect.width, height: rect.height },
|
|
209
|
+
}));
|
|
210
|
+
this.isForcingMainViewDivElement = false;
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
99
215
|
public start() {
|
|
216
|
+
console.log("[window-manager] start attributes size:" + JSON.stringify(this.mainViewSize));
|
|
100
217
|
this.sizeChangeHandler(this.mainViewSize);
|
|
101
218
|
if (this.started) return;
|
|
102
219
|
this.addCameraListener();
|
|
103
220
|
this.addCameraReaction();
|
|
104
221
|
if (this.manager.room) this.syncMainView(this.manager.room);
|
|
105
222
|
this.started = true;
|
|
223
|
+
if(this.mainView.focusScenePath) {
|
|
224
|
+
this.manager.windowManger.onMainViewScenePathChangeHandler(this.mainView.focusScenePath);
|
|
225
|
+
}
|
|
226
|
+
console.log("[window-manager] start end mainView size:" + JSON.stringify(this.mainView.size));
|
|
106
227
|
}
|
|
107
228
|
|
|
108
229
|
public addCameraReaction = () => {
|
|
@@ -118,10 +239,11 @@ export class MainViewProxy {
|
|
|
118
239
|
private cameraReaction = () => {
|
|
119
240
|
return reaction(
|
|
120
241
|
() => this.mainViewCamera,
|
|
121
|
-
camera => {
|
|
242
|
+
(camera: MainViewCamera | undefined) => {
|
|
122
243
|
if (camera && camera.id !== this.manager.uid) {
|
|
123
244
|
this.moveCameraToContian(this.mainViewSize);
|
|
124
245
|
this.moveCamera(camera);
|
|
246
|
+
this.cameraReactionLocalConsole.log(`camera: ${JSON.stringify(camera)}, current size: ${JSON.stringify(this.mainViewSize)}`);
|
|
125
247
|
}
|
|
126
248
|
},
|
|
127
249
|
{ fireImmediately: true }
|
|
@@ -132,12 +254,15 @@ export class MainViewProxy {
|
|
|
132
254
|
if (size) {
|
|
133
255
|
this.moveCameraToContian(size);
|
|
134
256
|
this.moveCamera(this.mainViewCamera);
|
|
257
|
+
console.log("[window-manager] sizeChangeHandler current size and camera" + JSON.stringify(size) + JSON.stringify(this.mainViewCamera) +
|
|
258
|
+
JSON.stringify(this.mainView.camera) + JSON.stringify(this.mainView.size));
|
|
135
259
|
}
|
|
136
260
|
this.ensureMainViewSize();
|
|
137
261
|
}, 30);
|
|
138
262
|
|
|
139
263
|
public onUpdateContainerSizeRatio = () => {
|
|
140
264
|
const size = this.store.getMainViewSize();
|
|
265
|
+
console.log("[window-manager] onUpdateContainerSizeRatio " + JSON.stringify(size));
|
|
141
266
|
this.sizeChangeHandler(size);
|
|
142
267
|
};
|
|
143
268
|
|
|
@@ -230,18 +355,18 @@ export class MainViewProxy {
|
|
|
230
355
|
|
|
231
356
|
private addCameraListener() {
|
|
232
357
|
this.view.callbacks.on("onCameraUpdatedByDevice", this.onCameraUpdatedByDevice);
|
|
233
|
-
this.view.callbacks.on("onCameraUpdated", this.
|
|
234
|
-
this.view.callbacks.on("onSizeUpdated", this.
|
|
358
|
+
this.view.callbacks.on("onCameraUpdated", this.onCameraUpdated);
|
|
359
|
+
this.view.callbacks.on("onSizeUpdated", this.onSizeUpdated);
|
|
235
360
|
}
|
|
236
361
|
|
|
237
362
|
private removeCameraListener() {
|
|
238
363
|
this.view.callbacks.off("onCameraUpdatedByDevice", this.onCameraUpdatedByDevice);
|
|
239
|
-
this.view.callbacks.off("onCameraUpdated", this.
|
|
240
|
-
this.view.callbacks.off("onSizeUpdated", this.
|
|
364
|
+
this.view.callbacks.off("onCameraUpdated", this.onCameraUpdated);
|
|
365
|
+
this.view.callbacks.off("onSizeUpdated", this.onSizeUpdated);
|
|
241
366
|
}
|
|
242
367
|
|
|
243
368
|
private _syncMainViewTimer = 0;
|
|
244
|
-
private
|
|
369
|
+
private handleCameraOrSizeUpdated = () => {
|
|
245
370
|
callbacks.emit("cameraStateChange", this.cameraState);
|
|
246
371
|
// sdk >= 2.16.43 的 syncMainView() 可以写入当前 main view 的 camera, 以修复复制粘贴元素的位置
|
|
247
372
|
// 注意到这个操作会发送信令,应当避免频繁调用
|
|
@@ -252,6 +377,16 @@ export class MainViewProxy {
|
|
|
252
377
|
this.ensureMainViewSize();
|
|
253
378
|
};
|
|
254
379
|
|
|
380
|
+
private onCameraUpdated = (camera: Camera) => {
|
|
381
|
+
this.cameraUpdatedLocalConsole.log(JSON.stringify(camera));
|
|
382
|
+
this.handleCameraOrSizeUpdated();
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
private onSizeUpdated = (size: Size) => {
|
|
386
|
+
this.sizeUpdatedLocalConsole.log(JSON.stringify(size));
|
|
387
|
+
this.handleCameraOrSizeUpdated();
|
|
388
|
+
};
|
|
389
|
+
|
|
255
390
|
private ensureMainViewSize() {
|
|
256
391
|
if (
|
|
257
392
|
(!this.mainViewSize ||
|
|
@@ -309,6 +444,15 @@ export class MainViewProxy {
|
|
|
309
444
|
};
|
|
310
445
|
|
|
311
446
|
public destroy() {
|
|
447
|
+
console.log("[window-manager] destroy ");
|
|
448
|
+
if (this.wrapperRectWorkaroundFrame) {
|
|
449
|
+
cancelAnimationFrame(this.wrapperRectWorkaroundFrame);
|
|
450
|
+
this.wrapperRectWorkaroundFrame = 0;
|
|
451
|
+
}
|
|
452
|
+
this.playgroundSizeChangeListenerLocalConsole.destroy();
|
|
453
|
+
this.sizeUpdatedLocalConsole.destroy();
|
|
454
|
+
this.cameraUpdatedLocalConsole.destroy();
|
|
455
|
+
this.cameraReactionLocalConsole.destroy();
|
|
312
456
|
this.removeMainViewListener();
|
|
313
457
|
this.stop();
|
|
314
458
|
this.sideEffectManager.flushAll();
|