@netless/app-slide 0.2.32 → 0.2.33

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 CHANGED
@@ -1,20 +1,974 @@
1
- import type { NetlessApp } from "@netless/window-manager";
2
- import type { ISlideConfig } from "@netless/slide";
3
- import type { Attributes, MagixEvents } from "./typings";
4
- import type { AddHooks, FreezableSlide } from "./utils/freezer";
5
- import { Slide } from "@netless/slide";
6
- import { DefaultUrl, SlideController } from "./SlideController";
7
- import { SlideDocsViewer } from "./SlideDocsViewer";
8
- import { apps, FreezerLength, addHooks } from "./utils/freezer";
9
- export type { PreviewParams } from "./SlidePreviewer";
10
- export { SlidePreviewer, default as previewSlide } from "./SlidePreviewer";
11
- export type { Attributes, AddHooks, FreezableSlide };
12
- export { Slide };
13
- export declare const usePlugin: (plugin: any) => any;
14
- export declare const version: string;
15
- export { DefaultUrl, apps, FreezerLength, addHooks };
16
- export { setFreezerLength, getFreezerLength, onCreated, onDestroyed } from "./utils/freezer";
17
- export interface AppOptions extends Pick<ISlideConfig, "rtcAudio" | "useLocalCache" | "resourceTimeout" | "loaderDelegate" | "navigatorDelegate" | "fixedFrameSize" | "logger"> {
1
+ import { ReadonlyTeleBox, RegisterParams, AppContext, View, NetlessApp } from '@netless/window-manager';
2
+ import { VolumeAdjuster, SlideError } from '@netless/ppt-player';
3
+ import { IPlugin } from '@netless/plugin-system';
4
+
5
+ interface ILoaderDelegate {
6
+ /**
7
+ * 加载 json 资源, 需返回 json 文本
8
+ * @param url 原始资源地址
9
+ */
10
+ loadJson(url: string): Promise<string>;
11
+ /**
12
+ * 加载图片资源, 需返回 Blob 对象
13
+ * @param url 原始资源地址
14
+ */
15
+ loadImage(url: string): Promise<Blob>;
16
+ /**
17
+ * 媒体文件重定向, mp3 mp4 资源会调用这个代理函数, 需返回重定向后的 url
18
+ * @param url 原始资源地址
19
+ */
20
+ redirectMedia(url: string): string;
21
+ }
22
+ interface RtcAudio {
23
+ /**
24
+ * 开始播放音频.
25
+ */
26
+ play(): void;
27
+ /**
28
+ * 暂停音频播放, 且音频当前播放时间不变
29
+ */
30
+ pause(): void;
31
+ /**
32
+ * 当音频对象不再使用时候被调用
33
+ */
34
+ destroy(): void;
35
+ /**
36
+ * 设置音量, 参数值范围 0 ~ 1
37
+ */
38
+ volume(value: number): void;
39
+ /**
40
+ * 获取音频当前播放时间, 单位为:秒
41
+ */
42
+ get currentTime(): number;
43
+ /**
44
+ * 设置音频当前播放时间, 单位为:秒。需注意, 无论音频是否正在播放, 都需要确保能设置成功。
45
+ * 如果音频暂停状态下, 设置此值, 那么需保证, 下次恢复播放是从此值位置开始播放。
46
+ */
47
+ set currentTime(time: number);
48
+ /**
49
+ * 返回音频是否暂停状态
50
+ */
51
+ get isPaused(): boolean;
52
+ /**
53
+ * 返回音频时长
54
+ */
55
+ get duration(): number;
56
+ /**
57
+ * 当音频加载完成时触发, 例如: 音频 meta 数据加载完成, 这时候知道了音频实际时长, 就需要触发此事件, 需要保证此事件触发时,
58
+ * 能通过 duration 属性获取到更新后的音频时长
59
+ * @param event
60
+ * @param listener
61
+ */
62
+ on(event: "load", listener: () => void): this;
63
+ /**
64
+ * 当音频暂停时候触发
65
+ * @param event
66
+ * @param listener
67
+ */
68
+ on(event: "pause", listener: () => void): this;
69
+ /**
70
+ * 当音频开始播放时候触发
71
+ * @param event
72
+ * @param listener
73
+ */
74
+ on(event: "play", listener: () => void): this;
75
+ /**
76
+ * 移除参数指定事件的所有监听器
77
+ */
78
+ removeAllListeners(event: string): void;
79
+ }
80
+ interface RtcAudioClazz {
81
+ /**
82
+ * 创建 rtc 播放器, url 为音频地址
83
+ * @param url
84
+ */
85
+ new (url: string): RtcAudio;
86
+ }
87
+ interface ILogger$1 {
88
+ info?(msg: string): void;
89
+ error?(msg: string): void;
90
+ warn?(msg: string): void;
91
+ }
92
+ declare const SLIDE_EVENTS: {
93
+ /** 同步事件派发 */
94
+ readonly syncDispatch: "syncDispatch";
95
+ /** 同步事件接收 */
96
+ readonly syncReceive: "syncReceive";
97
+ /**
98
+ * 同步模式下才会触发这个事件, 指示同步消息滞后, 需要全量同步
99
+ */
100
+ readonly syncEventLag: "syncEventLag";
101
+ /** 当前 slide 渲染开始触发 */
102
+ readonly renderStart: "renderStart";
103
+ /** 当前 slide 渲染完毕触发 */
104
+ readonly renderEnd: "renderEnd";
105
+ /** 当前 slide 渲染出错触发 */
106
+ readonly renderError: "renderError";
107
+ /** slide 页码变化时触发 */
108
+ readonly slideChange: "slideChange";
109
+ /** 主序列动画开始时触发 */
110
+ readonly mainSeqStepStart: "mainSeqStepStart";
111
+ /** 主序列动画结束时触发 */
112
+ readonly mainSeqStepEnd: "mainSeqStepEnd";
113
+ /**
114
+ * 任意动画开始时触发
115
+ */
116
+ readonly animateStart: "animateStart";
117
+ /**
118
+ * 任意动画结束时触发
119
+ */
120
+ readonly animateEnd: "animateEnd";
121
+ /** slide 状态变化触发 */
122
+ readonly stateChange: "stateChange";
123
+ /** ppt 已经没有下一步动作触发 **/
124
+ readonly slideStepEnd: "slideEnd";
125
+ /** ppt 已经没有上一步动作触发 **/
126
+ readonly slideStepStart: "slideStart";
127
+ };
128
+ interface ISlideRenderOptions {
129
+ /** 预期最低渲染 fps, 默认 40 */
130
+ minFPS?: number;
131
+ /** 预期最高渲染 fps, 默认 50 */
132
+ maxFPS?: number;
133
+ /** 渲染分辨倍率, 整数, 默认为 window.devicePixelRatio */
134
+ resolution?: number;
135
+ /** 是否根据 fps, 自动调整分辨率, 默认为 false */
136
+ autoResolution?: boolean;
137
+ /** 是否自动降低渲染 fps */
138
+ autoFPS?: boolean;
139
+ /** 播放切页动画时候的背景颜色, 接受 css 颜色字符串或者 16进制颜色值("#ffffff",0xffffff) */
140
+ transactionBgColor?: string | number;
141
+ /**
142
+ * 用于设置最高显示分辨率。此值不仅影响 canvas 渲染分辨率, 同时也影响纹理质量,
143
+ * 在低端设备, 降低此值能极大改善内存占用及图片黑屏现象.
144
+ * [1] 最低 960 * 540, 小于 1 按 1 计算;
145
+ * [2] 普通 1280 * 720; --- 移动端默认设置.
146
+ * [3] 高清 1920 * 1080;
147
+ * [4] 3K 3200 × 1800, 大于 4 按 4 计算; --- pc 端默认设置.
148
+ * 默认情况下, pc 设备 3K, 移动设备 720P
149
+ */
150
+ maxResolutionLevel?: number;
151
+ /**
152
+ * 是否强制使用 2d 渲染, 强制使用 2d 渲染会丢失部分 3d、滤镜、特效
153
+ */
154
+ forceCanvas?: boolean;
155
+ /**
156
+ * @deprecated 当前版本已经修复花屏问题, 无需开启这个参数
157
+ * 是否开启 NVIDIA 显卡检测, windows 11 配合 NVIDIA 显卡在
158
+ * 播放部分切页动画时会花屏。
159
+ * 开启这个选项, 会自动检测是否 NVIDIA, 如果是 NVIDIA 显卡则
160
+ * 使用不同的逻辑播放切页动画, 不会花屏, 但是切页响应会慢 200 ~ 1000 ms
161
+ */
162
+ enableNvidiaDetect?: boolean;
163
+ }
164
+ interface INavigatorDelegate {
165
+ gotoPage(index: number): void;
166
+ }
167
+ interface ISlideConfig {
168
+ /** canvas 挂载点 */
169
+ anchor: HTMLDivElement;
170
+ /** 是否可互动 */
171
+ interactive: boolean;
172
+ /** 渲染选项, 可选 */
173
+ renderOptions?: ISlideRenderOptions;
174
+ /** 是否展示控制栏和stats */
175
+ controller?: boolean;
176
+ /** 是否根据窗口大小自动调整分辨率 */
177
+ resize?: boolean;
178
+ /** 获取房间时间 */
179
+ timestamp?: () => number;
180
+ /**
181
+ * 运行模式
182
+ *
183
+ * "interactive" 互动模式, 所有人都可以操作 ppt
184
+ * "sync" 同步模式, 只有一个人能操作 ppt
185
+ * "local" 本地模式, 不会触发任意同步事件
186
+ */
187
+ mode: "interactive" | "sync" | "local";
188
+ /**
189
+ * 是否启用全局点击, 开启后, 只要点击到 ppt 视口范围,
190
+ * 并且没有触发 ppt 内部可互动元素, 就会触发下一步动作.
191
+ * 默认为 false
192
+ */
193
+ enableGlobalClick?: boolean;
194
+ /**
195
+ * 提供的音频播放器类, 用于 rtc 混音
196
+ */
197
+ rtcAudio?: RtcAudioClazz;
198
+ /**
199
+ * 提供 logger 对象, 用以记录运行日志
200
+ */
201
+ logger?: ILogger$1;
202
+ /**
203
+ * 是否启用本地缓存,启用后会将 ppt 远程资源缓存在 indexDB 中
204
+ * 默认为 true
205
+ */
206
+ useLocalCache?: boolean;
207
+ /**
208
+ * 资源加载超时时间, 默认 15 秒
209
+ */
210
+ resourceTimeout?: number;
211
+ /**
212
+ * 远程资源代理, 详细使用参考 README
213
+ */
214
+ loaderDelegate?: ILoaderDelegate;
215
+ /**
216
+ * ppt 页码导航代理, 添加此属性后, ppt 内部动作引起的页码变换, 全部走代理逻辑.
217
+ */
218
+ navigatorDelegate?: INavigatorDelegate;
219
+ /**
220
+ * 设置 ppt 固定高宽, 设置后 ppt 不会跟随父元素的大小自动变化
221
+ * 如果有缩放需求,需要调用 updateFixedFrameSize 方法
222
+ * width 及 height 属性单位为 px
223
+ */
224
+ fixedFrameSize?: {
225
+ width: number;
226
+ height: number;
227
+ };
228
+ /**
229
+ * 客户端 id, 在同步及互动场景下, 需要能区分每个不同的客户端。对于收到同步消息的一端来说, 需要用这个
230
+ * clientId 区分是不是自己发出的消息又被自己接收了。
231
+ * 如果同步及互动场景下, 没有给这个值会造成某些情况下的状态不同步,已知的场景有:
232
+ * 1. ppt 某一页有自动动画, 动画过程中进行的下一步动作, 在其他客户端可能表现为下一页(即翻页)
233
+ */
234
+ clientId?: string;
235
+ }
236
+ interface MediaState {
237
+ type: "pause" | "play";
238
+ time: number;
239
+ frozenTime?: number;
240
+ fullscreen?: boolean;
241
+ }
242
+ interface TimeNodeSeqState {
243
+ step: number;
244
+ state: "idle" | "running" | "end" | null;
245
+ }
246
+ interface ISlideState {
247
+ taskId: string;
248
+ url: string;
249
+ currentSlideIndex: number;
250
+ mainSeqStep: number;
251
+ mainSeqState: "idle" | "running" | "end" | null;
252
+ mediaState: {
253
+ [key: string]: MediaState;
254
+ };
255
+ interactiveSeqState: {
256
+ [key: string]: TimeNodeSeqState;
257
+ };
258
+ }
259
+ declare type SyncEvent = SyncInteractiveAnimEvent | SyncPrevStepEvent | SyncNextStepEvent | SyncRenderSlideEvent | SyncSetResourceEvent | SyncMediaPlayEvent | SyncMediaPauseEvent | SyncMediaSeekEvent | SyncMediaFullscreenEvent;
260
+ interface BasicSyncEvent {
261
+ slideIndex: number;
262
+ uuid?: string;
263
+ incrId?: number;
264
+ clientId?: string;
265
+ }
266
+ interface SyncMediaPlayEvent extends BasicSyncEvent {
267
+ type: "mediaPlay";
268
+ id: string;
269
+ state: MediaState;
270
+ }
271
+ interface SyncMediaPauseEvent extends BasicSyncEvent {
272
+ type: "mediaPause";
273
+ id: string;
274
+ state: MediaState;
275
+ }
276
+ interface SyncMediaSeekEvent extends BasicSyncEvent {
277
+ type: "mediaSeek";
278
+ id: string;
279
+ time: number;
280
+ state: MediaState;
281
+ }
282
+ interface SyncMediaFullscreenEvent extends BasicSyncEvent {
283
+ type: "mediaFullscreen";
284
+ targetId: string;
285
+ state: boolean;
286
+ }
287
+ interface SyncInteractiveAnimEvent extends BasicSyncEvent {
288
+ type: "interactiveAnim";
289
+ action: string;
290
+ seqId: string;
291
+ }
292
+ interface SyncPrevStepEvent extends BasicSyncEvent {
293
+ type: "prevStep";
294
+ next: number;
295
+ }
296
+ interface SyncNextStepEvent extends BasicSyncEvent {
297
+ type: "nextStep";
298
+ next: number;
299
+ }
300
+ interface SyncRenderSlideEvent extends BasicSyncEvent {
301
+ type: "renderSlide";
302
+ index: number;
303
+ isForward: boolean;
304
+ }
305
+ interface SyncSetResourceEvent extends BasicSyncEvent {
306
+ type: "setResource";
307
+ taskId: string;
308
+ url: string;
309
+ }
310
+ interface SlideEventEmitter {
311
+ removeAllListeners(): this;
312
+ removeListener(event: keyof typeof SLIDE_EVENTS, fn?: any): this;
313
+ emit(event: typeof SLIDE_EVENTS.renderStart, index: number): boolean;
314
+ on(event: typeof SLIDE_EVENTS.renderStart, listener: (index: number) => void): this;
315
+ emit(event: typeof SLIDE_EVENTS.renderEnd, index: number): boolean;
316
+ on(event: typeof SLIDE_EVENTS.renderEnd, listener: (index: number) => void): this;
317
+ emit(event: typeof SLIDE_EVENTS.slideChange, nextSlideIndex: number): boolean;
318
+ on(event: typeof SLIDE_EVENTS.slideChange, listener: (nextSlideIndex: number) => void): this;
319
+ emit(event: typeof SLIDE_EVENTS.syncDispatch, args: SyncEvent): boolean;
320
+ on(event: typeof SLIDE_EVENTS.syncDispatch, listener: (event: SyncEvent) => void): this;
321
+ emit(event: typeof SLIDE_EVENTS.syncReceive, args: SyncEvent): boolean;
322
+ on(event: typeof SLIDE_EVENTS.syncReceive, listener: (event: SyncEvent) => void): this;
323
+ emit(event: typeof SLIDE_EVENTS.renderError, args: {
324
+ error: SlideError;
325
+ index: number;
326
+ }): boolean;
327
+ on(event: typeof SLIDE_EVENTS.renderError, listener: (args: {
328
+ error: SlideError;
329
+ index: number;
330
+ }) => void): this;
331
+ emit(event: typeof SLIDE_EVENTS.animateStart): boolean;
332
+ on(event: typeof SLIDE_EVENTS.animateStart, listener: () => void): this;
333
+ emit(event: typeof SLIDE_EVENTS.animateEnd): boolean;
334
+ on(event: typeof SLIDE_EVENTS.animateEnd, listener: () => void): this;
335
+ emit(event: typeof SLIDE_EVENTS.mainSeqStepStart, index: number): boolean;
336
+ on(event: typeof SLIDE_EVENTS.mainSeqStepStart, listener: (index: number) => void): this;
337
+ emit(event: typeof SLIDE_EVENTS.mainSeqStepEnd, index: number): boolean;
338
+ on(event: typeof SLIDE_EVENTS.mainSeqStepEnd, listener: (index: number) => void): this;
339
+ emit(event: typeof SLIDE_EVENTS.stateChange, state: ISlideState): boolean;
340
+ on(event: typeof SLIDE_EVENTS.stateChange, listener: (state: ISlideState) => void): this;
341
+ emit(event: typeof SLIDE_EVENTS.syncEventLag): boolean;
342
+ on(event: typeof SLIDE_EVENTS.syncEventLag, listener: () => void): this;
343
+ emit(event: typeof SLIDE_EVENTS.slideStepEnd): boolean;
344
+ on(event: typeof SLIDE_EVENTS.slideStepEnd, listener: () => void): this;
345
+ emit(event: typeof SLIDE_EVENTS.slideStepStart): boolean;
346
+ on(event: typeof SLIDE_EVENTS.slideStepStart, listener: () => void): this;
347
+ }
348
+ declare const Slide_base: new () => SlideEventEmitter;
349
+ declare class Slide extends Slide_base {
350
+ static instances: Slide[];
351
+ static _tempFrozenIds: string[];
352
+ static _tempLog: string;
353
+ static _tempLogIndex: number;
354
+ static flushLog(force?: boolean): Promise<void>;
355
+ static remoteLogAddress: string | null;
356
+ static stopRemoteLog(): void;
357
+ static startRemoteLog(address: string): Promise<void>;
358
+ static appendLogString(logStr: string): void;
359
+ static usePlugin: (plugin: IPlugin) => void;
360
+ /**
361
+ * 设置全局音量, 对所有 Slide 实例都生效
362
+ */
363
+ static volumeAdjuster: VolumeAdjuster;
364
+ private iosResetCache;
365
+ private iosNewPlayer?;
366
+ private needClearCacheImage;
367
+ private version?;
368
+ private __slideState;
369
+ private userInputTime;
370
+ private isSyncingSlideState;
371
+ private frozenTaskManager;
372
+ private randomId;
373
+ private resize;
374
+ private isAnimating;
375
+ private renderingTaskManager;
376
+ private isLoading;
377
+ private interactive;
378
+ private anchor;
379
+ private player?;
380
+ private renderingIndex;
381
+ private frameWidth;
382
+ private frameHeight;
383
+ private frame;
384
+ private canvasContainer;
385
+ private medianController;
386
+ private frameResizeObserver;
387
+ private timestamp;
388
+ private mode;
389
+ private enableGlobalClick;
390
+ private lastEmitedState;
391
+ private syncQueue;
392
+ private playerController;
393
+ private lock;
394
+ private isInitResized;
395
+ private cacheImage;
396
+ private config;
397
+ private isTouchStart;
398
+ private touchStartId;
399
+ private taskId;
400
+ private volumeAdjuster;
401
+ private designWidth;
402
+ private designHeight;
403
+ private _slideCount;
404
+ private logger;
405
+ private _dispatchIncrId;
406
+ private _receiveIncrId;
407
+ private get dispatchIncrId();
408
+ constructor(initConfig: ISlideConfig);
409
+ private _updateVolumeByStaticAdjuster;
410
+ private recoverHandler;
411
+ private reportError;
412
+ initSlideConfig(config: ISlideConfig): ISlideConfig;
413
+ static handleFrozenAllSlide: () => void;
414
+ static handleReleaseAllSlide: () => void;
415
+ static handleLogReport: (sessionId: string) => Promise<void>;
416
+ static handleLogDownload: () => Promise<void>;
417
+ private initPlayer;
418
+ private userInputHandle;
419
+ private handleViewClick;
420
+ private handleViewTouchStart;
421
+ private handleViewTouchEnd;
422
+ private createController;
423
+ private handleSlideRef;
424
+ private setMedianControllerAttribute;
425
+ private frameResizeHandler;
426
+ /**
427
+ * 更新 ppt 固定高宽, 此方法只有在设置了 fixedFrameSize 配置项的情况下才会生效
428
+ * @param width 需要更新的宽度值, 单位 px
429
+ * @param height 需要更新的高度值, 单位 px
430
+ */
431
+ updateFixedFrameSize(width: number, height: number, callback?: () => void): void;
432
+ private resizeView;
433
+ private receiveSyncHandler;
434
+ /**
435
+ * 设置整个 slide 的状态, slide 会以传入的状态更新画面.
436
+ * 供整体同步时候调用.
437
+ * @param state ISlideState
438
+ */
439
+ setSlideState(state: Partial<ISlideState>): Promise<void>;
440
+ private initInteractiveSeq;
441
+ private initMedia;
442
+ /**
443
+ * 返回 slide 总页数
444
+ */
445
+ get slideCount(): number;
446
+ /**
447
+ * 获取 slide 设计高宽, 单位为 px, 返回数组形式为 [width, height]
448
+ * 可以在 renderSlide 之前调用
449
+ */
450
+ getSizeAsync(): Promise<[number, number]>;
451
+ /**
452
+ * 获取 slide 总页数, 可以在 renderSlide 之前调用
453
+ */
454
+ getSlideCountAsync(): Promise<number>;
455
+ /**
456
+ * 整个 slide 的状态, 将获取的值传递给另一个客户端, 并调用 setSlideState
457
+ * 可以完成整体同步. 只读属性.
458
+ * @readonly
459
+ */
460
+ get slideState(): ISlideState;
461
+ /**
462
+ * 主序列动画步数, 只读属性
463
+ * @readonly
464
+ */
465
+ get mainSeqLength(): number;
466
+ /**
467
+ * 主序列动画, 当前步, 只读属性
468
+ * @readonly
469
+ */
470
+ get mainSeqStep(): number;
471
+ /**
472
+ * 主序列动画, 当前状态, 只读属性
473
+ * "idle": 动画尚未运行
474
+ * "running": 动画运行中
475
+ * "end": 动画已经结束
476
+ * null: 当前 Slide 没有主序列动画
477
+ * @readonly
478
+ */
479
+ get mainSeqState(): "idle" | "running" | "end" | null;
480
+ /**
481
+ * 实时渲染属性, 只读属性.
482
+ * @readonly
483
+ */
484
+ get renderOptions(): ISlideRenderOptions | null;
485
+ /**
486
+ * drawCall 次数, 即每帧调用 gpu drawElements 次数, 只读属性.
487
+ * @readonly
488
+ */
489
+ get drawCall(): number;
490
+ /**
491
+ * 渲染 fps, 只读属性.
492
+ * @readonly
493
+ */
494
+ get renderFps(): number;
495
+ /**
496
+ * js 运行时 fps, 只读属性.
497
+ * @readonly
498
+ */
499
+ get runtimeFps(): number;
500
+ /**
501
+ * 渲染 Slide 的 canvas 元素.
502
+ * @readonly
503
+ */
504
+ get view(): HTMLCanvasElement | null;
505
+ /**
506
+ * Slide 宽度. 此宽度为设计宽度, 由 ppt 决定. 只读属性.
507
+ * @readonly
508
+ */
509
+ get width(): number;
510
+ /**
511
+ * Slide 高度. 此高度为设计高度, 由 ppt 决定. 只读属性.
512
+ * @readonly
513
+ */
514
+ get height(): number;
515
+ /**
516
+ * 更新渲染属性
517
+ * @param renderOptions
518
+ */
519
+ updateRenderOption(renderOptions: ISlideRenderOptions): void;
520
+ /**
521
+ * 设置 ppt 转换后的资源
522
+ * @param taskId 转换任务 id
523
+ * @param url 资源 url 前缀
524
+ */
525
+ setResource(taskId: string, url: string): void;
526
+ private _renderSlide;
527
+ private handlePrevSlide;
528
+ private handleNextSlide;
529
+ private handleGotoSlide;
530
+ /**
531
+ * 渲染 index 参数对应的 ppt 页.
532
+ * @param index 要显示的页码, 从 1 开始
533
+ */
534
+ renderSlide(index: number, isForward?: boolean): void;
535
+ private needCreateNewPlayer;
536
+ private poseRenderSlide;
537
+ /**
538
+ * 直接渲染 index 指定的页码, 不论当前是 sync 还是 interactive 模式.
539
+ * 即调用此方法不会触发 syncDispatch 事件
540
+ * @param index 要渲染的页码
541
+ * @param isForward 是否向前翻页, 影响切页动画时正放还是倒放
542
+ */
543
+ doRenderSlide(index: number, isForward?: boolean): Promise<void>;
544
+ getSnapshot(): string | null;
545
+ /**
546
+ * 执行下一个主序列动画
547
+ */
548
+ nextStep(): void;
549
+ private doNextStep;
550
+ /**
551
+ * 执行上一个主序列动画
552
+ */
553
+ prevStep(): void;
554
+ private doPrevStep;
555
+ private isSlideStateReady;
556
+ private emitStateChange;
557
+ private emitSyncDispatch;
558
+ /**
559
+ * 重置主序列动画
560
+ * @param index 将要重置到的步数
561
+ * @param status 将要重置到的状态, "start" 重置到动画开始, "end" 重置到动画结束
562
+ */
563
+ setMainSeqStep(index: number, status: "start" | "end"): void;
564
+ /**
565
+ * 设置是否可以互动
566
+ * @param val boolean
567
+ */
568
+ setInteractive(val: boolean): void;
569
+ /**
570
+ * 暂停播放, 非同步操作
571
+ */
572
+ pause(): void;
573
+ /**
574
+ * 恢复播放状态, 非同步操作
575
+ */
576
+ resume(): void;
577
+ private _doFrozen;
578
+ /**
579
+ * 进入冻结状态, 将 ppt 画面缓存为一张图片, 并释放 webgl 上下文
580
+ */
581
+ frozen(): void;
582
+ private _doRelease;
583
+ /**
584
+ * 从冻结状态恢复
585
+ */
586
+ release(): void;
587
+ private _doDestroy;
588
+ private waitLoadEnd;
589
+ preload(index: number): Promise<void>;
590
+ /**
591
+ * 销毁方法.
592
+ */
593
+ destroy(): void;
594
+ /**
595
+ * 销毁当前 Slide 实例的本地缓存, 需要在 destroy 之前调用。
596
+ */
597
+ clearSlideCache(): void;
598
+ /**
599
+ * 返回 ppt 是否存在下一步动作
600
+ */
601
+ hasNextStep(): boolean;
602
+ /**
603
+ * 返回 ppt 是否存在上一步动作
604
+ */
605
+ hasPrevStep(): boolean;
606
+ /**
607
+ * 截取当前状态的截图
608
+ * @return 图片 dataUrl, 如果失败则返回 null
609
+ */
610
+ snapshot(): Promise<string | null>;
611
+ /**
612
+ * 截取动画最后一步状态的截图
613
+ * @param index 要截取的页码
614
+ * @return 图片 dataUrl, 如果失败则返回 null
615
+ */
616
+ snapshotWithTimingEnd(index: number): Promise<string | null>;
617
+ /**
618
+ * 设置此 Slide 实例全局音量, 非同步操作, 只会修改本地音量,不会触发同步事件
619
+ * @param v 数值范围 0 ~ 1
620
+ */
621
+ updateGlobalVolume(v: number): void;
622
+ /**
623
+ * 获取此 Slide 实例全局音量
624
+ */
625
+ getGlobalVolume(): number;
626
+ /**
627
+ * 销毁历史所有本地缓存
628
+ */
629
+ static clearLocalCache(): void;
630
+ /**
631
+ * @deprecated 该 api 已经失效, 请用 slideInstance.clearSlideCache 和 Slide.clearLocalCache 替代
632
+ */
633
+ static disposeLocalCache(): void;
634
+ }
635
+
636
+ declare type SlideState = Slide["slideState"];
637
+ interface Attributes {
638
+ /** convert task id */
639
+ taskId: string;
640
+ /** base url of converted resources */
641
+ url: string;
642
+ /** internal state of slide, do not change */
643
+ state: SlideState | null;
644
+ }
645
+ declare type MagixPayload = {
646
+ type: typeof SLIDE_EVENTS.syncDispatch;
647
+ payload: SyncEvent;
648
+ };
649
+ declare type MagixEvents = {
650
+ [SLIDE_EVENTS.syncDispatch]: MagixPayload;
651
+ };
652
+
653
+ interface FreezableSlide {
654
+ freeze: () => void;
655
+ unfreeze: () => void;
656
+ }
657
+ declare let FreezerLength: number;
658
+ declare function getFreezerLength(): number;
659
+ /** @param length - must be >= 1, default is 2 */
660
+ declare function setFreezerLength(length: number): void;
661
+ declare const apps: {
662
+ map: Map<string, FreezableSlide>;
663
+ boxes: Map<string, ReadonlyTeleBox>;
664
+ queue: string[];
665
+ validateQueue(): void;
666
+ set(appId: string, slide: FreezableSlide, box: ReadonlyTeleBox): void;
667
+ delete(appId: string): void;
668
+ focus(appId: string): void;
669
+ };
670
+ declare function onCreated(callback: (appId: string) => void): () => boolean;
671
+ declare function onDestroyed(callback: (appId: string) => void): () => boolean;
672
+ declare type AddHooks = NonNullable<RegisterParams["addHooks"]>;
673
+ /**
674
+ * Put this function in your register code:
675
+ * `WindowManager.register({ kind: 'Slide', src: SlideApp, addHooks })`
676
+ * So that it will automatically freeze the app when it is not in focus.
677
+ */
678
+ declare const addHooks: AddHooks;
679
+
680
+ declare type SideEffectDisposer = () => any;
681
+ declare class SideEffectManager {
682
+ /**
683
+ * Add a disposer directly.
684
+ * @param disposer a disposer or a list of disposers
685
+ * @param disposerID Optional id for the disposer
686
+ * @returns disposerID
687
+ */
688
+ addDisposer(disposer: SideEffectDisposer | SideEffectDisposer[], disposerID?: string): string;
689
+ /**
690
+ * @alias addDisposer
691
+ * Add a disposer directly.
692
+ * @param disposer a disposer or a list of disposers
693
+ * @param disposerID Optional id for the disposer
694
+ * @returns disposerID
695
+ */
696
+ push: (disposer: SideEffectDisposer | SideEffectDisposer[], disposerID?: string) => string;
697
+ /**
698
+ * Add a side effect.
699
+ * @param executor Executes side effect. Return a disposer or a list of disposers. Returns null or false to ignore.
700
+ * @param disposerID Optional id for the disposer
701
+ * @returns disposerID
702
+ */
703
+ add(executor: () => SideEffectDisposer | SideEffectDisposer[] | null | false, disposerID?: string): string;
704
+ /**
705
+ * Sugar for addEventListener.
706
+ * @param el
707
+ * @param type
708
+ * @param listener
709
+ * @param options
710
+ * @param disposerID Optional id for the disposer
711
+ * @returns disposerID
712
+ */
713
+ addEventListener<K extends keyof WindowEventMap>(el: Window, type: K, listener: (this: Window, ev: WindowEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions, disposerID?: string): string;
714
+ addEventListener<K extends keyof DocumentEventMap>(el: Document, type: K, listener: (this: Document, ev: DocumentEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions, disposerID?: string): string;
715
+ addEventListener<K extends keyof HTMLElementEventMap>(el: HTMLElement, type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions, disposerID?: string): string;
716
+ addEventListener<K extends keyof MediaQueryListEventMap>(el: MediaQueryList, type: K, listener: (this: HTMLElement, ev: MediaQueryListEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions, disposerID?: string): string;
717
+ /**
718
+ * Sugar for setTimeout.
719
+ * @param handler
720
+ * @param timeout
721
+ * @param disposerID Optional id for the disposer
722
+ * @returns disposerID
723
+ */
724
+ setTimeout(handler: () => void, timeout: number, disposerID?: string): string;
725
+ /**
726
+ * Sugar for setInterval.
727
+ * @param handler
728
+ * @param timeout
729
+ * @param disposerID Optional id for the disposer
730
+ * @returns disposerID
731
+ */
732
+ setInterval(handler: () => void, timeout: number, disposerID?: string): string;
733
+ /**
734
+ * Remove but not run the disposer. Do nothing if not found.
735
+ * @param disposerID
736
+ */
737
+ remove(disposerID: string): SideEffectDisposer | undefined;
738
+ /**
739
+ * Remove and run the disposer. Do nothing if not found.
740
+ * @param disposerID
741
+ */
742
+ flush(disposerID: string): void;
743
+ /**
744
+ * Remove and run all of the disposers.
745
+ */
746
+ flushAll(): void;
747
+ /**
748
+ * All disposers. Use this only when you know what you are doing.
749
+ */
750
+ readonly disposers: Map<string, SideEffectDisposer>;
751
+ genUID(): string;
752
+ }
753
+
754
+ interface DocsViewerPage {
755
+ src: string;
756
+ height: number;
757
+ width: number;
758
+ thumbnail?: string;
759
+ }
760
+ interface DocsViewerConfig {
761
+ readonly: boolean;
762
+ onNewPageIndex: (index: number) => void;
763
+ onPlay?: () => void;
764
+ }
765
+ declare class DocsViewer {
766
+ constructor({ readonly, onNewPageIndex, onPlay }: DocsViewerConfig);
767
+ protected readonly: boolean;
768
+ protected onNewPageIndex: (index: number) => void;
769
+ protected onPlay?: () => void;
770
+ private _pages;
771
+ set pages(value: DocsViewerPage[]);
772
+ get pages(): DocsViewerPage[];
773
+ $content: HTMLElement;
774
+ $preview: HTMLElement;
775
+ $previewMask: HTMLElement;
776
+ $footer: HTMLElement;
777
+ $pageNumberInput: HTMLInputElement;
778
+ $totalPage: HTMLSpanElement;
779
+ $btnPlay: HTMLButtonElement;
780
+ $btnSidebar: HTMLButtonElement;
781
+ pageIndex: number;
782
+ unmount(): void;
783
+ setReadonly(readonly: boolean): void;
784
+ destroy(): void;
785
+ setPageIndex(pageIndex: number): void;
786
+ refreshTotalPage(): void;
787
+ setSmallBox(isSmallBox: boolean): void;
788
+ render(): HTMLElement;
789
+ protected renderContent(): HTMLElement;
790
+ private previewLazyLoad?;
791
+ protected renderPreview(): HTMLElement;
792
+ private refreshPreview;
793
+ protected renderPreviewMask(): HTMLElement;
794
+ setPaused: () => void;
795
+ setPlaying: () => void;
796
+ refreshBtnSidebar(): void;
797
+ protected renderFooter(): HTMLElement;
798
+ protected renderFooterBtn(className: string, $icon: SVGElement, $iconActive?: SVGElement): HTMLButtonElement;
799
+ protected togglePreview(isShowPreview?: boolean): void;
800
+ protected wrapClassName(className: string): string;
801
+ protected namespace: string;
802
+ protected isShowPreview: boolean;
803
+ protected isSmallBox: boolean;
804
+ protected sideEffect: SideEffectManager;
805
+ }
806
+
807
+ declare const DefaultUrl = "https://convertcdn.netless.link/dynamicConvert";
808
+ interface SlideControllerOptions {
809
+ context: AppContext<Attributes, MagixEvents, AppOptions>;
810
+ anchor: HTMLDivElement;
811
+ onRenderEnd: () => void;
812
+ onPageChanged: (page: number) => void;
813
+ onTransitionStart: () => void;
814
+ onTransitionEnd: () => void;
815
+ onError: (args: {
816
+ error: Error;
817
+ index: number;
818
+ }) => void;
819
+ onRenderError?: (error: Error, pageIndex: number) => void;
820
+ showRenderError?: boolean;
821
+ }
822
+ declare class SlideController {
823
+ readonly context: SlideControllerOptions["context"];
824
+ readonly slide: Slide;
825
+ readonly showRenderError: boolean;
826
+ readonly onRenderError?: (error: Error, pageIndex: number) => void;
827
+ private readonly room?;
828
+ private readonly player?;
829
+ private readonly sideEffect;
830
+ private readonly onPageChanged;
831
+ private readonly onTransitionStart;
832
+ private readonly onTransitionEnd;
833
+ private readonly onError;
834
+ private syncStateOnceFlag;
835
+ private visible;
836
+ private savedIsFrozen;
837
+ constructor({ context, anchor, onPageChanged, onTransitionStart, onTransitionEnd, onError, onRenderError, showRenderError, }: SlideControllerOptions);
838
+ ready: boolean;
839
+ private resolveReady;
840
+ readonly readyPromise: Promise<void>;
841
+ jumpToPage(page: number): void;
842
+ private initialize;
843
+ private kickStart;
844
+ private registerEventListeners;
845
+ private onSyncDispatch;
846
+ private magixEventListener;
847
+ private syncStateOnce;
848
+ private onStateChange;
849
+ private pollCount;
850
+ private pollReadyState;
851
+ private _pageCount;
852
+ get pageCount(): number;
853
+ get page(): number;
854
+ private createSlide;
855
+ private destroyed;
856
+ destroy(): void;
857
+ timestamp: () => number;
858
+ isFrozen: boolean;
859
+ private _toFreeze;
860
+ freeze: () => void;
861
+ unfreeze: () => Promise<void>;
862
+ private onVisibilityChange;
863
+ }
864
+
865
+ declare type MountSlideOptions = Omit<SlideControllerOptions, "context" | "onPageChanged"> & {
866
+ onReady: () => void;
867
+ };
868
+ interface SlideDocsViewerConfig {
869
+ box: ReadonlyTeleBox;
870
+ view: View;
871
+ mountSlideController: (options: MountSlideOptions) => SlideController;
872
+ mountWhiteboard: (dom: HTMLDivElement) => void;
873
+ baseScenePath: string;
874
+ appId: string;
875
+ }
876
+ declare class SlideDocsViewer {
877
+ viewer: DocsViewer;
878
+ slideController: SlideController | null;
879
+ protected readonly box: ReadonlyTeleBox;
880
+ protected readonly whiteboardView: SlideDocsViewerConfig["view"];
881
+ protected readonly mountSlideController: SlideDocsViewerConfig["mountSlideController"];
882
+ protected readonly mountWhiteboard: SlideDocsViewerConfig["mountWhiteboard"];
883
+ private readonly baseScenePath;
884
+ private readonly appId;
885
+ private isViewMounted;
886
+ constructor({ box, view, mountSlideController, mountWhiteboard, baseScenePath, appId, }: SlideDocsViewerConfig);
887
+ $slide: HTMLDivElement;
888
+ $whiteboardView: HTMLDivElement;
889
+ $overlay: HTMLDivElement;
890
+ render(): void;
891
+ protected renderOverlay(): HTMLDivElement;
892
+ protected renderSlideContainer(): HTMLDivElement;
893
+ protected renderWhiteboardView(): HTMLDivElement;
894
+ mount(): this;
895
+ protected onError: ({ error, index }: {
896
+ error: Error;
897
+ index: number;
898
+ }) => void;
899
+ protected onRenderEnd: () => void;
900
+ protected refreshPages: () => void;
901
+ protected getPageIndex(page: number): number;
902
+ unmount(): this;
903
+ setReadonly(readonly: boolean): void;
904
+ destroy(): void;
905
+ toggleClickThrough(tool?: string): void;
906
+ protected scaleDocsToFit: () => void;
907
+ protected onPlay: () => void;
908
+ protected onNewPageIndex: (index: number) => void;
909
+ protected sideEffect: SideEffectManager;
910
+ protected wrapClassName(className: string): string;
911
+ protected namespace: string;
912
+ private getWhiteSnapshot;
913
+ private reportProgress;
914
+ private toPdf;
915
+ }
916
+
917
+ interface PreviewParams {
918
+ container: HTMLElement;
919
+ taskId: string;
920
+ url?: string;
921
+ debug?: boolean;
922
+ }
923
+ declare function previewSlide({ container, taskId, url, debug, }: PreviewParams): SlidePreviewer;
924
+ declare class SlidePreviewer {
925
+ readonly viewer: DocsViewer;
926
+ readonly bgColor: string;
927
+ readonly target: HTMLElement;
928
+ slide: Slide | null;
929
+ debug: boolean;
930
+ $slide: HTMLDivElement;
931
+ private readonly sideEffect;
932
+ ready: boolean;
933
+ private resolveReady;
934
+ readonly readyPromise: Promise<void>;
935
+ constructor(config: {
936
+ target: HTMLElement;
937
+ });
938
+ render(): void;
939
+ /**
940
+ * In case you have a different window -- for example, in electron.
941
+ * Use this method to re-register hotkeys.
942
+ *
943
+ * @example
944
+ * previewer.registerHotKeys(windowLike)
945
+ */
946
+ registerHotKeys(windowLike: Window): void;
947
+ private hotkeyListener;
948
+ mount(taskId: string, url: string): void;
949
+ protected renderStyle(): HTMLElement;
950
+ protected registerEventListeners(): void;
951
+ protected onPageChanged: (page: number) => void;
952
+ protected onTransitionStart: () => void;
953
+ protected onTransitionEnd: () => void;
954
+ protected onError: ({ error }: {
955
+ error: Error;
956
+ }) => void;
957
+ private destroyed;
958
+ destroy(): void;
959
+ protected refreshPages: () => void;
960
+ protected getPageIndex(page: number): number;
961
+ protected renderSlideContainer(): HTMLDivElement;
962
+ protected onPlay: () => void;
963
+ protected onNewPageIndex: (index: number) => void;
964
+ protected wrapClassName(className: string): string;
965
+ protected namespace: string;
966
+ }
967
+
968
+ declare const usePlugin: (plugin: any) => any;
969
+ declare const version: string;
970
+
971
+ interface AppOptions extends Pick<ISlideConfig, "rtcAudio" | "useLocalCache" | "resourceTimeout" | "loaderDelegate" | "navigatorDelegate" | "fixedFrameSize" | "logger"> {
18
972
  /** show debug controller */
19
973
  debug?: boolean;
20
974
  /** scale */
@@ -40,12 +994,12 @@ export interface AppOptions extends Pick<ISlideConfig, "rtcAudio" | "useLocalCac
40
994
  /** whether to show an overlay of error message @default: true */
41
995
  showRenderError?: boolean;
42
996
  }
43
- export interface ILogger {
997
+ interface ILogger {
44
998
  info?(msg: string): void;
45
999
  error?(msg: string): void;
46
1000
  warn?(msg: string): void;
47
1001
  }
48
- export interface AppResult {
1002
+ interface AppResult {
49
1003
  viewer: () => SlideDocsViewer | null;
50
1004
  controller: () => SlideController | null | undefined;
51
1005
  slide: () => Slide | undefined;
@@ -57,4 +1011,5 @@ export interface AppResult {
57
1011
  jumpToPage: (page: number) => boolean;
58
1012
  }
59
1013
  declare const SlideApp: NetlessApp<Attributes, MagixEvents, AppOptions, AppResult>;
60
- export default SlideApp;
1014
+
1015
+ export { AddHooks, AppOptions, AppResult, Attributes, DefaultUrl, FreezableSlide, FreezerLength, ILogger, PreviewParams, Slide, SlidePreviewer, addHooks, apps, SlideApp as default, getFreezerLength, onCreated, onDestroyed, previewSlide, setFreezerLength, usePlugin, version };