@netless/app-slide 0.0.17 → 0.0.21
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/DocsViewer/index.d.ts +1 -0
- package/dist/SlideController/helpers.d.ts +6 -0
- package/dist/SlideController/index.d.ts +51 -0
- package/dist/SlideDocsViewer/index.d.ts +13 -7
- package/dist/index.d.ts +4 -10
- package/dist/main.cjs.js +4194 -2292
- package/dist/main.cjs.js.map +1 -1
- package/dist/main.es.js +29691 -25580
- package/dist/main.es.js.map +1 -1
- package/dist/main.iife.js +4194 -2292
- package/dist/main.iife.js.map +1 -1
- package/dist/typings.d.ts +14 -0
- package/dist/utils/helpers.d.ts +1 -0
- package/package.json +7 -2
- package/src/DocsViewer/index.ts +12 -7
- package/src/SlideController/helpers.ts +39 -0
- package/src/SlideController/index.ts +257 -0
- package/src/SlideDocsViewer/index.ts +41 -13
- package/src/index.ts +49 -139
- package/src/typings.ts +17 -0
- package/src/utils/helpers.ts +4 -0
- package/dist/utils/slide.d.ts +0 -47
- package/playground.ts +0 -31
- package/src/utils/slide.ts +0 -203
- package/tsconfig.json +0 -7
- package/vite.config.ts +0 -3
package/src/index.ts
CHANGED
|
@@ -1,181 +1,90 @@
|
|
|
1
|
-
import type { Event, Player, RoomState } from "white-web-sdk";
|
|
2
|
-
import type { Slide, SyncEvent } from "@netless/slide";
|
|
3
1
|
import type { NetlessApp } from "@netless/window-manager";
|
|
4
|
-
import type {
|
|
2
|
+
import type { RoomState } from "white-web-sdk";
|
|
3
|
+
import type { MountSlideOptions } from "./SlideDocsViewer";
|
|
4
|
+
import type { Attributes } from "./typings";
|
|
5
5
|
|
|
6
|
-
import { SLIDE_EVENTS } from "@netless/slide";
|
|
7
|
-
import { ensureAttributes } from "@netless/app-shared";
|
|
8
6
|
import { SideEffectManager } from "side-effect-manager";
|
|
7
|
+
import { ensureAttributes } from "@netless/app-shared";
|
|
8
|
+
import {
|
|
9
|
+
DefaultUrl,
|
|
10
|
+
EmptyAttributes,
|
|
11
|
+
syncSceneWithSlide,
|
|
12
|
+
SlideController,
|
|
13
|
+
} from "./SlideController";
|
|
9
14
|
import { SlideDocsViewer } from "./SlideDocsViewer";
|
|
10
|
-
import { createSlideController, syncSceneWithSlide } from "./utils/slide";
|
|
11
|
-
import { isObj } from "./utils/helpers";
|
|
12
15
|
import styles from "./style.scss?inline";
|
|
13
16
|
|
|
14
|
-
export type
|
|
17
|
+
export type { Attributes };
|
|
15
18
|
|
|
16
|
-
export
|
|
17
|
-
/** convert task id */
|
|
18
|
-
taskId: string;
|
|
19
|
-
/** base url of converted resources */
|
|
20
|
-
url: string;
|
|
21
|
-
/** internal state of slide, do not change */
|
|
22
|
-
state: SlideState | null;
|
|
23
|
-
}
|
|
19
|
+
export { DefaultUrl };
|
|
24
20
|
|
|
25
21
|
const SlideApp: NetlessApp<Attributes> = {
|
|
26
22
|
kind: "Slide",
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const displayer = context.getDisplayer();
|
|
32
|
-
const attrs = ensureAttributes(context, {
|
|
33
|
-
taskId: "",
|
|
34
|
-
url: "",
|
|
35
|
-
state: null,
|
|
36
|
-
});
|
|
23
|
+
setup(context) {
|
|
24
|
+
if (context.getIsWritable()) {
|
|
25
|
+
ensureAttributes(context, EmptyAttributes);
|
|
26
|
+
}
|
|
37
27
|
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
const attributes = context.getAttributes();
|
|
29
|
+
if (!attributes?.taskId) {
|
|
30
|
+
throw new Error("[Slide] no taskId");
|
|
40
31
|
}
|
|
41
32
|
|
|
33
|
+
const view = context.getView();
|
|
42
34
|
if (!view) {
|
|
43
|
-
throw new Error(
|
|
35
|
+
throw new Error("[Slide] no view, please set scenePath on addApp()");
|
|
44
36
|
}
|
|
37
|
+
view.disableCameraTransform = true;
|
|
45
38
|
|
|
46
|
-
const
|
|
47
|
-
const fixElectron = !!context.getAppOptions()?.fixElectron;
|
|
48
|
-
const resolution = context.getAppOptions()?.resolution;
|
|
49
|
-
|
|
39
|
+
const box = context.getBox();
|
|
50
40
|
box.mountStyles(styles);
|
|
51
41
|
|
|
52
|
-
|
|
53
|
-
// 因为 view 存在,init scene path 必定存在
|
|
42
|
+
// must exist because of view
|
|
54
43
|
const baseScenePath = context.getInitScenePath() as string;
|
|
55
|
-
const channel = `channel-${context.appId}`;
|
|
56
44
|
|
|
57
|
-
let
|
|
58
|
-
|
|
59
|
-
const timestamp = () => {
|
|
60
|
-
if (room) {
|
|
61
|
-
return room.calibrationTimestamp;
|
|
62
|
-
} else {
|
|
63
|
-
return (displayer as Player).beginTimestamp + (displayer as Player).progressTime;
|
|
64
|
-
}
|
|
65
|
-
};
|
|
45
|
+
let docsViewer: SlideDocsViewer | null = null;
|
|
66
46
|
|
|
67
47
|
const onPageChanged = (page: number) => {
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
syncSceneWithSlide(room, context,
|
|
48
|
+
const room = context.getRoom();
|
|
49
|
+
if (docsViewer && docsViewer.slideController && room && context.getIsWritable()) {
|
|
50
|
+
syncSceneWithSlide(room, context, docsViewer.slideController.slide, baseScenePath);
|
|
71
51
|
docsViewer.viewer.setPageIndex(page - 1);
|
|
72
52
|
}
|
|
73
53
|
};
|
|
74
54
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const onTransitionEnd = () => {
|
|
80
|
-
docsViewer.viewer.setPaused();
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const onDispatchSyncEvent = (event: SyncEvent) => {
|
|
84
|
-
if (debug) {
|
|
85
|
-
console.log("[Slide] dispatch", event);
|
|
86
|
-
}
|
|
87
|
-
if (context.getIsWritable() && theController && room) {
|
|
88
|
-
room.dispatchMagixEvent(channel, { type: SLIDE_EVENTS.syncDispatch, payload: event });
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const onStateChange = (slideState: SlideState) => {
|
|
93
|
-
if (context.getIsWritable()) {
|
|
94
|
-
context.updateAttributes(["state"], slideState);
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
sideEffect.add(() => {
|
|
99
|
-
let first = !context.isAddApp;
|
|
100
|
-
const magixEventListener = async (ev: Event) => {
|
|
101
|
-
if (debug) {
|
|
102
|
-
console.log(
|
|
103
|
-
"[Slide] receive",
|
|
104
|
-
ev.payload.payload,
|
|
105
|
-
"(",
|
|
106
|
-
!!theController,
|
|
107
|
-
ev.event === channel,
|
|
108
|
-
ev.payload.type === SLIDE_EVENTS.syncDispatch,
|
|
109
|
-
")"
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
if (theController && ev.event === channel && isObj(ev.payload)) {
|
|
113
|
-
const { type, payload } = ev.payload;
|
|
114
|
-
if (type === SLIDE_EVENTS.syncDispatch) {
|
|
115
|
-
if (first && attrs.state) {
|
|
116
|
-
first = false;
|
|
117
|
-
theController.setState(attrs.state);
|
|
118
|
-
}
|
|
119
|
-
theController.receiveSyncEvent(payload);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
displayer.addMagixEventListener(channel, magixEventListener, {
|
|
124
|
-
fireSelfEventAfterCommit: true,
|
|
125
|
-
});
|
|
126
|
-
return () => displayer.removeMagixEventListener(channel, magixEventListener);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
const mountSlideController = async (anchor: HTMLDivElement) => {
|
|
130
|
-
theController = createSlideController(
|
|
131
|
-
anchor,
|
|
132
|
-
attrs.taskId,
|
|
133
|
-
attrs.url || "https://convertcdn.netless.link/dynamicConvert",
|
|
134
|
-
debug,
|
|
135
|
-
JSON.parse(JSON.stringify(attrs.state)),
|
|
136
|
-
displayer.state.sceneState.index + 1,
|
|
55
|
+
const mountSlideController = (options: MountSlideOptions): SlideController => {
|
|
56
|
+
const slideController = new SlideController({
|
|
57
|
+
context,
|
|
58
|
+
...options,
|
|
137
59
|
onPageChanged,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
);
|
|
146
|
-
theController.initialize();
|
|
147
|
-
await theController.ready;
|
|
148
|
-
return theController;
|
|
60
|
+
});
|
|
61
|
+
if (import.meta.env.DEV) {
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
|
+
(window as any).slideController = slideController;
|
|
64
|
+
}
|
|
65
|
+
slideController.readyPromise.then(options.onReady);
|
|
66
|
+
return slideController;
|
|
149
67
|
};
|
|
150
68
|
|
|
151
|
-
|
|
69
|
+
docsViewer = new SlideDocsViewer({
|
|
152
70
|
box,
|
|
153
71
|
view,
|
|
154
72
|
mountSlideController,
|
|
155
73
|
mountWhiteboard: dom => context.mountView(dom),
|
|
156
74
|
});
|
|
157
75
|
|
|
158
|
-
try {
|
|
159
|
-
await docsViewer.mount();
|
|
160
|
-
view.disableCameraTransform = true;
|
|
161
|
-
} catch (err) {
|
|
162
|
-
console.warn(err);
|
|
163
|
-
console.log("[Slide]: destroy by error");
|
|
164
|
-
sideEffect.flushAll();
|
|
165
|
-
docsViewer.destroy();
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
76
|
if (import.meta.env.DEV) {
|
|
170
77
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
171
78
|
(window as any).slideDoc = docsViewer;
|
|
172
79
|
}
|
|
173
80
|
|
|
81
|
+
const room = context.getRoom();
|
|
82
|
+
const sideEffect = new SideEffectManager();
|
|
174
83
|
if (room) {
|
|
175
84
|
docsViewer.toggleClickThrough(room.state.memberState.currentApplianceName);
|
|
176
85
|
sideEffect.add(() => {
|
|
177
86
|
const onRoomStateChanged = (e: Partial<RoomState>) => {
|
|
178
|
-
if (e.memberState) {
|
|
87
|
+
if (e.memberState && docsViewer) {
|
|
179
88
|
docsViewer.toggleClickThrough(e.memberState.currentApplianceName);
|
|
180
89
|
}
|
|
181
90
|
};
|
|
@@ -184,15 +93,16 @@ const SlideApp: NetlessApp<Attributes> = {
|
|
|
184
93
|
});
|
|
185
94
|
}
|
|
186
95
|
|
|
187
|
-
context.emitter.on("writableChange", () => {
|
|
188
|
-
docsViewer.setReadonly(!context.getIsWritable());
|
|
189
|
-
});
|
|
190
|
-
|
|
191
96
|
context.emitter.on("destroy", () => {
|
|
192
97
|
console.log("[Slide]: destroy");
|
|
193
98
|
sideEffect.flushAll();
|
|
194
|
-
docsViewer
|
|
99
|
+
if (docsViewer) {
|
|
100
|
+
docsViewer.destroy();
|
|
101
|
+
docsViewer = null;
|
|
102
|
+
}
|
|
195
103
|
});
|
|
104
|
+
|
|
105
|
+
docsViewer.mount();
|
|
196
106
|
},
|
|
197
107
|
};
|
|
198
108
|
|
package/src/typings.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Slide, SLIDE_EVENTS, SyncEvent } from "@netless/slide";
|
|
2
|
+
|
|
3
|
+
export type SlideState = Slide["slideState"];
|
|
4
|
+
|
|
5
|
+
export interface Attributes {
|
|
6
|
+
/** convert task id */
|
|
7
|
+
taskId: string;
|
|
8
|
+
/** base url of converted resources */
|
|
9
|
+
url: string;
|
|
10
|
+
/** internal state of slide, do not change */
|
|
11
|
+
state: SlideState | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type MagixPayload = {
|
|
15
|
+
type: typeof SLIDE_EVENTS.syncDispatch;
|
|
16
|
+
payload: SyncEvent;
|
|
17
|
+
};
|
package/src/utils/helpers.ts
CHANGED
package/dist/utils/slide.d.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { SyncEvent } from "@netless/slide";
|
|
2
|
-
import type { Room } from "white-web-sdk";
|
|
3
|
-
import type { AppContext } from "@netless/window-manager";
|
|
4
|
-
import type { DocsViewerPage } from "../DocsViewer";
|
|
5
|
-
import type { Attributes, SlideState } from "../index";
|
|
6
|
-
import { Slide } from "@netless/slide";
|
|
7
|
-
/**
|
|
8
|
-
* 因为 slide 的 `renderSlide()` 比较耗时,而切 scene 很快,这里让 scene 跟随 slide 的状态。
|
|
9
|
-
*
|
|
10
|
-
* 同时,UI 也应该和 slide 对齐。考虑到快速点击下一页的情况:slide 无法立刻切到下一页。我们应该记住当前的
|
|
11
|
-
* "目标页",slide 的 `renderEnd` 没触发前不再继续调用 `renderSlide()`。
|
|
12
|
-
*/
|
|
13
|
-
export declare function syncSceneWithSlide(room: Room, context: AppContext<Attributes>, slide: Slide, baseScenePath: string): void;
|
|
14
|
-
export declare function createDocsViewerPages(slide: Slide): DocsViewerPage[];
|
|
15
|
-
/**
|
|
16
|
-
* slide 依赖事件回溯 (收到广播事件) 来进行同步进度,每次 `renderSlide()` 等操作都不会实际触发更改,
|
|
17
|
-
* 而是发出一条广播事件,等收到事件后,使用 `slide.emit(SLIDE_EVENTS.syncReceive)` 来实际触发。
|
|
18
|
-
*
|
|
19
|
-
* controller 要保证每个事件都正确反馈给 slide。
|
|
20
|
-
*/
|
|
21
|
-
export declare class SlideController {
|
|
22
|
-
readonly slide: Slide;
|
|
23
|
-
readonly onPageChanged: (page: number) => void;
|
|
24
|
-
readonly onTransitionStart: () => void;
|
|
25
|
-
readonly onTransitionEnd: () => void;
|
|
26
|
-
readonly onDispatchSyncEvent: (event: SyncEvent) => void;
|
|
27
|
-
readonly onStateChange: (state: SlideState) => void;
|
|
28
|
-
private readonly initialState;
|
|
29
|
-
private readonly initialPage;
|
|
30
|
-
constructor(slide: Slide, onPageChanged: (page: number) => void, onTransitionStart: () => void, onTransitionEnd: () => void, onDispatchSyncEvent: (event: SyncEvent) => void, onStateChange: (state: SlideState) => void, initialState: SlideState | null, initialPage: number);
|
|
31
|
-
private resolveReady;
|
|
32
|
-
private reject;
|
|
33
|
-
readonly ready: Promise<this>;
|
|
34
|
-
private onRenderError;
|
|
35
|
-
initialize(): void;
|
|
36
|
-
private pollCount;
|
|
37
|
-
private pollReadyState;
|
|
38
|
-
receiveSyncEvent(event: SyncEvent): void;
|
|
39
|
-
setState(state: SlideState): void;
|
|
40
|
-
isReady(): boolean;
|
|
41
|
-
private targetingPage;
|
|
42
|
-
private resetTargetingPage;
|
|
43
|
-
jumpToPage(page: number): void;
|
|
44
|
-
destroy(): void;
|
|
45
|
-
}
|
|
46
|
-
export declare function createSlideController(anchor: HTMLDivElement, taskId: string, url: string, controller: boolean, initialState: Slide["slideState"] | null, initialPage: number, onPageChanged: (page: number) => void, onTransitionStart: () => void, onTransitionEnd: () => void, onDispatchSyncEvent: (event: SyncEvent) => void, onStateChange: (state: Slide["slideState"]) => void, timestamp: () => number, _fixElectron: boolean, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
47
|
-
resolution?: number): SlideController;
|
package/playground.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { PlaygroundConfigs } from "../playground/typings";
|
|
2
|
-
import type { Attributes } from "./src";
|
|
3
|
-
|
|
4
|
-
const options: PlaygroundConfigs<Attributes> = [
|
|
5
|
-
{
|
|
6
|
-
kind: "Slide",
|
|
7
|
-
src: () => import("./src"),
|
|
8
|
-
options: {
|
|
9
|
-
title: "ByeBye GoodBye",
|
|
10
|
-
scenePath: `/Slide/5f36bc1041c811ecba2783d2bae94ad0`,
|
|
11
|
-
},
|
|
12
|
-
attributes: {
|
|
13
|
-
taskId: "5f36bc1041c811ecba2783d2bae94ad0",
|
|
14
|
-
url: "https://convertcdn.netless.group/dynamicConvert",
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
kind: "Slide",
|
|
19
|
-
src: () => import("./src"),
|
|
20
|
-
options: {
|
|
21
|
-
title: "大凉山区",
|
|
22
|
-
scenePath: `/Slide/8887363041c811ecba2783d2bae94ad0`,
|
|
23
|
-
},
|
|
24
|
-
attributes: {
|
|
25
|
-
taskId: "8887363041c811ecba2783d2bae94ad0",
|
|
26
|
-
url: "https://convertcdn.netless.group/dynamicConvert",
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
export default options;
|
package/src/utils/slide.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import type { SyncEvent } from "@netless/slide";
|
|
2
|
-
import type { Room, ScenePathType } from "white-web-sdk";
|
|
3
|
-
import type { AppContext } from "@netless/window-manager";
|
|
4
|
-
import type { DocsViewerPage } from "../DocsViewer";
|
|
5
|
-
import type { Attributes, SlideState } from "../index";
|
|
6
|
-
|
|
7
|
-
import { SLIDE_EVENTS, Slide } from "@netless/slide";
|
|
8
|
-
import { clamp } from "./helpers";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 因为 slide 的 `renderSlide()` 比较耗时,而切 scene 很快,这里让 scene 跟随 slide 的状态。
|
|
12
|
-
*
|
|
13
|
-
* 同时,UI 也应该和 slide 对齐。考虑到快速点击下一页的情况:slide 无法立刻切到下一页。我们应该记住当前的
|
|
14
|
-
* "目标页",slide 的 `renderEnd` 没触发前不再继续调用 `renderSlide()`。
|
|
15
|
-
*/
|
|
16
|
-
export function syncSceneWithSlide(
|
|
17
|
-
room: Room,
|
|
18
|
-
context: AppContext<Attributes>,
|
|
19
|
-
slide: Slide,
|
|
20
|
-
baseScenePath: string
|
|
21
|
-
) {
|
|
22
|
-
const page = slide.slideState.currentSlideIndex;
|
|
23
|
-
// 如果不存在 currentSlideIndex,可能没初始化完,此时什么都不做
|
|
24
|
-
if (page == null) return;
|
|
25
|
-
// 如果 room 不可写,什么也不做
|
|
26
|
-
if (!context.getIsWritable()) return;
|
|
27
|
-
|
|
28
|
-
const scenePath = [baseScenePath, page].join("/");
|
|
29
|
-
// 这里用 === none 而不是 !== page,是因为这个接口有 bug,最新的 sdk 才修掉
|
|
30
|
-
if (room.scenePathType(scenePath) === ("none" as ScenePathType.None)) {
|
|
31
|
-
// 如果不存在对应 scene,重新创建一遍
|
|
32
|
-
room.removeScenes(baseScenePath);
|
|
33
|
-
const count = slide.slideCount;
|
|
34
|
-
const scenes: { name: string }[] = [];
|
|
35
|
-
for (let i = 1; i <= count; ++i) scenes.push({ name: `${i}` });
|
|
36
|
-
room.putScenes(baseScenePath, scenes);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
context.setScenePath(scenePath);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function createDocsViewerPages(slide: Slide): DocsViewerPage[] {
|
|
43
|
-
const { width, height, slideCount, slideState } = slide;
|
|
44
|
-
const { taskId, url } = slideState;
|
|
45
|
-
const pages: DocsViewerPage[] = [];
|
|
46
|
-
for (let i = 1; i <= slideCount; ++i) {
|
|
47
|
-
pages.push({ width, height, thumbnail: `${url}/${taskId}/preview/${i}.png`, src: "ppt" });
|
|
48
|
-
}
|
|
49
|
-
return pages;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* slide 依赖事件回溯 (收到广播事件) 来进行同步进度,每次 `renderSlide()` 等操作都不会实际触发更改,
|
|
54
|
-
* 而是发出一条广播事件,等收到事件后,使用 `slide.emit(SLIDE_EVENTS.syncReceive)` 来实际触发。
|
|
55
|
-
*
|
|
56
|
-
* controller 要保证每个事件都正确反馈给 slide。
|
|
57
|
-
*/
|
|
58
|
-
export class SlideController {
|
|
59
|
-
constructor(
|
|
60
|
-
public readonly slide: Slide,
|
|
61
|
-
readonly onPageChanged: (page: number) => void,
|
|
62
|
-
readonly onTransitionStart: () => void,
|
|
63
|
-
readonly onTransitionEnd: () => void,
|
|
64
|
-
readonly onDispatchSyncEvent: (event: SyncEvent) => void,
|
|
65
|
-
readonly onStateChange: (state: SlideState) => void,
|
|
66
|
-
private readonly initialState: SlideState | null,
|
|
67
|
-
private readonly initialPage: number
|
|
68
|
-
) {
|
|
69
|
-
slide.on(SLIDE_EVENTS.slideChange, this.resetTargetingPage);
|
|
70
|
-
slide.on(SLIDE_EVENTS.slideChange, onPageChanged);
|
|
71
|
-
|
|
72
|
-
slide.on(SLIDE_EVENTS.renderStart, onTransitionStart);
|
|
73
|
-
slide.on(SLIDE_EVENTS.renderEnd, onTransitionEnd);
|
|
74
|
-
// slide.on(SLIDE_EVENTS.animateStart, onTransitionStart);
|
|
75
|
-
// slide.on(SLIDE_EVENTS.animateEnd, onTransitionEnd);
|
|
76
|
-
slide.on(SLIDE_EVENTS.mainSeqStepStart, onTransitionStart);
|
|
77
|
-
slide.on(SLIDE_EVENTS.mainSeqStepEnd, onTransitionEnd);
|
|
78
|
-
|
|
79
|
-
slide.on(SLIDE_EVENTS.syncDispatch, onDispatchSyncEvent);
|
|
80
|
-
|
|
81
|
-
slide.on(SLIDE_EVENTS.renderError, this.onRenderError);
|
|
82
|
-
slide.on(SLIDE_EVENTS.renderError, onTransitionEnd);
|
|
83
|
-
|
|
84
|
-
slide.on(SLIDE_EVENTS.stateChange, onStateChange);
|
|
85
|
-
|
|
86
|
-
this.pollReadyState();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
private resolveReady!: (slideController: this) => void;
|
|
90
|
-
private reject!: (error: Error) => void;
|
|
91
|
-
|
|
92
|
-
readonly ready = new Promise<this>((resolve, reject) => {
|
|
93
|
-
this.resolveReady = resolve;
|
|
94
|
-
this.reject = reject;
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
private onRenderError = ({ error }: { error: Error }) => {
|
|
98
|
-
console.warn("[Slide] render error", error);
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
initialize() {
|
|
102
|
-
if (this.initialState) {
|
|
103
|
-
console.log("[Slide] init with state", this.initialState);
|
|
104
|
-
this.slide.setSlideState(this.initialState);
|
|
105
|
-
} else {
|
|
106
|
-
this.slide.renderSlide(this.initialPage);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private pollCount = 0;
|
|
111
|
-
|
|
112
|
-
private pollReadyState = () => {
|
|
113
|
-
if (this.isReady()) {
|
|
114
|
-
this.resolveReady(this);
|
|
115
|
-
} else if (this.pollCount < 60) {
|
|
116
|
-
this.pollCount++;
|
|
117
|
-
setTimeout(this.pollReadyState, 500);
|
|
118
|
-
} else {
|
|
119
|
-
this.reject(new Error("slide init time out (30s)"));
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
receiveSyncEvent(event: SyncEvent) {
|
|
124
|
-
this.slide.emit(SLIDE_EVENTS.syncReceive, event);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
setState(state: SlideState) {
|
|
128
|
-
this.slide.setSlideState(state);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
isReady() {
|
|
132
|
-
return this.slide.slideCount > 0;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
private targetingPage = -1;
|
|
136
|
-
|
|
137
|
-
private resetTargetingPage = () => {
|
|
138
|
-
this.targetingPage = -1;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
jumpToPage(page: number) {
|
|
142
|
-
if (!this.isReady()) return;
|
|
143
|
-
page = clamp(page, 1, this.slide.slideCount);
|
|
144
|
-
if (page === this.targetingPage) return;
|
|
145
|
-
this.targetingPage = page;
|
|
146
|
-
this.slide.renderSlide(page);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
destroy() {
|
|
150
|
-
this.slide.destroy();
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function createSlideController(
|
|
155
|
-
anchor: HTMLDivElement,
|
|
156
|
-
taskId: string,
|
|
157
|
-
url: string,
|
|
158
|
-
controller: boolean,
|
|
159
|
-
initialState: Slide["slideState"] | null,
|
|
160
|
-
initialPage: number,
|
|
161
|
-
onPageChanged: (page: number) => void,
|
|
162
|
-
onTransitionStart: () => void,
|
|
163
|
-
onTransitionEnd: () => void,
|
|
164
|
-
onDispatchSyncEvent: (event: SyncEvent) => void,
|
|
165
|
-
onStateChange: (state: Slide["slideState"]) => void,
|
|
166
|
-
timestamp: () => number,
|
|
167
|
-
_fixElectron: boolean, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
168
|
-
resolution?: number
|
|
169
|
-
) {
|
|
170
|
-
const slide = new Slide({
|
|
171
|
-
anchor,
|
|
172
|
-
interactive: true,
|
|
173
|
-
mode: "interactive",
|
|
174
|
-
resize: true,
|
|
175
|
-
controller,
|
|
176
|
-
renderOptions: {
|
|
177
|
-
minFPS: 25,
|
|
178
|
-
maxFPS: 30,
|
|
179
|
-
autoFPS: true,
|
|
180
|
-
autoResolution: true,
|
|
181
|
-
resolution,
|
|
182
|
-
},
|
|
183
|
-
timestamp,
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
if (import.meta.env.DEV) {
|
|
187
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
188
|
-
(window as any).slide = slide;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
slide.setResource(taskId, url);
|
|
192
|
-
|
|
193
|
-
return new SlideController(
|
|
194
|
-
slide,
|
|
195
|
-
onPageChanged,
|
|
196
|
-
onTransitionStart,
|
|
197
|
-
onTransitionEnd,
|
|
198
|
-
onDispatchSyncEvent,
|
|
199
|
-
onStateChange,
|
|
200
|
-
initialState,
|
|
201
|
-
initialPage
|
|
202
|
-
);
|
|
203
|
-
}
|
package/tsconfig.json
DELETED
package/vite.config.ts
DELETED