PromucFlow_constructor/app/client/src/pages/Editor/Canvas.tsx
Pranav Kanade 7a75d400ab
Feature: Sharing pointers of concurrent editors (#6540)
* updated collab event names

* added a canvas to record the mouse movement

* can show pointers

* temp

* can draw multiple pointers using canvas, moved multiplayer canvas to artboard level

* using constants to draw the cursors on canvas

* can show pointers with different colors

* showing proper username

* added constants for collab events and namespace

* updated the page socket var name

* defined a id constant, and resizing the canvas if needed on window resizing, and then clearing it

* minor refactor

* hide pointer of users leaving the page

* moved our the share pointer func

* defined separate types

* added minor comment

* using requestAnimationFrame to improve performance.

* added connection checks before emitting events. Added mechanism to try to reconnect manually

* using ref to keep animation step id

* updated the way using requestAnimationFrame

* passing pageId as prop to canvas and pointer canvas

* emitting events only if there are more than one realtime editors

* added pageId dependency

* removed unnecessary prop and using reactive state

* remove explicit connection event

* maintaining connection state of page level socket
2021-08-18 15:59:52 +05:30

88 lines
2.5 KiB
TypeScript

import React, { memo, useCallback } from "react";
import store from "store";
import WidgetFactory from "utils/WidgetFactory";
import { RenderModes } from "constants/WidgetConstants";
import { ContainerWidgetProps } from "widgets/ContainerWidget";
import { WidgetProps } from "widgets/BaseWidget";
import PropertyPane from "pages/Editor/PropertyPane";
import ArtBoard from "pages/common/ArtBoard";
import log from "loglevel";
import * as Sentry from "@sentry/react";
import CanvasMultiPointerArena, {
POINTERS_CANVAS_ID,
} from "../common/CanvasMultiPointerArena";
import { throttle } from "lodash";
import { io } from "socket.io-client";
import {
APP_COLLAB_EVENTS,
NAMESPACE_COLLAB_PAGE_EDIT,
} from "constants/AppCollabConstants";
interface CanvasProps {
dsl: ContainerWidgetProps<WidgetProps>;
pageId: string;
}
// This auto connects the socket
const pageEditSocket = io(NAMESPACE_COLLAB_PAGE_EDIT);
const shareMousePointer = (e: any, pageId: string) => {
if (store.getState().ui.appCollab.editors.length < 2) return;
if (pageEditSocket && pageEditSocket.connected) {
const selectionCanvas: any = document.getElementById(POINTERS_CANVAS_ID);
const rect = selectionCanvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
pageEditSocket.emit(APP_COLLAB_EVENTS.SHARE_USER_POINTER, {
data: { x, y },
pageId,
});
} else {
pageEditSocket && pageEditSocket.connect();
}
};
// TODO(abhinav): get the render mode from context
const Canvas = memo((props: CanvasProps) => {
const { pageId } = props;
const delayedShareMousePointer = useCallback(
throttle((e) => shareMousePointer(e, pageId), 50, {
trailing: false,
}),
[shareMousePointer, pageId],
);
try {
return (
<>
<PropertyPane />
<ArtBoard
className="t--canvas-artboard"
data-testid="t--canvas-artboard"
id="art-board"
onMouseMove={(e) => {
e.persist();
delayedShareMousePointer(e);
}}
width={props.dsl.rightColumn}
>
{props.dsl.widgetId &&
WidgetFactory.createWidget(props.dsl, RenderModes.CANVAS)}
<CanvasMultiPointerArena
pageEditSocket={pageEditSocket}
pageId={pageId}
/>
</ArtBoard>
</>
);
} catch (error) {
log.error("Error rendering DSL", error);
Sentry.captureException(error);
return null;
}
});
Canvas.displayName = "Canvas";
export default Canvas;