@netless/app-presentation 0.1.9-beta.1 → 0.1.9-beta.3
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 +17 -0
- package/dist/index.global.js +5578 -20
- package/dist/index.js +5578 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5578 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -1
- package/src/app-presentation.ts +31 -7
- package/src/scrollbar/index.ts +26 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netless/app-presentation",
|
|
3
|
-
"version": "0.1.9-beta.
|
|
3
|
+
"version": "0.1.9-beta.3",
|
|
4
4
|
"description": "Netless App for presentation slides (images)",
|
|
5
5
|
"author": "netless",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"@hyrious/esbuild-dev": "^0.10.5",
|
|
34
34
|
"@netless/fastboard": "^1.0.6",
|
|
35
35
|
"@netless/window-manager": "^1.0.4",
|
|
36
|
+
"@types/lodash": "^4.17.20",
|
|
36
37
|
"@types/node": "^20.11.30",
|
|
37
38
|
"@wopjs/disposable": "^0.1.5",
|
|
38
39
|
"@wopjs/dom": "^0.1.3",
|
|
@@ -42,5 +43,8 @@
|
|
|
42
43
|
"sass": "^1.72.0",
|
|
43
44
|
"vanilla-lazyload": "^18.0.0",
|
|
44
45
|
"vite": "^5.2.6"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"lodash": "^4.17.21"
|
|
45
49
|
}
|
|
46
50
|
}
|
package/src/app-presentation.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { listen } from '@wopjs/dom'
|
|
|
6
6
|
import styles from './style.scss?inline'
|
|
7
7
|
import { Presentation, type PresentationConfig, type PresentationPage } from "./presentation";
|
|
8
8
|
import { readable, type Readable } from "./store";
|
|
9
|
-
import { Scrollbar } from "./scrollbar";
|
|
9
|
+
import { Scrollbar, type ScrollbarEventCallback } from "./scrollbar";
|
|
10
10
|
|
|
11
11
|
export type Logger = (...data: any[]) => void
|
|
12
12
|
|
|
@@ -45,6 +45,7 @@ export interface PresentationAppOptions {
|
|
|
45
45
|
useScrollbar?: boolean;
|
|
46
46
|
/** debounceSync is used to set the presentation debounce sync, it will be used in the presentation, and the presentation will be debounce sync when the app is initialized */
|
|
47
47
|
debounceSync?: boolean;
|
|
48
|
+
scrollbarEventCallback?: ScrollbarEventCallback
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
export interface PresentationController {
|
|
@@ -67,6 +68,10 @@ export interface PresentationController {
|
|
|
67
68
|
setDocsViewReadonly: (bol: boolean) => void;
|
|
68
69
|
/** set the presentation readonly */
|
|
69
70
|
setReadonly: (bol: boolean) => void;
|
|
71
|
+
/** move the camera */
|
|
72
|
+
moveCamera: (camera: { centerX: number, centerY: number, scale: number }) => void;
|
|
73
|
+
/** get the origin scale */
|
|
74
|
+
getOriginScale: () => number;
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
export { styles }
|
|
@@ -375,16 +380,35 @@ export const NetlessAppPresentation: NetlessApp<{}, {}, PresentationAppOptions,
|
|
|
375
380
|
app.setReadonly(!isWritable)
|
|
376
381
|
}))
|
|
377
382
|
|
|
383
|
+
const getPageSize = () => {
|
|
384
|
+
const { width, height } = app.page() || {}
|
|
385
|
+
return { width: width || 0, height: height || 0 }
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const getOriginScale = () => {
|
|
389
|
+
const { size } = view;
|
|
390
|
+
const { width, height } = getPageSize();
|
|
391
|
+
return Math.min(size.height / height, size.width / width);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const moveCamera = (camera: { centerX: number, centerY: number, scale: number }) => {
|
|
395
|
+
if (context.getIsWritable()) {
|
|
396
|
+
view.moveCamera({...camera, animationMode: 'immediately' as AnimationMode});
|
|
397
|
+
syncView();
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
throw new Error('[Presentation]: moveCamera must be called in writable room')
|
|
401
|
+
}
|
|
402
|
+
|
|
378
403
|
let scrollbar:Scrollbar | undefined;
|
|
379
404
|
if (options.useScrollbar) {
|
|
380
405
|
dispose.make(() => {
|
|
381
406
|
scrollbar = new Scrollbar(app.contentDOM, {
|
|
382
|
-
getPageSize
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
},
|
|
407
|
+
getPageSize,
|
|
408
|
+
getOriginScale,
|
|
409
|
+
syncView,
|
|
386
410
|
getWritable: () => context.getIsWritable(),
|
|
387
|
-
|
|
411
|
+
scrollbarEventCallback: options.scrollbarEventCallback
|
|
388
412
|
}, view)
|
|
389
413
|
return () => scrollbar?.destroy()
|
|
390
414
|
})
|
|
@@ -516,7 +540,7 @@ export const NetlessAppPresentation: NetlessApp<{}, {}, PresentationAppOptions,
|
|
|
516
540
|
}
|
|
517
541
|
}
|
|
518
542
|
|
|
519
|
-
const controller: PresentationController = { app, view, context, jumpPage, prevPage, nextPage, pageState, toPdf, log, setDocsViewReadonly, setReadonly }
|
|
543
|
+
const controller: PresentationController = { app, view, context, jumpPage, prevPage, nextPage, pageState, toPdf, log, setDocsViewReadonly, setReadonly, moveCamera, getOriginScale }
|
|
520
544
|
|
|
521
545
|
dispose.add(listen(window, 'message', (ev: MessageEvent<"@netless/_presentation_">) => {
|
|
522
546
|
if (ev.data === "@netless/_presentation_") {
|
package/src/scrollbar/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import './style.scss?inline';
|
|
2
2
|
import type { View, AnimationMode } from "@netless/window-manager";
|
|
3
3
|
import { makeDraggable } from "./Draggable";
|
|
4
|
+
import { debounce } from 'lodash';
|
|
4
5
|
|
|
5
6
|
export interface ScrollbarOption {
|
|
6
7
|
readonly?: boolean;
|
|
@@ -9,9 +10,19 @@ export interface ScrollbarOption {
|
|
|
9
10
|
height: number;
|
|
10
11
|
};
|
|
11
12
|
getWritable: () => boolean;
|
|
13
|
+
getOriginScale: () => number;
|
|
12
14
|
syncView: () => void;
|
|
15
|
+
scrollbarEventCallback?: ScrollbarEventCallback;
|
|
13
16
|
}
|
|
14
17
|
|
|
18
|
+
export interface ScrollbarEventCallback {
|
|
19
|
+
onScrollbarDragStart?: () => void;
|
|
20
|
+
onScrollbarDragEnd?: () => void;
|
|
21
|
+
onScrollbarDragX?: (x: number) => void;
|
|
22
|
+
onScrollbarDragY?: (y: number) => void;
|
|
23
|
+
onScrollCameraUpdated?: (originScale: number, scale: number) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
15
26
|
export class Scrollbar {
|
|
16
27
|
readonly namespace = "netless-app-presentation"
|
|
17
28
|
private container: HTMLElement;
|
|
@@ -24,6 +35,7 @@ export class Scrollbar {
|
|
|
24
35
|
}
|
|
25
36
|
},
|
|
26
37
|
getWritable: () => false,
|
|
38
|
+
getOriginScale: () => 1,
|
|
27
39
|
syncView: () => void 0
|
|
28
40
|
};
|
|
29
41
|
private view: View;
|
|
@@ -51,12 +63,6 @@ export class Scrollbar {
|
|
|
51
63
|
return `${this.namespace}-${className}`
|
|
52
64
|
}
|
|
53
65
|
|
|
54
|
-
private getOriginScale() {
|
|
55
|
-
const { size } = this.view;
|
|
56
|
-
const { width, height } = this.option.getPageSize();
|
|
57
|
-
return Math.min(size.height / height, size.width / width);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
66
|
setReadonly(bol: boolean){
|
|
61
67
|
this.readonly = bol;
|
|
62
68
|
if (this.readonly) {
|
|
@@ -66,10 +72,10 @@ export class Scrollbar {
|
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
74
|
|
|
69
|
-
onCameraUpdated = () => {
|
|
75
|
+
onCameraUpdated = debounce(() => {
|
|
70
76
|
if (this.readonly) return;
|
|
71
77
|
const { scale, centerX, centerY } = this.view.camera;
|
|
72
|
-
const originScale = this.getOriginScale();
|
|
78
|
+
const originScale = this.option.getOriginScale();
|
|
73
79
|
const ratio = Math.round(originScale / scale * 1000) / 1000;
|
|
74
80
|
const scrollX = Math.round(centerX * originScale);
|
|
75
81
|
const scrollY = Math.round(centerY * originScale);
|
|
@@ -83,8 +89,8 @@ export class Scrollbar {
|
|
|
83
89
|
this.scrollbarY.style.display = ratio === 1 ? 'none' : 'block';
|
|
84
90
|
this.scrollbarY.style.transform = `translateY(${scrollY}px)`;
|
|
85
91
|
}
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
this.option.scrollbarEventCallback?.onScrollCameraUpdated?.(originScale, scale);
|
|
93
|
+
}, 50)
|
|
88
94
|
|
|
89
95
|
onDragStart = () => {
|
|
90
96
|
const camera = this.view.camera;
|
|
@@ -93,11 +99,12 @@ export class Scrollbar {
|
|
|
93
99
|
centerY: camera.centerY,
|
|
94
100
|
scale: camera.scale,
|
|
95
101
|
}
|
|
102
|
+
this.option.scrollbarEventCallback?.onScrollbarDragStart?.();
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
getScrollXRange(camera: {scale: number}) {
|
|
99
106
|
const { width } = this.option.getPageSize();
|
|
100
|
-
const originScale = this.getOriginScale();
|
|
107
|
+
const originScale = this.option.getOriginScale();
|
|
101
108
|
const scale = camera.scale;
|
|
102
109
|
const ratio = Math.round(originScale / scale * 1000) / 1000;
|
|
103
110
|
const scrollWidth = width * (1-ratio);
|
|
@@ -108,7 +115,7 @@ export class Scrollbar {
|
|
|
108
115
|
|
|
109
116
|
getScrollYRange(camera: {scale: number}) {
|
|
110
117
|
const { height } = this.option.getPageSize();
|
|
111
|
-
const originScale = this.getOriginScale();
|
|
118
|
+
const originScale = this.option.getOriginScale();
|
|
112
119
|
const scale = camera.scale;
|
|
113
120
|
const ratio = Math.round(originScale / scale * 1000) / 1000;
|
|
114
121
|
const scrollHeight = height * (1-ratio);
|
|
@@ -120,7 +127,7 @@ export class Scrollbar {
|
|
|
120
127
|
onDragX = (transformedDrag: {x: number, y: number}) => {
|
|
121
128
|
if (this.cameraCache) {
|
|
122
129
|
const {x} = transformedDrag;
|
|
123
|
-
const originScale = this.getOriginScale();
|
|
130
|
+
const originScale = this.option.getOriginScale();
|
|
124
131
|
const { minX, maxX } = this.getScrollXRange(this.cameraCache);
|
|
125
132
|
const scrollX = Math.round(x / originScale);
|
|
126
133
|
let centerX = scrollX + this.cameraCache.centerX;
|
|
@@ -133,13 +140,14 @@ export class Scrollbar {
|
|
|
133
140
|
centerX,
|
|
134
141
|
animationMode: 'immediately' as AnimationMode
|
|
135
142
|
})
|
|
143
|
+
this.option.scrollbarEventCallback?.onScrollbarDragY?.(centerX);
|
|
136
144
|
}
|
|
137
145
|
}
|
|
138
146
|
|
|
139
147
|
onDragY = (transformedDrag: {x: number, y: number}) => {
|
|
140
148
|
if(this.cameraCache){
|
|
141
149
|
const {y} = transformedDrag;
|
|
142
|
-
const originScale = this.getOriginScale();
|
|
150
|
+
const originScale = this.option.getOriginScale();
|
|
143
151
|
const { minY, maxY } = this.getScrollYRange(this.cameraCache);
|
|
144
152
|
const scrollY = Math.round(y / originScale);
|
|
145
153
|
let centerY = scrollY + this.cameraCache.centerY;
|
|
@@ -151,13 +159,15 @@ export class Scrollbar {
|
|
|
151
159
|
this.view.moveCamera({
|
|
152
160
|
centerY,
|
|
153
161
|
animationMode: 'immediately' as AnimationMode
|
|
154
|
-
})
|
|
162
|
+
})
|
|
163
|
+
this.option.scrollbarEventCallback?.onScrollbarDragY?.(centerY);
|
|
155
164
|
}
|
|
156
165
|
}
|
|
157
166
|
|
|
158
167
|
onDragEnd = () => {
|
|
159
168
|
this.cameraCache = undefined
|
|
160
169
|
this.option.syncView();
|
|
170
|
+
this.option.scrollbarEventCallback?.onScrollbarDragEnd?.();
|
|
161
171
|
}
|
|
162
172
|
|
|
163
173
|
private init() {
|
|
@@ -200,7 +210,7 @@ export class Scrollbar {
|
|
|
200
210
|
this.scrollContainer.append(this.scrollbarContainerX, this.scrollbarContainerY);
|
|
201
211
|
this.container.appendChild(this.scrollContainer);
|
|
202
212
|
this.view.callbacks.on('onCameraUpdated', this.onCameraUpdated);
|
|
203
|
-
this.onCameraUpdated()
|
|
213
|
+
this.onCameraUpdated();
|
|
204
214
|
}
|
|
205
215
|
|
|
206
216
|
destroy() {
|