Skip to content

Commit

Permalink
fix(whiteboard): scroll bug on the edge (#1561)
Browse files Browse the repository at this point in the history
* fix(whiteboard): scroll bug on the edge

* refactor(whiteboard): improve scroll mode behaviors

* refactor scroll

* upgrade window-manager, fix replay error
  • Loading branch information
hyrious authored Jun 9, 2022
1 parent 9b9a7c5 commit b5ee57c
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 53 deletions.
2 changes: 1 addition & 1 deletion desktop/renderer-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@netless/flat-rtc-agora-electron": "workspace:*",
"@netless/player-controller": "^0.0.9",
"@netless/video-js-plugin": "^0.3.8",
"@netless/window-manager": "^0.4.27-canary.0",
"@netless/window-manager": "^0.4.31",
"@videojs/vhs-utils": "^2.3.0",
"agora-rtm-sdk": "^1.4.4",
"antd": "^4.19.2",
Expand Down
2 changes: 1 addition & 1 deletion desktop/renderer-app/src/components/Whiteboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const Whiteboard = observer<WhiteboardProps>(function Whiteboard({

useEffect(() => {
if (whiteboardEl && fastboardAPP) {
return mousewheelToScroll(whiteboardEl, fastboardAPP.manager);
return mousewheelToScroll(whiteboardEl, fastboardAPP);
}
return;
}, [whiteboardEl, fastboardAPP]);
Expand Down
41 changes: 31 additions & 10 deletions desktop/renderer-app/src/stores/whiteboard-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ import { v4 as v4uuid } from "uuid";
import { debounce } from "lodash-es";
import { makeAutoObservable, observable, runInAction } from "mobx";
import { isMobile, isWindows } from "react-device-detect";
import { DeviceType, Room, RoomPhase, RoomState, SceneDefinition, ViewMode } from "white-web-sdk";
import {
AnimationMode,
DeviceType,
Room,
RoomPhase,
RoomState,
SceneDefinition,
ViewMode,
} from "white-web-sdk";
import { snapshot } from "@netless/white-snapshot";

import { RoomType } from "../../../../packages/flat-components/src/types/room";
Expand Down Expand Up @@ -343,13 +351,13 @@ export class WhiteboardStore {

// Disable scale, fix height.
fastboardAPP.manager.mainView.setCameraBound({
damping: 0,
damping: 1,
centerX: 0,
centerY: 0,
minContentMode: () => 1,
maxContentMode: () => 1,
width: 0,
height: 2400,
height: 9999,
});

this.updateFastboardAPP(fastboardAPP);
Expand All @@ -366,12 +374,25 @@ export class WhiteboardStore {
this.updateViewMode(room.state.broadcastState.mode);
}

this.scrollToTopOnce();

if (NODE_ENV === "development") {
(window as any).room = room;
(window as any).manager = this.windowManager;
}
}

private scrollToTopOnce(): void {
const { room, windowManager } = this;
if (!room || !windowManager) {
return;
}
if (!room.state.globalState || !(room.state.globalState as any).scrollToTop) {
room.setGlobalState({ scrollToTop: true });
windowManager.moveCamera({ centerY: -950, animationMode: AnimationMode.Immediately });
}
}

public async destroy(): Promise<void> {
this.preloadPPTResource.cancel();
await this.fastboardAPP?.destroy();
Expand Down Expand Up @@ -470,13 +491,13 @@ export class WhiteboardStore {
};

public insertImage = async (file: Pick<CloudStorageFile, "fileURL">): Promise<void> => {
const room = this.room;
if (!room) {
const windowManager = this.windowManager;
if (!windowManager) {
return;
}

// 1. shrink the image a little to fit the screen
const maxWidth = window.innerWidth * 0.8;
const maxWidth = window.innerWidth * 0.6;

let width: number;
let height: number;
Expand All @@ -499,24 +520,24 @@ export class WhiteboardStore {
}

const uuid = v4uuid();
const { centerX, centerY } = room.state.cameraState;
const { centerX, centerY } = windowManager.cameraState;
width *= scale;
height *= scale;
this.windowManager?.mainView.insertImage({
windowManager.mainView.insertImage({
uuid,
centerX,
centerY,
width: Math.floor(width),
height: Math.floor(height),
locked: false,
});
this.windowManager?.mainView.completeImageUpload(uuid, file.fileURL);
windowManager.mainView.completeImageUpload(uuid, file.fileURL);

// Prevent scale.
// // 2. move camera to fit image height
// width /= 0.8;
// height /= 0.8;
// this.windowManager?.moveCameraToContain({
// windowManager.moveCameraToContain({
// originX: centerX - width / 2,
// originY: centerY - height / 2,
// width: width,
Expand Down
31 changes: 23 additions & 8 deletions desktop/renderer-app/src/utils/mousewheel-to-scroll.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import type { AnimationMode, WindowManager } from "@netless/window-manager";
import type { FastboardApp } from "@netless/fastboard-react";
import type { AnimationMode } from "@netless/window-manager";

// Let mouse wheel act as scrolling the whiteboard
export function mousewheelToScroll(root: HTMLElement, manager: WindowManager): () => void {
export function mousewheelToScroll(root: HTMLElement, fastboard: FastboardApp): () => void {
const $whiteboard = root.querySelector(".netless-window-manager-main-view") as HTMLDivElement;
if (!$whiteboard) {
throw new Error("Not found .netless-window-manager-main-view");
}
const listener = (ev: Event): void => {
ev.preventDefault();
ev.stopPropagation();
const dy = (ev as WheelEvent).deltaY || 0;
manager.moveCamera({
centerY: manager.camera.centerY + dy * manager.camera.scale,
animationMode: "immediately" as AnimationMode.Immediately,
});
if (fastboard.writable.value) {
fastboard.manager.moveCamera({
centerY: clamp(
fastboard.manager.camera.centerY + dy * fastboard.manager.camera.scale,
-950,
950,
),
animationMode: "immediately" as AnimationMode.Immediately,
});
}
};
root.addEventListener("wheel", listener, true);
return () => root.removeEventListener("wheel", listener, true);
$whiteboard.addEventListener("wheel", listener, true);
return () => $whiteboard.removeEventListener("wheel", listener, true);
}

function clamp(x: number, min: number, max: number): number {
return x < min ? min : x > max ? max : x;
}
26 changes: 13 additions & 13 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion web/flat-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@netless/flat-rtc-agora-web": "workspace:*",
"@netless/player-controller": "^0.0.9",
"@netless/video-js-plugin": "^0.3.8",
"@netless/window-manager": "^0.4.27-canary.0",
"@netless/window-manager": "^0.4.31",
"@videojs/vhs-utils": "^2.3.0",
"@zip.js/zip.js": "^2.4.6",
"agora-rtc-sdk-ng": "^4.9.4",
Expand Down
2 changes: 1 addition & 1 deletion web/flat-web/src/components/Whiteboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const Whiteboard = observer<WhiteboardProps>(function Whiteboard({

useEffect(() => {
if (whiteboardEl && fastboardAPP) {
return mousewheelToScroll(whiteboardEl, fastboardAPP.manager);
return mousewheelToScroll(whiteboardEl, fastboardAPP);
}
return;
}, [whiteboardEl, fastboardAPP]);
Expand Down
41 changes: 31 additions & 10 deletions web/flat-web/src/stores/whiteboard-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ import { debounce } from "lodash-es";
import { makeAutoObservable, observable, runInAction } from "mobx";
import { isMobile, isWindows } from "react-device-detect";
import { v4 as v4uuid } from "uuid";
import { DeviceType, Room, RoomPhase, RoomState, SceneDefinition, ViewMode } from "white-web-sdk";
import {
AnimationMode,
DeviceType,
Room,
RoomPhase,
RoomState,
SceneDefinition,
ViewMode,
} from "white-web-sdk";
import { snapshot } from "@netless/white-snapshot";

import { queryConvertingTaskStatus } from "../api-middleware/courseware-converting";
Expand Down Expand Up @@ -311,13 +319,13 @@ export class WhiteboardStore {

// Disable scale, fix height.
fastboardAPP.manager.mainView.setCameraBound({
damping: 0,
damping: 1,
centerX: 0,
centerY: 0,
minContentMode: () => 1,
maxContentMode: () => 1,
width: 0,
height: 2400,
height: 9999,
});

this.updateFastboardAPP(fastboardAPP);
Expand All @@ -334,12 +342,25 @@ export class WhiteboardStore {
this.updateViewMode(room.state.broadcastState.mode);
}

this.scrollToTopOnce();

if (process.env.DEV) {
(window as any).room = room;
(window as any).manager = manager;
}
}

private scrollToTopOnce(): void {
const { room, windowManager } = this;
if (!room || !windowManager) {
return;
}
if (!room.state.globalState || !(room.state.globalState as any).scrollToTop) {
room.setGlobalState({ scrollToTop: true });
windowManager.moveCamera({ centerY: -950, animationMode: AnimationMode.Immediately });
}
}

public async destroy(): Promise<void> {
this.preloadPPTResource.cancel();
await this.fastboardAPP?.destroy();
Expand Down Expand Up @@ -438,13 +459,13 @@ export class WhiteboardStore {
};

public insertImage = async (file: Pick<CloudStorageFile, "fileURL">): Promise<void> => {
const room = this.room;
if (!room) {
const windowManager = this.windowManager;
if (!windowManager) {
return;
}

// 1. shrink the image a little to fit the screen
const maxWidth = window.innerWidth * 0.8;
const maxWidth = window.innerWidth * 0.6;

let width: number;
let height: number;
Expand All @@ -467,10 +488,10 @@ export class WhiteboardStore {
}

const uuid = v4uuid();
const { centerX, centerY } = room.state.cameraState;
const { centerX, centerY } = windowManager.cameraState;
width *= scale;
height *= scale;
this.windowManager?.mainView.insertImage({
windowManager.mainView.insertImage({
uuid,
centerX,
centerY,
Expand All @@ -479,13 +500,13 @@ export class WhiteboardStore {
locked: false,
});

this.windowManager?.mainView.completeImageUpload(uuid, file.fileURL);
windowManager.mainView.completeImageUpload(uuid, file.fileURL);

// Prevent scale.
// // 2. move camera to fit image height
// width /= 0.8;
// height /= 0.8;
// this.windowManager?.moveCameraToContain({
// windowManager.moveCameraToContain({
// originX: centerX - width / 2,
// originY: centerY - height / 2,
// width: width,
Expand Down
Loading

0 comments on commit b5ee57c

Please sign in to comment.