follow scroll location POC
This commit is contained in:
parent
a80ac4c748
commit
9152ce24f2
@ -9,7 +9,9 @@ export const actionGoToCollaborator = register({
|
|||||||
viewMode: true,
|
viewMode: true,
|
||||||
trackEvent: { category: "collab" },
|
trackEvent: { category: "collab" },
|
||||||
perform: (_elements, appState, value) => {
|
perform: (_elements, appState, value) => {
|
||||||
const point = value as Collaborator["pointer"];
|
const _value = value as Collaborator & { clientId: string };
|
||||||
|
const point = _value.pointer;
|
||||||
|
|
||||||
if (!point) {
|
if (!point) {
|
||||||
return { appState, commitToHistory: false };
|
return { appState, commitToHistory: false };
|
||||||
}
|
}
|
||||||
@ -17,6 +19,8 @@ export const actionGoToCollaborator = register({
|
|||||||
return {
|
return {
|
||||||
appState: {
|
appState: {
|
||||||
...appState,
|
...appState,
|
||||||
|
// ˇˇ or maybe an atom? 🤔
|
||||||
|
userToFollow: _value.clientId,
|
||||||
...centerScrollOn({
|
...centerScrollOn({
|
||||||
scenePoint: point,
|
scenePoint: point,
|
||||||
viewportDimensions: {
|
viewportDimensions: {
|
||||||
@ -39,7 +43,7 @@ export const actionGoToCollaborator = register({
|
|||||||
return (
|
return (
|
||||||
<Avatar
|
<Avatar
|
||||||
color={background}
|
color={background}
|
||||||
onClick={() => updateData(collaborator.pointer)}
|
onClick={() => updateData({ ...collaborator, clientId })}
|
||||||
name={collaborator.username || ""}
|
name={collaborator.username || ""}
|
||||||
src={collaborator.avatarUrl}
|
src={collaborator.avatarUrl}
|
||||||
/>
|
/>
|
||||||
|
@ -98,6 +98,7 @@ export const getDefaultAppState = (): Omit<
|
|||||||
pendingImageElementId: null,
|
pendingImageElementId: null,
|
||||||
showHyperlinkPopup: false,
|
showHyperlinkPopup: false,
|
||||||
selectedLinearElement: null,
|
selectedLinearElement: null,
|
||||||
|
userToFollow: null,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -204,6 +205,7 @@ const APP_STATE_STORAGE_CONF = (<
|
|||||||
pendingImageElementId: { browser: false, export: false, server: false },
|
pendingImageElementId: { browser: false, export: false, server: false },
|
||||||
showHyperlinkPopup: { browser: false, export: false, server: false },
|
showHyperlinkPopup: { browser: false, export: false, server: false },
|
||||||
selectedLinearElement: { browser: true, export: false, server: false },
|
selectedLinearElement: { browser: true, export: false, server: false },
|
||||||
|
userToFollow: { browser: false, export: false, server: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
const _clearAppStateForStorage = <
|
const _clearAppStateForStorage = <
|
||||||
|
@ -1500,6 +1500,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.refreshDeviceState(this.excalidrawContainerRef.current);
|
this.refreshDeviceState(this.excalidrawContainerRef.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO follow-participant
|
||||||
|
// add zoom change
|
||||||
if (
|
if (
|
||||||
prevState.scrollX !== this.state.scrollX ||
|
prevState.scrollX !== this.state.scrollX ||
|
||||||
prevState.scrollY !== this.state.scrollY
|
prevState.scrollY !== this.state.scrollY
|
||||||
|
@ -89,6 +89,7 @@ export interface CollabAPI {
|
|||||||
/** function so that we can access the latest value from stale callbacks */
|
/** function so that we can access the latest value from stale callbacks */
|
||||||
isCollaborating: () => boolean;
|
isCollaborating: () => boolean;
|
||||||
onPointerUpdate: CollabInstance["onPointerUpdate"];
|
onPointerUpdate: CollabInstance["onPointerUpdate"];
|
||||||
|
onScrollChange: CollabInstance["onScrollChange"];
|
||||||
startCollaboration: CollabInstance["startCollaboration"];
|
startCollaboration: CollabInstance["startCollaboration"];
|
||||||
stopCollaboration: CollabInstance["stopCollaboration"];
|
stopCollaboration: CollabInstance["stopCollaboration"];
|
||||||
syncElements: CollabInstance["syncElements"];
|
syncElements: CollabInstance["syncElements"];
|
||||||
@ -162,6 +163,7 @@ class Collab extends PureComponent<Props, CollabState> {
|
|||||||
const collabAPI: CollabAPI = {
|
const collabAPI: CollabAPI = {
|
||||||
isCollaborating: this.isCollaborating,
|
isCollaborating: this.isCollaborating,
|
||||||
onPointerUpdate: this.onPointerUpdate,
|
onPointerUpdate: this.onPointerUpdate,
|
||||||
|
onScrollChange: this.onScrollChange,
|
||||||
startCollaboration: this.startCollaboration,
|
startCollaboration: this.startCollaboration,
|
||||||
syncElements: this.syncElements,
|
syncElements: this.syncElements,
|
||||||
fetchImageFilesFromFirebase: this.fetchImageFilesFromFirebase,
|
fetchImageFilesFromFirebase: this.fetchImageFilesFromFirebase,
|
||||||
@ -506,6 +508,8 @@ class Collab extends PureComponent<Props, CollabState> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WS_SCENE_EVENT_TYPES.UPDATE:
|
case WS_SCENE_EVENT_TYPES.UPDATE:
|
||||||
|
console.log("received update", decryptedData);
|
||||||
|
console.log(this.excalidrawAPI.getAppState());
|
||||||
this.handleRemoteSceneUpdate(
|
this.handleRemoteSceneUpdate(
|
||||||
this.reconcileElements(decryptedData.payload.elements),
|
this.reconcileElements(decryptedData.payload.elements),
|
||||||
);
|
);
|
||||||
@ -513,6 +517,9 @@ class Collab extends PureComponent<Props, CollabState> {
|
|||||||
case "MOUSE_LOCATION": {
|
case "MOUSE_LOCATION": {
|
||||||
const { pointer, button, username, selectedElementIds } =
|
const { pointer, button, username, selectedElementIds } =
|
||||||
decryptedData.payload;
|
decryptedData.payload;
|
||||||
|
|
||||||
|
// console.log({ decryptedData });
|
||||||
|
|
||||||
const socketId: SocketUpdateDataSource["MOUSE_LOCATION"]["payload"]["socketId"] =
|
const socketId: SocketUpdateDataSource["MOUSE_LOCATION"]["payload"]["socketId"] =
|
||||||
decryptedData.payload.socketId ||
|
decryptedData.payload.socketId ||
|
||||||
// @ts-ignore legacy, see #2094 (#2097)
|
// @ts-ignore legacy, see #2094 (#2097)
|
||||||
@ -530,6 +537,35 @@ class Collab extends PureComponent<Props, CollabState> {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// TODO follow-participant
|
||||||
|
// case "SCROLL_LOCATION"
|
||||||
|
// case "ZOOM_VALUE"
|
||||||
|
// if following someone, update scroll and zoom
|
||||||
|
|
||||||
|
case "SCROLL_LOCATION":
|
||||||
|
const {
|
||||||
|
scroll: { x, y },
|
||||||
|
} = decryptedData.payload;
|
||||||
|
|
||||||
|
const socketId: SocketUpdateDataSource["SCROLL_LOCATION"]["payload"]["socketId"] =
|
||||||
|
decryptedData.payload.socketId;
|
||||||
|
|
||||||
|
console.log({ decryptedData });
|
||||||
|
|
||||||
|
const appState = this.excalidrawAPI.getAppState();
|
||||||
|
console.log({ appState });
|
||||||
|
|
||||||
|
if (appState.userToFollow === socketId) {
|
||||||
|
this.excalidrawAPI.updateScene({
|
||||||
|
appState: {
|
||||||
|
scrollX: x,
|
||||||
|
scrollY: y,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case "IDLE_STATUS": {
|
case "IDLE_STATUS": {
|
||||||
const { userState, socketId, username } = decryptedData.payload;
|
const { userState, socketId, username } = decryptedData.payload;
|
||||||
const collaborators = new Map(this.collaborators);
|
const collaborators = new Map(this.collaborators);
|
||||||
@ -756,6 +792,7 @@ class Collab extends PureComponent<Props, CollabState> {
|
|||||||
button: SocketUpdateDataSource["MOUSE_LOCATION"]["payload"]["button"];
|
button: SocketUpdateDataSource["MOUSE_LOCATION"]["payload"]["button"];
|
||||||
pointersMap: Gesture["pointers"];
|
pointersMap: Gesture["pointers"];
|
||||||
}) => {
|
}) => {
|
||||||
|
// console.log({ payload });
|
||||||
payload.pointersMap.size < 2 &&
|
payload.pointersMap.size < 2 &&
|
||||||
this.portal.socket &&
|
this.portal.socket &&
|
||||||
this.portal.broadcastMouseLocation(payload);
|
this.portal.broadcastMouseLocation(payload);
|
||||||
@ -763,6 +800,21 @@ class Collab extends PureComponent<Props, CollabState> {
|
|||||||
CURSOR_SYNC_TIMEOUT,
|
CURSOR_SYNC_TIMEOUT,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO follow-participant
|
||||||
|
// - onScrollChange
|
||||||
|
// -- broadCastScrollLocation
|
||||||
|
// - onZoomChange
|
||||||
|
// -- broadCastZoomValue
|
||||||
|
|
||||||
|
onScrollChange = throttle(
|
||||||
|
(payload: {
|
||||||
|
scrollX: SocketUpdateDataSource["SCROLL_LOCATION"]["payload"]["scroll"]["x"];
|
||||||
|
scrollY: SocketUpdateDataSource["SCROLL_LOCATION"]["payload"]["scroll"]["y"];
|
||||||
|
}) => {
|
||||||
|
this.portal.socket && this.portal.broadcastScrollLocation(payload);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
onIdleStateChange = (userState: UserIdleState) => {
|
onIdleStateChange = (userState: UserIdleState) => {
|
||||||
this.portal.broadcastIdleChange(userState);
|
this.portal.broadcastIdleChange(userState);
|
||||||
};
|
};
|
||||||
|
@ -213,6 +213,36 @@ class Portal {
|
|||||||
username: this.collab.state.username,
|
username: this.collab.state.username,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// console.log("broadcastMouseLocation data", data);
|
||||||
|
|
||||||
|
return this._broadcastSocketData(
|
||||||
|
data as SocketUpdateData,
|
||||||
|
true, // volatile
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO follow-participant
|
||||||
|
// - broadCastScrollLocation
|
||||||
|
// - broadCastZoomValue
|
||||||
|
|
||||||
|
broadcastScrollLocation = (payload: {
|
||||||
|
scrollX: SocketUpdateDataSource["SCROLL_LOCATION"]["payload"]["scroll"]["x"];
|
||||||
|
scrollY: SocketUpdateDataSource["SCROLL_LOCATION"]["payload"]["scroll"]["y"];
|
||||||
|
}) => {
|
||||||
|
if (this.socket?.id) {
|
||||||
|
const data: SocketUpdateDataSource["SCROLL_LOCATION"] = {
|
||||||
|
type: "SCROLL_LOCATION",
|
||||||
|
payload: {
|
||||||
|
socketId: this.socket.id,
|
||||||
|
scroll: { x: payload.scrollX, y: payload.scrollY },
|
||||||
|
username: this.collab.state.username,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("broadcastScrollLocation data", data);
|
||||||
|
|
||||||
return this._broadcastSocketData(
|
return this._broadcastSocketData(
|
||||||
data as SocketUpdateData,
|
data as SocketUpdateData,
|
||||||
true, // volatile
|
true, // volatile
|
||||||
|
@ -113,6 +113,14 @@ export type SocketUpdateDataSource = {
|
|||||||
username: string;
|
username: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
SCROLL_LOCATION: {
|
||||||
|
type: "SCROLL_LOCATION";
|
||||||
|
payload: {
|
||||||
|
socketId: string;
|
||||||
|
scroll: { x: number; y: number };
|
||||||
|
username: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
IDLE_STATUS: {
|
IDLE_STATUS: {
|
||||||
type: "IDLE_STATUS";
|
type: "IDLE_STATUS";
|
||||||
payload: {
|
payload: {
|
||||||
|
@ -649,6 +649,13 @@ const ExcalidrawWrapper = () => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Excalidraw
|
<Excalidraw
|
||||||
|
// TODO follow-participant
|
||||||
|
// add onZoomChange
|
||||||
|
onScrollChange={(x, y) => {
|
||||||
|
// console.log({ x, y });
|
||||||
|
|
||||||
|
collabAPI?.onScrollChange({ scrollX: x, scrollY: y });
|
||||||
|
}}
|
||||||
ref={excalidrawRefCallback}
|
ref={excalidrawRefCallback}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
initialData={initialStatePromiseRef.current.promise}
|
initialData={initialStatePromiseRef.current.promise}
|
||||||
|
@ -223,6 +223,7 @@ export type AppState = {
|
|||||||
pendingImageElementId: ExcalidrawImageElement["id"] | null;
|
pendingImageElementId: ExcalidrawImageElement["id"] | null;
|
||||||
showHyperlinkPopup: false | "info" | "editor";
|
showHyperlinkPopup: false | "info" | "editor";
|
||||||
selectedLinearElement: LinearElementEditor | null;
|
selectedLinearElement: LinearElementEditor | null;
|
||||||
|
userToFollow: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UIAppState = Omit<
|
export type UIAppState = Omit<
|
||||||
|
Loading…
x
Reference in New Issue
Block a user