@netless/app-presentation 0.1.9-beta.5 → 0.1.9-beta.7
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/build.ts +3 -0
- package/dist/index.d.ts +115 -40
- package/dist/index.global.js +255 -135
- package/dist/index.js +255 -135
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +255 -135
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -4
- package/src/app-presentation.ts +112 -23
- package/src/index.ts +1 -0
- package/src/presentation.ts +5 -5
- package/src/scrollbar/index.ts +66 -20
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.7",
|
|
4
4
|
"description": "Netless App for presentation slides (images)",
|
|
5
5
|
"author": "netless",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"@hyrious/configs": "^0.1.1",
|
|
32
32
|
"@hyrious/dts": "^0.2.1",
|
|
33
33
|
"@hyrious/esbuild-dev": "^0.10.5",
|
|
34
|
-
"@netless/fastboard": "
|
|
35
|
-
"@netless/window-manager": "^1.0.
|
|
34
|
+
"@netless/fastboard": "1.1.1-beta.0",
|
|
35
|
+
"@netless/window-manager": "^1.0.7-beta.9",
|
|
36
36
|
"@types/lodash": "^4.17.20",
|
|
37
37
|
"@types/node": "^20.11.30",
|
|
38
38
|
"@wopjs/disposable": "^0.1.5",
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
"rollup": "^4.13.1",
|
|
43
43
|
"sass": "^1.72.0",
|
|
44
44
|
"vanilla-lazyload": "^18.0.0",
|
|
45
|
-
"vite": "^5.2.6"
|
|
45
|
+
"vite": "^5.2.6",
|
|
46
|
+
"white-web-sdk": "^2.16.53",
|
|
47
|
+
"@netless/appliance-plugin": "1.1.22-beta.11"
|
|
46
48
|
},
|
|
47
49
|
"dependencies": {
|
|
48
50
|
"lodash": "^4.17.21"
|
package/src/app-presentation.ts
CHANGED
|
@@ -3,10 +3,11 @@ import type { AnimationMode, AppContext, AppPayload, NetlessApp, PublicEvent, Re
|
|
|
3
3
|
import { disposableStore } from '@wopjs/disposable'
|
|
4
4
|
import { listen } from '@wopjs/dom'
|
|
5
5
|
|
|
6
|
-
import styles from './style.scss?inline'
|
|
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
9
|
import { Scrollbar, type ScrollbarEventCallback } from "./scrollbar";
|
|
10
|
+
import { debounce } from "lodash";
|
|
10
11
|
|
|
11
12
|
export type Logger = (...data: any[]) => void
|
|
12
13
|
|
|
@@ -46,6 +47,10 @@ export interface PresentationAppOptions {
|
|
|
46
47
|
/** 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
48
|
debounceSync?: boolean;
|
|
48
49
|
scrollbarEventCallback?: ScrollbarEventCallback
|
|
50
|
+
/** goToPageByClick is used to set the presentation go to page by click, it will be used in the presentation, and the presentation will be go to page by click when the app is initialized */
|
|
51
|
+
goToPageByClick?: boolean;
|
|
52
|
+
/** useClipView is used to set the presentation use clip view, it will be used in the presentation, and the presentation will be use clip view when the app is initialized */
|
|
53
|
+
useClipView?: boolean;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
export interface PresentationController {
|
|
@@ -74,10 +79,12 @@ export interface PresentationController {
|
|
|
74
79
|
getOriginScale: () => number;
|
|
75
80
|
/** get the view scale */
|
|
76
81
|
getScale: () =>number;
|
|
82
|
+
/** get the page size */
|
|
83
|
+
getPageSize: () => { width: number, height: number };
|
|
84
|
+
/** screenshot the current page */
|
|
85
|
+
screenshotCurrentPageAsync: (context: CanvasRenderingContext2D, width?: number, height?: number) => Promise<void>;
|
|
77
86
|
}
|
|
78
87
|
|
|
79
|
-
export { styles }
|
|
80
|
-
|
|
81
88
|
const ppt2page = (ppt: SceneDefinition["ppt"], name?: string): PresentationPage | null =>
|
|
82
89
|
ppt ? { width: ppt.width, height: ppt.height, src: ppt.src, thumbnail: ppt.previewURL, name } : null
|
|
83
90
|
|
|
@@ -88,7 +95,6 @@ const createLogger = (room: Room | undefined): Logger => {
|
|
|
88
95
|
return (...args) => console.log(...args)
|
|
89
96
|
}
|
|
90
97
|
}
|
|
91
|
-
``
|
|
92
98
|
const scenesEqual = (scenes1?: SceneDefinition[], scenes2?: SceneDefinition[]): boolean => {
|
|
93
99
|
if (!scenes1 || !scenes2) {return false}
|
|
94
100
|
if (scenes1.length !== scenes2.length) return false;
|
|
@@ -338,8 +344,13 @@ export const NetlessAppPresentation: NetlessApp<{}, {}, PresentationAppOptions,
|
|
|
338
344
|
|
|
339
345
|
dispose.add(view$$.addStateChangedListener(() => syncViewFromRemote(false, true)))
|
|
340
346
|
|
|
347
|
+
const getPageSize = () => {
|
|
348
|
+
const { width, height } = app.page() || {}
|
|
349
|
+
return { width: width || 0, height: height || 0 }
|
|
350
|
+
}
|
|
351
|
+
|
|
341
352
|
const box = context.getBox()
|
|
342
|
-
const app = dispose.add(createPresentation(box, pages, jumpPage, pageIndex$, options.thumbnail))
|
|
353
|
+
const app = dispose.add(createPresentation(box, pages, jumpPage, pageIndex$, view, options.thumbnail, options.useClipView))
|
|
343
354
|
app.contentDOM.dataset.appPresentationVersion = __VERSION__
|
|
344
355
|
app.scaleDocsToFit = scaleDocsToFit
|
|
345
356
|
app.log = log
|
|
@@ -348,6 +359,21 @@ export const NetlessAppPresentation: NetlessApp<{}, {}, PresentationAppOptions,
|
|
|
348
359
|
app.setDocsViewReadonly(true)
|
|
349
360
|
}
|
|
350
361
|
|
|
362
|
+
const room = context.getRoom();
|
|
363
|
+
const goToPageByClick = () => {
|
|
364
|
+
const currentApplianceName = context.getRoom()?.state?.memberState?.currentApplianceName ?? '';
|
|
365
|
+
if (!app.readonly && currentApplianceName === 'clicker') {
|
|
366
|
+
nextPage();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if(room && options.goToPageByClick && app.whiteboardDOM) {
|
|
371
|
+
dispose.make(() => {
|
|
372
|
+
app.whiteboardDOM.addEventListener('click', goToPageByClick);
|
|
373
|
+
return () => app.whiteboardDOM.removeEventListener('click', goToPageByClick);
|
|
374
|
+
})
|
|
375
|
+
}
|
|
376
|
+
|
|
351
377
|
context.mountView(app.whiteboardDOM)
|
|
352
378
|
if (options.disableCameraTransform) {
|
|
353
379
|
view.disableCameraTransform = true
|
|
@@ -376,17 +402,13 @@ export const NetlessAppPresentation: NetlessApp<{}, {}, PresentationAppOptions,
|
|
|
376
402
|
view.callbacks.on('onCameraUpdatedByDevice', syncView)
|
|
377
403
|
return () => view.callbacks.off('onCameraUpdatedByDevice', syncView)
|
|
378
404
|
})
|
|
405
|
+
|
|
379
406
|
syncViewFromRemote(true)
|
|
380
407
|
|
|
381
408
|
dispose.add(context.emitter.on("writableChange", (isWritable: boolean): void => {
|
|
382
409
|
app.setReadonly(!isWritable)
|
|
383
410
|
}))
|
|
384
411
|
|
|
385
|
-
const getPageSize = () => {
|
|
386
|
-
const { width, height } = app.page() || {}
|
|
387
|
-
return { width: width || 0, height: height || 0 }
|
|
388
|
-
}
|
|
389
|
-
|
|
390
412
|
const getOriginScale = () => {
|
|
391
413
|
const { size } = view;
|
|
392
414
|
const { width, height } = getPageSize();
|
|
@@ -397,13 +419,39 @@ export const NetlessAppPresentation: NetlessApp<{}, {}, PresentationAppOptions,
|
|
|
397
419
|
return view.camera.scale
|
|
398
420
|
}
|
|
399
421
|
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
422
|
+
const screenshotCurrentPageAsync = async (_context: CanvasRenderingContext2D, _width?: number, _height?: number) => {
|
|
423
|
+
const uuid = room?.calibrationTimestamp?.toString() ?? Date.now().toString();
|
|
424
|
+
|
|
425
|
+
const currentPage = pages[pageIndex$.value];
|
|
426
|
+
if (!currentPage) {
|
|
427
|
+
throw new Error('[Presentation]: current page not found')
|
|
428
|
+
}
|
|
429
|
+
const { width, height, src } = currentPage;
|
|
430
|
+
|
|
431
|
+
const img = document.createElement('img')
|
|
432
|
+
img.width = width;
|
|
433
|
+
img.height = height;
|
|
434
|
+
img.crossOrigin = 'Anonymous';
|
|
435
|
+
await new Promise(resolve => { img.onload = resolve; img.src = src })
|
|
436
|
+
_context.drawImage(img, 0, 0, width, height, 0, 0, _width || width, _height || height);
|
|
437
|
+
const currentScenePath = view.focusScenePath;
|
|
438
|
+
if (!currentScenePath) {
|
|
439
|
+
throw new Error('[Presentation]: current scene path not found')
|
|
440
|
+
}
|
|
441
|
+
const windowManger = context.getWindowManager() as any;
|
|
442
|
+
if (windowManger._appliancePlugin) {
|
|
443
|
+
await windowManger._appliancePlugin.screenshotToCanvasAsync(_context, currentScenePath, _width || width, _height || height, {
|
|
444
|
+
centerX: 0,
|
|
445
|
+
centerY: 0,
|
|
446
|
+
scale: _width && _height ? Math.min(_width / width, _height / height) : 1,
|
|
447
|
+
});
|
|
448
|
+
} else {
|
|
449
|
+
await view.screenshotToCanvasAsync(_context, currentScenePath, _width || width, _height || height, {
|
|
450
|
+
centerX: 0,
|
|
451
|
+
centerY: 0,
|
|
452
|
+
scale: _width && _height ? Math.min(_width / width, _height / height) : 1,
|
|
453
|
+
});
|
|
405
454
|
}
|
|
406
|
-
throw new Error('[Presentation]: moveCamera must be called in writable room')
|
|
407
455
|
}
|
|
408
456
|
|
|
409
457
|
let scrollbar:Scrollbar | undefined;
|
|
@@ -421,6 +469,17 @@ export const NetlessAppPresentation: NetlessApp<{}, {}, PresentationAppOptions,
|
|
|
421
469
|
})
|
|
422
470
|
}
|
|
423
471
|
|
|
472
|
+
const moveCamera = (camera: { centerX: number, centerY: number, scale: number }) => {
|
|
473
|
+
if (context.getIsWritable() && scrollbar) {
|
|
474
|
+
if (!scrollbar) {
|
|
475
|
+
throw new Error('[Presentation]: moveCamera must be called when appOptions: useScrollbar is true')
|
|
476
|
+
}
|
|
477
|
+
scrollbar.moveCamera(camera);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
throw new Error('[Presentation]: moveCamera must be called in writable room')
|
|
481
|
+
}
|
|
482
|
+
|
|
424
483
|
context.emitter.on('destroy', () => dispose())
|
|
425
484
|
|
|
426
485
|
const reportProgress = (progress: number, result: { pdf: ArrayBuffer, title: string } | null) => {
|
|
@@ -493,13 +552,13 @@ export const NetlessAppPresentation: NetlessApp<{}, {}, PresentationAppOptions,
|
|
|
493
552
|
const name = p.name ?? String(index + 1)
|
|
494
553
|
if (scenes.some(scene => scene.name == name)) {
|
|
495
554
|
const camera = { centerX: 0, centerY: 0, scale: Math.min(wb_canvas.width / width, wb_canvas.height / height) };
|
|
496
|
-
const sPath = `${scenePath}/${
|
|
555
|
+
const sPath = `${scenePath}/${name}`;
|
|
497
556
|
// appliancePlugin is a performance optimization for whiteboard;
|
|
498
|
-
const windowManger = (
|
|
557
|
+
const windowManger = context.getWindowManager() as any;
|
|
499
558
|
if (windowManger._appliancePlugin) {
|
|
500
|
-
await windowManger._appliancePlugin.screenshotToCanvasAsync(wb, sPath, wb_canvas.width, wb_canvas.height, camera);
|
|
559
|
+
await (windowManger as any)._appliancePlugin.screenshotToCanvasAsync(wb, sPath, wb_canvas.width, wb_canvas.height, camera);
|
|
501
560
|
} else {
|
|
502
|
-
view.
|
|
561
|
+
await view.screenshotToCanvasAsync(
|
|
503
562
|
wb, sPath,
|
|
504
563
|
wb_canvas.width, wb_canvas.height,
|
|
505
564
|
camera,
|
|
@@ -542,12 +601,15 @@ export const NetlessAppPresentation: NetlessApp<{}, {}, PresentationAppOptions,
|
|
|
542
601
|
|
|
543
602
|
const setReadonly = (bol: boolean) => {
|
|
544
603
|
app.setReadonly(bol)
|
|
604
|
+
if (options.goToPageByClick) {
|
|
605
|
+
|
|
606
|
+
}
|
|
545
607
|
if(scrollbar) {
|
|
546
608
|
scrollbar.setReadonly(bol)
|
|
547
609
|
}
|
|
548
610
|
}
|
|
549
611
|
|
|
550
|
-
const controller: PresentationController = { app, view, context, jumpPage, prevPage, nextPage, pageState, toPdf, log, setDocsViewReadonly, setReadonly, moveCamera, getOriginScale, getScale }
|
|
612
|
+
const controller: PresentationController = { app, view, context, jumpPage, prevPage, nextPage, pageState, toPdf, log, setDocsViewReadonly, setReadonly, moveCamera, getOriginScale, getScale, getPageSize, screenshotCurrentPageAsync }
|
|
551
613
|
|
|
552
614
|
dispose.add(listen(window, 'message', (ev: MessageEvent<"@netless/_presentation_">) => {
|
|
553
615
|
if (ev.data === "@netless/_presentation_") {
|
|
@@ -576,7 +638,7 @@ class AppPresentation extends Presentation {
|
|
|
576
638
|
constructor(config: PresentationConfig & { jumpPage: (index: number) => void }) {
|
|
577
639
|
super(config)
|
|
578
640
|
this.jumpPage = config.jumpPage
|
|
579
|
-
this.image.style.display = 'none'
|
|
641
|
+
// this.image.style.display = 'none'
|
|
580
642
|
}
|
|
581
643
|
|
|
582
644
|
override updateImage() {
|
|
@@ -604,17 +666,44 @@ function createPresentation(
|
|
|
604
666
|
pages: PresentationPage[],
|
|
605
667
|
jumpPage: (index: number) => void,
|
|
606
668
|
pageIndex$: Readable<number>,
|
|
669
|
+
view: View,
|
|
607
670
|
thumbnail?: (src: string) => string,
|
|
671
|
+
useClipView?: boolean,
|
|
608
672
|
): AppPresentation {
|
|
609
673
|
box.mountStyles(styles)
|
|
610
674
|
|
|
611
|
-
const app = new AppPresentation({ pages, readonly: box.readonly, jumpPage, thumbnail
|
|
675
|
+
const app = new AppPresentation({ pages, readonly: box.readonly, jumpPage, thumbnail})
|
|
612
676
|
app.box = box
|
|
613
677
|
box.mountContent(app.contentDOM)
|
|
614
678
|
box.mountFooter(app.footerDOM)
|
|
615
679
|
|
|
616
680
|
app.dispose.add(pageIndex$.subscribe(pageIndex => { app.setPageIndex(pageIndex) }))
|
|
617
681
|
|
|
682
|
+
if(useClipView && view){
|
|
683
|
+
const onCameraUpdatedEffectForMaskView = debounce(() => {
|
|
684
|
+
const { width: pageWidth, height: pageHeight } = app.page() || {};
|
|
685
|
+
if(!pageWidth || !pageHeight) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
const { scale } = view.camera;
|
|
689
|
+
const { width, height } = view.size;
|
|
690
|
+
const pageRatioX = Math.round((1 - (pageWidth * scale / width)) / 2 * 100);
|
|
691
|
+
const pageRatioY = Math.round((1 - (pageHeight * scale / height)) / 2 * 100);
|
|
692
|
+
app.whiteboardDOM.style.clipPath = `inset(${pageRatioY}% ${pageRatioX}%)`;
|
|
693
|
+
}, 50)
|
|
694
|
+
onCameraUpdatedEffectForMaskView();
|
|
695
|
+
const onCameraUpdatedEffect = () => {
|
|
696
|
+
view.callbacks.on("onSizeUpdated", onCameraUpdatedEffectForMaskView)
|
|
697
|
+
view.callbacks.on("onCameraUpdated", onCameraUpdatedEffectForMaskView)
|
|
698
|
+
return () => {
|
|
699
|
+
view.callbacks.off("onCameraUpdated", onCameraUpdatedEffectForMaskView);
|
|
700
|
+
view.callbacks.off("onSizeUpdated", onCameraUpdatedEffectForMaskView);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
app.dispose.make(onCameraUpdatedEffect)
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
|
|
618
707
|
return app
|
|
619
708
|
}
|
|
620
709
|
|
package/src/index.ts
CHANGED
package/src/presentation.ts
CHANGED
|
@@ -90,9 +90,9 @@ export class Presentation implements IDisposable<void> {
|
|
|
90
90
|
this.contentDOM.className = this.c('content')
|
|
91
91
|
this.previewDOM = document.createElement('div')
|
|
92
92
|
this.previewDOM.className = this.c('preview')
|
|
93
|
-
this.imageDOM = document.createElement('div')
|
|
94
|
-
this.imageDOM.className = this.c('image')
|
|
95
|
-
this.image = document.createElement('img')
|
|
93
|
+
// this.imageDOM = document.createElement('div')
|
|
94
|
+
// this.imageDOM.className = this.c('image')
|
|
95
|
+
// this.image = document.createElement('img')
|
|
96
96
|
this.whiteboardDOM = document.createElement('div')
|
|
97
97
|
this.whiteboardDOM.className = this.c('wb-view')
|
|
98
98
|
this.footerDOM = document.createElement('div')
|
|
@@ -166,8 +166,8 @@ export class Presentation implements IDisposable<void> {
|
|
|
166
166
|
}
|
|
167
167
|
}))
|
|
168
168
|
|
|
169
|
-
this.imageDOM.appendChild(this.image)
|
|
170
|
-
this.contentDOM.appendChild(this.imageDOM)
|
|
169
|
+
// this.imageDOM.appendChild(this.image)
|
|
170
|
+
// this.contentDOM.appendChild(this.imageDOM)
|
|
171
171
|
this.updateImage()
|
|
172
172
|
|
|
173
173
|
this.contentDOM.appendChild(this.whiteboardDOM)
|
package/src/scrollbar/index.ts
CHANGED
|
@@ -1,7 +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
|
+
import { debounce, isNumber } from 'lodash';
|
|
5
5
|
|
|
6
6
|
export interface ScrollbarOption {
|
|
7
7
|
appId: string;
|
|
@@ -79,17 +79,22 @@ export class Scrollbar {
|
|
|
79
79
|
if (this.readonly) return;
|
|
80
80
|
const { scale, centerX, centerY } = this.view.camera;
|
|
81
81
|
const originScale = this.option.getOriginScale();
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
82
|
+
const { width: pageWidth, height: pageHeight } = this.option.getPageSize();
|
|
83
|
+
const { width: viewWidth, height: viewHeight } = this.view.size;
|
|
84
|
+
const originScaleX = viewWidth / pageWidth;
|
|
85
|
+
const originScaleY = viewHeight / pageHeight;
|
|
86
|
+
const ratioX = Math.min(Math.round(originScaleX / scale * 100) / 100, 1);
|
|
87
|
+
const ratioY = Math.min(Math.round(originScaleY / scale * 100) / 100, 1);
|
|
88
|
+
const scrollX = Math.round(centerX * originScaleX);
|
|
89
|
+
const scrollY = Math.round(centerY * originScaleY);
|
|
85
90
|
if (this.scrollbarX) {
|
|
86
|
-
this.scrollbarX.style.width = `${
|
|
87
|
-
this.scrollbarX.style.display =
|
|
91
|
+
this.scrollbarX.style.width = `${ratioX * 100}%`;
|
|
92
|
+
this.scrollbarX.style.display = ratioX === 1 ? 'none' : 'block';
|
|
88
93
|
this.scrollbarX.style.transform = `translateX(${scrollX}px)`;
|
|
89
94
|
}
|
|
90
95
|
if (this.scrollbarY) {
|
|
91
|
-
this.scrollbarY.style.height = `${
|
|
92
|
-
this.scrollbarY.style.display =
|
|
96
|
+
this.scrollbarY.style.height = `${ratioY * 100}%`;
|
|
97
|
+
this.scrollbarY.style.display = ratioY === 1 ? 'none' : 'block';
|
|
93
98
|
this.scrollbarY.style.transform = `translateY(${scrollY}px)`;
|
|
94
99
|
}
|
|
95
100
|
this.option.scrollbarEventCallback?.onScrollCameraUpdated?.(this.appId, originScale, scale);
|
|
@@ -106,22 +111,26 @@ export class Scrollbar {
|
|
|
106
111
|
}
|
|
107
112
|
|
|
108
113
|
getScrollXRange(camera: {scale: number}) {
|
|
109
|
-
const { width } = this.option.getPageSize();
|
|
110
|
-
const
|
|
114
|
+
const { width: pageWidth } = this.option.getPageSize();
|
|
115
|
+
const { width: viewWidth } = this.view.size;
|
|
116
|
+
const originScaleX = viewWidth / pageWidth;
|
|
117
|
+
// const originScale = this.option.getOriginScale();
|
|
111
118
|
const scale = camera.scale;
|
|
112
|
-
const ratio = Math.round(
|
|
113
|
-
const scrollWidth =
|
|
119
|
+
const ratio = Math.min(Math.round(originScaleX / scale * 100) / 100, 1);
|
|
120
|
+
const scrollWidth = pageWidth * (1-ratio);
|
|
114
121
|
const minX = -scrollWidth / 2;
|
|
115
122
|
const maxX = scrollWidth / 2;
|
|
116
123
|
return { minX, maxX };
|
|
117
124
|
}
|
|
118
125
|
|
|
119
126
|
getScrollYRange(camera: {scale: number}) {
|
|
120
|
-
const { height } = this.option.getPageSize();
|
|
121
|
-
const
|
|
127
|
+
const { height: pageHeight } = this.option.getPageSize();
|
|
128
|
+
const { height: viewHeight } = this.view.size;
|
|
129
|
+
const originScaleY = viewHeight / pageHeight;
|
|
130
|
+
// const originScale = this.option.getOriginScale();
|
|
122
131
|
const scale = camera.scale;
|
|
123
|
-
const ratio = Math.round(
|
|
124
|
-
const scrollHeight =
|
|
132
|
+
const ratio = Math.min(Math.round(originScaleY / scale * 100) / 100, 1);
|
|
133
|
+
const scrollHeight = pageHeight * (1-ratio);
|
|
125
134
|
const minY = -scrollHeight / 2;
|
|
126
135
|
const maxY = scrollHeight / 2;
|
|
127
136
|
return { minY, maxY };
|
|
@@ -130,9 +139,12 @@ export class Scrollbar {
|
|
|
130
139
|
onDragX = (transformedDrag: {x: number, y: number}) => {
|
|
131
140
|
if (this.cameraCache) {
|
|
132
141
|
const {x} = transformedDrag;
|
|
133
|
-
const originScale = this.option.getOriginScale();
|
|
142
|
+
// const originScale = this.option.getOriginScale();
|
|
143
|
+
const { width: pageWidth } = this.option.getPageSize();
|
|
144
|
+
const { width: viewWidth } = this.view.size;
|
|
145
|
+
const originScaleX = viewWidth / pageWidth;
|
|
134
146
|
const { minX, maxX } = this.getScrollXRange(this.cameraCache);
|
|
135
|
-
const scrollX =
|
|
147
|
+
const scrollX =Math.round(x / originScaleX);
|
|
136
148
|
let centerX = scrollX + this.cameraCache.centerX;
|
|
137
149
|
if (centerX < minX) {
|
|
138
150
|
centerX = minX;
|
|
@@ -150,9 +162,12 @@ export class Scrollbar {
|
|
|
150
162
|
onDragY = (transformedDrag: {x: number, y: number}) => {
|
|
151
163
|
if(this.cameraCache){
|
|
152
164
|
const {y} = transformedDrag;
|
|
153
|
-
const originScale = this.option.getOriginScale();
|
|
165
|
+
// const originScale = this.option.getOriginScale();
|
|
166
|
+
const { height: pageHeight } = this.option.getPageSize();
|
|
167
|
+
const { height: viewHeight } = this.view.size;
|
|
168
|
+
const originScaleY = viewHeight / pageHeight;
|
|
154
169
|
const { minY, maxY } = this.getScrollYRange(this.cameraCache);
|
|
155
|
-
const scrollY = Math.round(y /
|
|
170
|
+
const scrollY = Math.round(y / originScaleY);
|
|
156
171
|
let centerY = scrollY + this.cameraCache.centerY;
|
|
157
172
|
if (centerY < minY) {
|
|
158
173
|
centerY = minY;
|
|
@@ -241,4 +256,35 @@ export class Scrollbar {
|
|
|
241
256
|
|
|
242
257
|
}
|
|
243
258
|
|
|
259
|
+
moveCamera = (camera: { centerX: number, centerY: number, scale: number }) => {
|
|
260
|
+
const { centerX, centerY } = camera;
|
|
261
|
+
const cacheCamera = this.view.camera;
|
|
262
|
+
const _camera: { centerX?: number, centerY?: number, scale?: number} = {};
|
|
263
|
+
if(isNumber(centerX)) {
|
|
264
|
+
const { minX, maxX } = this.getScrollXRange(cacheCamera);
|
|
265
|
+
let newCenterX = centerX;
|
|
266
|
+
if (centerX < minX) {
|
|
267
|
+
newCenterX = minX;
|
|
268
|
+
} else if (centerX > maxX) {
|
|
269
|
+
newCenterX = maxX;
|
|
270
|
+
}
|
|
271
|
+
_camera.centerX = newCenterX;
|
|
272
|
+
}
|
|
273
|
+
if(isNumber(centerY)) {
|
|
274
|
+
const { minY, maxY } = this.getScrollYRange(cacheCamera);
|
|
275
|
+
let newCenterY = centerY;
|
|
276
|
+
if (centerY < minY) {
|
|
277
|
+
newCenterY = minY;
|
|
278
|
+
} else if (centerY > maxY) {
|
|
279
|
+
newCenterY = maxY;
|
|
280
|
+
}
|
|
281
|
+
_camera.centerY = newCenterY;
|
|
282
|
+
}
|
|
283
|
+
this.view.moveCamera({
|
|
284
|
+
..._camera,
|
|
285
|
+
animationMode: 'immediately' as AnimationMode
|
|
286
|
+
})
|
|
287
|
+
this.option.syncView();
|
|
288
|
+
}
|
|
289
|
+
|
|
244
290
|
}
|