@netless/app-slide 0.2.102 → 0.2.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-zh.md +5 -0
- package/README.md +5 -0
- package/dist/index.d.ts +10 -2
- package/dist/main.cjs.js +102 -102
- package/dist/main.cjs.js.map +1 -1
- package/dist/main.es.js +79 -87
- package/dist/main.es.js.map +1 -1
- package/dist/main.iife.js +87 -87
- package/dist/main.iife.js.map +1 -1
- package/package.json +4 -3
- package/src/DocsViewer/ResizableContainer.ts +35 -9
- package/src/SlideController/index.ts +1 -0
- package/src/SlideDocsViewer/index.ts +26 -18
- package/src/index.ts +14 -17
- package/src/typings.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netless/app-slide",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.104",
|
|
4
4
|
"main": "dist/main.cjs.js",
|
|
5
5
|
"module": "dist/main.es.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"types": "node scripts/build-types.mjs",
|
|
9
9
|
"build": "vite build && npm run types",
|
|
10
10
|
"build:dev": "vite build --mode development && npm run types",
|
|
11
|
-
"cleanup": "rimraf ./dist"
|
|
11
|
+
"cleanup": "rimraf ./dist",
|
|
12
|
+
"test": "rimraf test/.cache && esbuild test/ResizableContainer.test.ts --bundle --platform=node --format=cjs --outfile=test/.cache/ResizableContainer.test.cjs && node test/.cache/ResizableContainer.test.cjs"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
14
15
|
"src",
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
"README-zh.md"
|
|
17
18
|
],
|
|
18
19
|
"devDependencies": {
|
|
19
|
-
"@netless/slide": "1.4.
|
|
20
|
+
"@netless/slide": "1.4.57",
|
|
20
21
|
"@types/color-string": "^1.5.2",
|
|
21
22
|
"color-string": "^1.9.1",
|
|
22
23
|
"jspdf": "2.5.1",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Slide } from "@netless/slide";
|
|
1
|
+
import type { Slide } from "@netless/slide";
|
|
2
2
|
import { ScrollBar } from "./ScrollBar";
|
|
3
3
|
import type { AppContext, ReadonlyTeleBox } from "@netless/window-manager";
|
|
4
4
|
import type { Attributes, MagixEvents } from "../typings";
|
|
@@ -8,8 +8,10 @@ export class ResizableContainer {
|
|
|
8
8
|
private root: HTMLDivElement;
|
|
9
9
|
public container: HTMLDivElement;
|
|
10
10
|
private scrollContainer: HTMLDivElement;
|
|
11
|
+
/** @deprecated Use addScaleChangedListener() for multiple observers. */
|
|
11
12
|
public onScaleChanged: ((scale: number) => void) | null = null;
|
|
12
13
|
public onLayoutUpdated: (() => void) | null = null;
|
|
14
|
+
private scaleChangedListeners = new Set<(scale: number) => void>();
|
|
13
15
|
|
|
14
16
|
private parent: HTMLElement;
|
|
15
17
|
private whiteboardContainer: HTMLDivElement | null = null;
|
|
@@ -18,6 +20,7 @@ export class ResizableContainer {
|
|
|
18
20
|
private slideWidth = 1;
|
|
19
21
|
private slideHeight = 1;
|
|
20
22
|
private scrollBar: ScrollBar | null = null;
|
|
23
|
+
private layoutFrameId: number | undefined;
|
|
21
24
|
private context: AppContext<Attributes, MagixEvents, AppOptions>;
|
|
22
25
|
|
|
23
26
|
// 每次 scale 后, 重置为居中
|
|
@@ -30,7 +33,7 @@ export class ResizableContainer {
|
|
|
30
33
|
parent: HTMLElement,
|
|
31
34
|
context: AppContext<Attributes, MagixEvents, AppOptions>,
|
|
32
35
|
enableResize: boolean,
|
|
33
|
-
_box?: ReadonlyTeleBox
|
|
36
|
+
_box?: ReadonlyTeleBox
|
|
34
37
|
) {
|
|
35
38
|
this.enableResize = enableResize;
|
|
36
39
|
this.parent = parent;
|
|
@@ -56,7 +59,7 @@ export class ResizableContainer {
|
|
|
56
59
|
// 初始化滚动条
|
|
57
60
|
this.scrollBar = new ScrollBar(this.root, this);
|
|
58
61
|
}
|
|
59
|
-
}
|
|
62
|
+
}
|
|
60
63
|
|
|
61
64
|
public getTranslate(): { x: number; y: number } {
|
|
62
65
|
return { x: this.translateX, y: this.translateY };
|
|
@@ -66,6 +69,13 @@ export class ResizableContainer {
|
|
|
66
69
|
return this.scale;
|
|
67
70
|
}
|
|
68
71
|
|
|
72
|
+
public addScaleChangedListener(listener: (scale: number) => void): () => void {
|
|
73
|
+
this.scaleChangedListeners.add(listener);
|
|
74
|
+
return () => {
|
|
75
|
+
this.scaleChangedListeners.delete(listener);
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
69
79
|
private renderScrollBar(
|
|
70
80
|
width: number,
|
|
71
81
|
overflowWidth: number,
|
|
@@ -97,6 +107,7 @@ export class ResizableContainer {
|
|
|
97
107
|
};
|
|
98
108
|
|
|
99
109
|
public updateResizableContainer() {
|
|
110
|
+
this.cancelScheduledLayoutUpdate();
|
|
100
111
|
const parentBounds = this.scrollContainer.getBoundingClientRect();
|
|
101
112
|
this.container.style.width = `${parentBounds.width * this.scale}px`;
|
|
102
113
|
this.container.style.height = `${parentBounds.height * this.scale}px`;
|
|
@@ -183,13 +194,26 @@ export class ResizableContainer {
|
|
|
183
194
|
this.scrollContainer.style.height = "100%";
|
|
184
195
|
}
|
|
185
196
|
applyScale = this.enableResize ? applyScale : 1;
|
|
186
|
-
if (this.onScaleChanged && this.enableResize) {
|
|
187
|
-
this.onScaleChanged(applyScale);
|
|
188
|
-
}
|
|
189
197
|
this.scale = applyScale;
|
|
190
|
-
|
|
191
|
-
this.
|
|
192
|
-
|
|
198
|
+
if (this.enableResize) {
|
|
199
|
+
this.onScaleChanged?.(this.scale);
|
|
200
|
+
for (const listener of this.scaleChangedListeners) {
|
|
201
|
+
listener(this.scale);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (this.layoutFrameId === undefined) {
|
|
205
|
+
this.layoutFrameId = requestAnimationFrame(() => {
|
|
206
|
+
this.layoutFrameId = undefined;
|
|
207
|
+
this.updateResizableContainer();
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private cancelScheduledLayoutUpdate(): void {
|
|
213
|
+
if (this.layoutFrameId !== undefined) {
|
|
214
|
+
cancelAnimationFrame(this.layoutFrameId);
|
|
215
|
+
this.layoutFrameId = undefined;
|
|
216
|
+
}
|
|
193
217
|
}
|
|
194
218
|
|
|
195
219
|
public addSlideContainer(slideContainer: HTMLDivElement) {
|
|
@@ -206,7 +230,9 @@ export class ResizableContainer {
|
|
|
206
230
|
}
|
|
207
231
|
|
|
208
232
|
public destroy(_box?: ReadonlyTeleBox): void {
|
|
233
|
+
this.cancelScheduledLayoutUpdate();
|
|
209
234
|
this.onLayoutUpdated = null;
|
|
235
|
+
this.scaleChangedListeners.clear();
|
|
210
236
|
this.scrollBar?.destroy();
|
|
211
237
|
}
|
|
212
238
|
}
|
|
@@ -486,24 +486,32 @@ export class SlideDocsViewer {
|
|
|
486
486
|
|
|
487
487
|
protected scaleDocsToFit = () => {
|
|
488
488
|
if (this.slideController) {
|
|
489
|
-
const { width, height } = this.slideController.slide;
|
|
490
|
-
if (
|
|
491
|
-
this.
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
width,
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
489
|
+
const { width: slideWidth, height: slideHeight } = this.slideController.slide;
|
|
490
|
+
if (slideWidth && slideHeight) {
|
|
491
|
+
const originSize = this.context.storage.state.originSize;
|
|
492
|
+
const { width, height } = originSize && originSize.width > 0 && originSize.height > 0
|
|
493
|
+
? originSize
|
|
494
|
+
: { width: slideWidth, height: slideHeight };
|
|
495
|
+
if (width > 0 && height > 0) {
|
|
496
|
+
this.whiteboardView.moveCameraToContain({
|
|
497
|
+
originX: -width / 2,
|
|
498
|
+
originY: -height / 2,
|
|
499
|
+
width,
|
|
500
|
+
height,
|
|
501
|
+
animationMode: "immediately" as AnimationMode.Immediately,
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
const scale = this.whiteboardView.camera.scale;
|
|
505
|
+
this.whiteboardView.setCameraBound({
|
|
506
|
+
damping: 1,
|
|
507
|
+
maxContentMode: () => scale,
|
|
508
|
+
minContentMode: () => scale,
|
|
509
|
+
centerX: 0,
|
|
510
|
+
centerY: 0,
|
|
511
|
+
width: slideWidth,
|
|
512
|
+
height: slideHeight,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
507
515
|
if (!this.isViewMounted) {
|
|
508
516
|
this.isViewMounted = true;
|
|
509
517
|
console.log("[Slide] mount whiteboard view");
|
package/src/index.ts
CHANGED
|
@@ -107,7 +107,7 @@ export interface AppResult {
|
|
|
107
107
|
jumpToPage: (page: number) => boolean;
|
|
108
108
|
setSildeReadonly: (bol: boolean) => void;
|
|
109
109
|
setSyncEventQueuePolicy: (policy: NonNullable<ISlideConfig["syncEventQueuePolicy"]>) => void;
|
|
110
|
-
onScaleChanged: (cb: (scale: number) => void) => void;
|
|
110
|
+
onScaleChanged: (cb: (scale: number) => void) => () => void;
|
|
111
111
|
scaleView: (to: number) => void;
|
|
112
112
|
getViewScale: () => number | undefined;
|
|
113
113
|
translateView: (offsetX: number, offsetY: number) => void;
|
|
@@ -262,25 +262,22 @@ const SlideApp: NetlessApp<Attributes, MagixEvents, AppOptions, AppResult> = {
|
|
|
262
262
|
return {
|
|
263
263
|
onScaleChanged: (cb: (scale: number) => void) => {
|
|
264
264
|
if (!docsViewer) {
|
|
265
|
-
return;
|
|
265
|
+
return () => void 0;
|
|
266
266
|
}
|
|
267
|
-
docsViewer.resizableContainer.
|
|
267
|
+
return docsViewer.resizableContainer.addScaleChangedListener(cb);
|
|
268
268
|
},
|
|
269
269
|
scaleView: (to: number) => {
|
|
270
|
-
|
|
271
|
-
if (Number.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
context.storage.setState({ slideScale: applyScale });
|
|
282
|
-
context.storage.setState({ translateX: 0.5, translateY: 0.5 });
|
|
283
|
-
docsViewer?.resizableContainer.scaleContainer(applyScale);
|
|
270
|
+
const applyScale = Number(to);
|
|
271
|
+
if (!Number.isFinite(applyScale) || applyScale <= 0) return;
|
|
272
|
+
const container = docsViewer?.resizableContainer;
|
|
273
|
+
if (!container || Math.abs(container.getScale() - applyScale) < 0.001) return;
|
|
274
|
+
|
|
275
|
+
context.storage.setState({
|
|
276
|
+
slideScale: applyScale,
|
|
277
|
+
translateX: 0.5,
|
|
278
|
+
translateY: 0.5,
|
|
279
|
+
});
|
|
280
|
+
container.scaleContainer(applyScale);
|
|
284
281
|
},
|
|
285
282
|
getViewScale: () => {
|
|
286
283
|
return docsViewer?.resizableContainer.getScale();
|