2023-12-06 02:15:25 +08:00
|
|
|
import React, { useState, useEffect, useRef } from 'react';
|
2024-01-09 22:31:08 +08:00
|
|
|
import SlideCalcUtil, {
|
|
|
|
HUNDRED_PERCENT,
|
|
|
|
MAX_PERCENT,
|
|
|
|
} from "/imports/utils/slideCalcUtils";
|
2023-12-06 02:15:25 +08:00
|
|
|
|
|
|
|
const useCursor = (publishCursorUpdate, whiteboardId) => {
|
|
|
|
const [cursorPosition, setCursorPosition] = useState({ x: -1, y: -1 });
|
|
|
|
|
|
|
|
const updateCursorPosition = (newX, newY) => {
|
|
|
|
setCursorPosition({ x: newX, y: newY });
|
|
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
publishCursorUpdate({
|
|
|
|
xPercent: cursorPosition?.x,
|
|
|
|
yPercent: cursorPosition?.y,
|
|
|
|
whiteboardId,
|
|
|
|
});
|
|
|
|
}, [cursorPosition, publishCursorUpdate, whiteboardId]);
|
|
|
|
|
|
|
|
return [cursorPosition, updateCursorPosition];
|
|
|
|
};
|
|
|
|
|
2024-01-09 22:31:08 +08:00
|
|
|
const useMouseEvents = ({ whiteboardRef, tlEditorRef, isWheelZoomRef, initialZoomRef }, {
|
2023-12-06 02:15:25 +08:00
|
|
|
isPresenter,
|
|
|
|
hasWBAccess,
|
|
|
|
isMouseDownRef,
|
|
|
|
whiteboardToolbarAutoHide,
|
|
|
|
animations,
|
|
|
|
publishCursorUpdate,
|
|
|
|
whiteboardId,
|
|
|
|
cursorPosition,
|
|
|
|
updateCursorPosition,
|
2024-01-09 22:31:08 +08:00
|
|
|
toggleToolsAnimations,
|
|
|
|
zoomChanger,
|
|
|
|
presentationAreaWidth,
|
|
|
|
presentationAreaHeight,
|
|
|
|
calculateZoomValue,
|
|
|
|
currentPresentationPage,
|
2023-12-06 02:15:25 +08:00
|
|
|
}) => {
|
|
|
|
|
|
|
|
const timeoutIdRef = React.useRef();
|
|
|
|
|
|
|
|
const handleMouseUp = () => {
|
|
|
|
if (!isPresenter && !hasWBAccess) {
|
|
|
|
tlEditorRef?.current?.updateInstanceState({ isReadonly: false });
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timeoutIdRef.current) {
|
|
|
|
clearTimeout(timeoutIdRef.current);
|
|
|
|
}
|
|
|
|
|
|
|
|
timeoutIdRef.current = setTimeout(() => {
|
|
|
|
isMouseDownRef.current = false;
|
|
|
|
}, 1000);
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleMouseDown = () => {
|
|
|
|
!isPresenter &&
|
|
|
|
!hasWBAccess &&
|
|
|
|
tlEditorRef?.current?.updateInstanceState({ isReadonly: true });
|
|
|
|
|
|
|
|
isMouseDownRef.current = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleMouseEnter = () => {
|
|
|
|
whiteboardToolbarAutoHide &&
|
|
|
|
toggleToolsAnimations(
|
|
|
|
"fade-out",
|
|
|
|
"fade-in",
|
|
|
|
animations ? ".3s" : "0s",
|
|
|
|
hasWBAccess || isPresenter
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleMouseLeave = () => {
|
|
|
|
if (whiteboardToolbarAutoHide) {
|
|
|
|
toggleToolsAnimations(
|
|
|
|
"fade-in",
|
|
|
|
"fade-out",
|
|
|
|
animations ? "3s" : "0s",
|
|
|
|
hasWBAccess || isPresenter
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
updateCursorPosition(-1, -1);
|
|
|
|
}, 150);
|
|
|
|
};
|
|
|
|
|
2024-01-09 22:31:08 +08:00
|
|
|
|
2023-12-06 02:15:25 +08:00
|
|
|
const handleMouseWheel = (event) => {
|
|
|
|
if (!tlEditorRef.current || !isPresenter) {
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-09 22:31:08 +08:00
|
|
|
isWheelZoomRef.current = true;
|
|
|
|
|
2023-12-06 02:15:25 +08:00
|
|
|
const MAX_ZOOM = 4;
|
2024-01-09 22:31:08 +08:00
|
|
|
const MIN_ZOOM = initialZoomRef.current;
|
|
|
|
const ZOOM_IN_FACTOR = 0.1; // Adjusted for finer control
|
|
|
|
const ZOOM_OUT_FACTOR = 0.1;
|
2023-12-06 02:15:25 +08:00
|
|
|
|
|
|
|
const { x: cx, y: cy, z: cz } = tlEditorRef.current.camera;
|
|
|
|
|
|
|
|
let zoom = cz;
|
|
|
|
if (event.deltaY < 0) {
|
|
|
|
zoom = Math.min(cz + ZOOM_IN_FACTOR, MAX_ZOOM);
|
|
|
|
} else {
|
|
|
|
zoom = Math.max(cz - ZOOM_OUT_FACTOR, MIN_ZOOM);
|
|
|
|
}
|
|
|
|
|
2024-01-09 22:31:08 +08:00
|
|
|
// Base Zoom Calculation using the passed calculateZoomValue function
|
|
|
|
const baseZoom = calculateZoomValue(
|
|
|
|
currentPresentationPage.scaledWidth,
|
|
|
|
currentPresentationPage.scaledHeight
|
|
|
|
);
|
|
|
|
|
|
|
|
// Apply aspect ratio adjustments
|
|
|
|
const displayAspectRatio = presentationAreaWidth / presentationAreaHeight;
|
|
|
|
const contentAspectRatio = currentPresentationPage.scaledWidth / currentPresentationPage.scaledHeight;
|
|
|
|
|
|
|
|
if (contentAspectRatio > displayAspectRatio) {
|
|
|
|
zoom *= contentAspectRatio / displayAspectRatio;
|
|
|
|
} else {
|
|
|
|
zoom *= displayAspectRatio / contentAspectRatio;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adjust zoom based on the base zoom calculation
|
|
|
|
zoom *= baseZoom;
|
|
|
|
|
|
|
|
const zoomRatio = zoom / initialZoomRef.current;
|
|
|
|
const backendZoomValue = zoomRatio * 100;
|
|
|
|
const adjustedBackendZoomValue = Math.min(Math.max(backendZoomValue, 100), 400);
|
|
|
|
|
2023-12-06 02:15:25 +08:00
|
|
|
const nextCamera = {
|
2024-01-09 22:31:08 +08:00
|
|
|
x: cx + (cursorPosition.x / zoom - cursorPosition.x) - (cursorPosition.x / cz - cursorPosition.x),
|
|
|
|
y: cy + (cursorPosition.y / zoom - cursorPosition.y) - (cursorPosition.y / cz - cursorPosition.y),
|
2023-12-06 02:15:25 +08:00
|
|
|
z: zoom,
|
|
|
|
};
|
|
|
|
|
2024-01-09 22:31:08 +08:00
|
|
|
// Apply the bounds restriction logic after the camera has been updated
|
|
|
|
const { maxX, maxY, minX, minY } = tlEditorRef.current.viewportPageBounds;
|
|
|
|
const { scaledWidth, scaledHeight } = currentPresentationPage;
|
|
|
|
|
|
|
|
if (maxX > scaledWidth) {
|
|
|
|
nextCamera.x += maxX - scaledWidth;
|
|
|
|
}
|
|
|
|
if (maxY > scaledHeight) {
|
|
|
|
nextCamera.y += maxY - scaledHeight;
|
|
|
|
}
|
|
|
|
if (nextCamera.x > 0 || minX < 0) {
|
|
|
|
nextCamera.x = 0;
|
|
|
|
}
|
|
|
|
if (nextCamera.y > 0 || minY < 0) {
|
|
|
|
nextCamera.y = 0;
|
|
|
|
}
|
|
|
|
|
2023-12-06 02:15:25 +08:00
|
|
|
tlEditorRef.current.setCamera(nextCamera, { duration: 300 });
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
2024-01-09 22:31:08 +08:00
|
|
|
|
|
|
|
zoomChanger(adjustedBackendZoomValue);
|
|
|
|
|
|
|
|
if (isWheelZoomRef.currentTimeout) {
|
|
|
|
clearTimeout(isWheelZoomRef.currentTimeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
isWheelZoomRef.currentTimeout = setTimeout(() => {
|
|
|
|
isWheelZoomRef.current = false;
|
|
|
|
}, 300);
|
2023-12-06 02:15:25 +08:00
|
|
|
};
|
|
|
|
|
2024-01-09 22:31:08 +08:00
|
|
|
|
2023-12-06 02:15:25 +08:00
|
|
|
React.useEffect(() => {
|
|
|
|
if (whiteboardToolbarAutoHide) {
|
|
|
|
toggleToolsAnimations(
|
|
|
|
"fade-in",
|
|
|
|
"fade-out",
|
|
|
|
animations ? "3s" : "0s",
|
|
|
|
hasWBAccess || isPresenter
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
toggleToolsAnimations(
|
|
|
|
"fade-out",
|
|
|
|
"fade-in",
|
|
|
|
animations ? ".3s" : "0s",
|
|
|
|
hasWBAccess || isPresenter
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}, [whiteboardToolbarAutoHide]);
|
|
|
|
|
|
|
|
React.useEffect(() => {
|
|
|
|
const whiteboardElement = whiteboardRef.current;
|
|
|
|
|
|
|
|
if (whiteboardElement) {
|
|
|
|
whiteboardElement.addEventListener("mousedown", handleMouseDown);
|
|
|
|
whiteboardElement.addEventListener("mouseup", handleMouseUp);
|
|
|
|
whiteboardElement.addEventListener("mouseenter", handleMouseEnter);
|
|
|
|
whiteboardElement.addEventListener("mouseleave", handleMouseLeave);
|
|
|
|
whiteboardElement.addEventListener("wheel", handleMouseWheel, { capture: true });
|
|
|
|
}
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
if (whiteboardElement) {
|
|
|
|
whiteboardElement.removeEventListener("mousedown", handleMouseDown);
|
|
|
|
whiteboardElement.removeEventListener("mouseup", handleMouseUp);
|
|
|
|
whiteboardElement.removeEventListener("mouseenter", handleMouseEnter);
|
|
|
|
whiteboardElement.removeEventListener("mouseleave", handleMouseLeave);
|
|
|
|
whiteboardElement.removeEventListener("wheel", handleMouseWheel);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}, [whiteboardRef, tlEditorRef, handleMouseDown, handleMouseUp, handleMouseEnter, handleMouseLeave, handleMouseWheel]);
|
|
|
|
};
|
|
|
|
|
|
|
|
export {
|
|
|
|
useMouseEvents,
|
|
|
|
useCursor,
|
|
|
|
};
|