fix(tldraw): wrong initial/viewer zoom
Fixes a case when the presentation is just uploaded and a wrong initial zoom was set. Also fix viewer zoom not correclty adjusting to the area size when zoomed out.
This commit is contained in:
parent
5748a783a6
commit
217fd6c06e
@ -1,10 +1,8 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import switchSlide from './methods/switchSlide';
|
||||
import zoomSlide from './methods/zoomSlide';
|
||||
import persistAsset from './methods/persistAsset';
|
||||
|
||||
Meteor.methods({
|
||||
switchSlide,
|
||||
zoomSlide,
|
||||
persistAsset,
|
||||
});
|
||||
|
@ -1,21 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import addAsset from '../modifiers/addAsset';
|
||||
|
||||
export default function persistAsset(asset) {
|
||||
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||
const EVENT_NAME = 'test';
|
||||
|
||||
try {
|
||||
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||
|
||||
asset.meetingId = meetingId;
|
||||
addAsset(asset);
|
||||
|
||||
// RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, shape);
|
||||
} catch (err) {
|
||||
Logger.error(`Exception while invoking method persistAsset ${err.stack}`);
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import Captions from '/imports/api/captions';
|
||||
|
||||
export default function addAsset(asset) {
|
||||
|
||||
delete asset._id;
|
||||
Captions.upsert({ meetingId: asset.meetingId, id: asset.id }, { ...asset })
|
||||
}
|
@ -892,6 +892,9 @@ class Presentation extends PureComponent {
|
||||
showSlide,
|
||||
isFullscreen,
|
||||
localPosition,
|
||||
isZoomed,
|
||||
presentationWidth,
|
||||
presentationHeight,
|
||||
} = this.state;
|
||||
|
||||
let viewBoxDimensions;
|
||||
@ -970,8 +973,10 @@ class Presentation extends PureComponent {
|
||||
curPageId={currentSlide?.num.toString()}
|
||||
svgUri={currentSlide?.svgUri}
|
||||
intl={intl}
|
||||
presentationBounds={presentationBounds}
|
||||
presentationWidth={presentationWidth}
|
||||
presentationHeight={presentationHeight}
|
||||
isViewersCursorLocked={isViewersCursorLocked}
|
||||
isZoomed={isZoomed}
|
||||
setIsZoomed={this.setIsZoomed}
|
||||
zoomChanger={this.zoomChanger}
|
||||
/>
|
||||
|
@ -2,15 +2,13 @@ import * as React from "react";
|
||||
import _ from "lodash";
|
||||
import Cursors from "./cursors/container";
|
||||
import { TldrawApp, Tldraw } from "@tldraw/tldraw";
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import {
|
||||
ColorStyle,
|
||||
DashStyle,
|
||||
SizeStyle,
|
||||
TDDocument,
|
||||
TDShapeType,
|
||||
} from "@tldraw/tldraw";
|
||||
import { Renderer, Utils } from "@tldraw/core";
|
||||
import { Utils } from "@tldraw/core";
|
||||
|
||||
function usePrevious(value) {
|
||||
const ref = React.useRef();
|
||||
@ -31,11 +29,8 @@ export default function Whiteboard(props) {
|
||||
isPresenter,
|
||||
removeShapes,
|
||||
initDefaultPages,
|
||||
meetingId,
|
||||
persistShape,
|
||||
persistAsset,
|
||||
shapes,
|
||||
assets,
|
||||
currentUser,
|
||||
curPres,
|
||||
whiteboardId,
|
||||
@ -45,7 +40,8 @@ export default function Whiteboard(props) {
|
||||
slidePosition,
|
||||
curPageId,
|
||||
svgUri,
|
||||
presentationBounds,
|
||||
presentationWidth,
|
||||
presentationHeight,
|
||||
isViewersCursorLocked,
|
||||
setIsZoomed,
|
||||
zoomChanger,
|
||||
@ -61,35 +57,28 @@ export default function Whiteboard(props) {
|
||||
pages,
|
||||
pageStates,
|
||||
bindings: {},
|
||||
assets,
|
||||
assets: {},
|
||||
});
|
||||
//const [doc, setDoc] = React.useState(rDocument.current);
|
||||
const [_assets, setAssets] = React.useState(assets);
|
||||
const [command, setCommand] = React.useState("");
|
||||
const [wbAccess, setWBAccess] = React.useState(props?.hasMultiUserAccess(props.whiteboardId, props.currentUser.userId));
|
||||
const [selectedIds, setSelectedIds] = React.useState([]);
|
||||
const [tldrawAPI, setTLDrawAPI] = React.useState(null);
|
||||
const [cameraFitSlide, setCameraFitSlide] = React.useState({point: [0, 0], zoom: 0});
|
||||
const prevShapes = usePrevious(shapes);
|
||||
const prevSlidePosition = usePrevious(slidePosition);
|
||||
const prevPageId = usePrevious(curPageId);
|
||||
|
||||
const calculateCameraFitSlide = () => {
|
||||
let zoom =
|
||||
Math.min(
|
||||
(presentationBounds.width) / slidePosition.width,
|
||||
(presentationBounds.height) / slidePosition.height
|
||||
(presentationWidth) / slidePosition.width,
|
||||
(presentationHeight) / slidePosition.height
|
||||
);
|
||||
|
||||
zoom = Utils.clamp(zoom, 0.1, 5);
|
||||
|
||||
let point = [0, 0];
|
||||
if ((presentationBounds.width / presentationBounds.height) >
|
||||
if ((presentationWidth / presentationHeight) >
|
||||
(slidePosition.width / slidePosition.height))
|
||||
{
|
||||
point[0] = (presentationBounds.width - (slidePosition.width * zoom)) / 2 / zoom
|
||||
point[0] = (presentationWidth - (slidePosition.width * zoom)) / 2 / zoom
|
||||
} else {
|
||||
point[1] = (presentationBounds.height - (slidePosition.height * zoom)) / 2 / zoom
|
||||
point[1] = (presentationHeight - (slidePosition.height * zoom)) / 2 / zoom
|
||||
}
|
||||
|
||||
isPresenter && zoomChanger(zoom);
|
||||
@ -172,9 +161,9 @@ export default function Whiteboard(props) {
|
||||
}
|
||||
|
||||
return currentDoc;
|
||||
}, [assets, shapes, tldrawAPI, curPageId, slidePosition]);
|
||||
}, [shapes, tldrawAPI, curPageId, slidePosition]);
|
||||
|
||||
// when presentationBounds change, update tldraw camera
|
||||
// when presentationSizes change, update tldraw camera
|
||||
// to fit slide on center if zoomed out
|
||||
React.useEffect(() => {
|
||||
if (curPageId && slidePosition) {
|
||||
@ -184,7 +173,7 @@ export default function Whiteboard(props) {
|
||||
tldrawAPI?.setCamera(camera.point, camera.zoom);
|
||||
}
|
||||
}
|
||||
}, [presentationBounds, curPageId, document?.documentElement?.dir]);
|
||||
}, [presentationWidth, presentationHeight, curPageId, document?.documentElement?.dir]);
|
||||
|
||||
// change tldraw page when presentation page changes
|
||||
React.useEffect(() => {
|
||||
@ -388,6 +377,14 @@ export default function Whiteboard(props) {
|
||||
|
||||
onPatch={(s, reason) => {
|
||||
if (reason && isPresenter && (reason.includes("zoomed") || reason.includes("panned"))) {
|
||||
if (cameraFitSlide.zoom === 0) {
|
||||
//can happen when the slide finish uploading
|
||||
const cameraFitSlide = calculateCameraFitSlide();
|
||||
tldrawAPI?.setCamera(cameraFitSlide.point, cameraFitSlide.zoom);
|
||||
setIsZoomed(false);
|
||||
setCameraFitSlide(cameraFitSlide);
|
||||
return;
|
||||
}
|
||||
const camera = tldrawAPI.getPageState().camera;
|
||||
//don't allow zoom out more than fit
|
||||
if (camera.zoom <= cameraFitSlide.zoom) {
|
||||
|
@ -16,18 +16,15 @@ const WhiteboardContainer = (props) => {
|
||||
|
||||
export default withTracker(({ whiteboardId, curPageId, intl, zoomChanger }) => {
|
||||
const shapes = Service.getShapes(whiteboardId, curPageId, intl);
|
||||
const assets = Service.getAssets();
|
||||
const curPres = Service.getCurrentPres();
|
||||
|
||||
return {
|
||||
initDefaultPages: Service.initDefaultPages,
|
||||
persistShape: Service.persistShape,
|
||||
persistAsset: Service.persistAsset,
|
||||
isMultiUserActive: Service.isMultiUserActive,
|
||||
hasMultiUserAccess: Service.hasMultiUserAccess,
|
||||
changeCurrentSlide: Service.changeCurrentSlide,
|
||||
shapes: shapes,
|
||||
assets: assets,
|
||||
curPres,
|
||||
removeShapes: Service.removeShapes,
|
||||
zoomSlide: PresentationToolbarService.zoomSlide,
|
||||
|
@ -1,5 +1,4 @@
|
||||
import Users from '/imports/api/users';
|
||||
import Captions from "/imports/api/captions";
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user';
|
||||
import addAnnotationQuery from '/imports/api/annotations/addAnnotation';
|
||||
@ -13,8 +12,6 @@ const Annotations = new Mongo.Collection(null);
|
||||
|
||||
const UnsentAnnotations = new Mongo.Collection(null);
|
||||
const ANNOTATION_CONFIG = Meteor.settings.public.whiteboard.annotations;
|
||||
const DRAW_START = ANNOTATION_CONFIG.status.start;
|
||||
const DRAW_UPDATE = ANNOTATION_CONFIG.status.update;
|
||||
const DRAW_END = ANNOTATION_CONFIG.status.end;
|
||||
|
||||
let annotationsStreamListener = null;
|
||||
@ -299,8 +296,6 @@ const persistShape = (shape, whiteboardId) => {
|
||||
sendAnnotation(annotation);
|
||||
};
|
||||
|
||||
const persistAsset = (asset) => makeCall("persistAsset", asset);
|
||||
|
||||
const removeShapes = (shapes, whiteboardId) => makeCall("deleteAnnotations", shapes, whiteboardId);
|
||||
|
||||
const changeCurrentSlide = (s) => {
|
||||
@ -355,18 +350,6 @@ const getCurrentPres = () => {
|
||||
return PresentationService.getCurrentPresentation(podId);
|
||||
}
|
||||
|
||||
const getAssets = () => {
|
||||
// temporary storage for assets
|
||||
let a = Captions.find().fetch().filter(s => s.src);
|
||||
let _assets = {}
|
||||
Object.entries(a).map(([k,v]) => {
|
||||
_assets[v.id] = v;
|
||||
return v.src && v;
|
||||
});
|
||||
|
||||
return _assets;
|
||||
}
|
||||
|
||||
const initDefaultPages = (count = 1) => {
|
||||
const pages = {};
|
||||
const pageStates = {};
|
||||
@ -409,9 +392,7 @@ export {
|
||||
removeGlobalAccess,
|
||||
removeIndividualAccess,
|
||||
persistShape,
|
||||
persistAsset,
|
||||
getShapes,
|
||||
getAssets,
|
||||
getCurrentPres,
|
||||
removeShapes,
|
||||
changeCurrentSlide,
|
||||
|
Loading…
Reference in New Issue
Block a user