The process of setting up a dynamic cursor in ReactFlow with Liveblocks for precise zooming, panning, and compatibility with various screen resolutions

The challenge lies in accurately representing the live cursor's position on other users' screens, which is affected by differences in screen resolutions, zoom levels, and ReactFlow element positioning as a result of individual user interactions. These discrepancies lead to a lack of alignment of the live cursor on remote displays, giving the appearance of being misplaced or misaligned. To ensure smooth collaboration, it is crucial to precisely adjust and synchronize the live cursor's position across all users' screens, taking into account factors such as resolution, zoom levels, and user interactions with ReactFlow elements.

I have successfully tackled this issue by dynamically adjusting the live cursor's position according to the zoom level and the current position of ReactFlow on other users' screens.

Answer №1

// Here is the implementation of the live cursor component:

import { FC, useEffect } from "react";
import { useReactFlow } from "reactflow"
import useLiveBlocksStore from "@/stores/useLiveBlocksStore";
interface LiveCursorProps {
    cursorPos: { x: number, y: number };
}
const LiveCursor: FC<LiveCursorProps> = ({cursorPos }) => {
    const reactFlowInstance = useReactFlow()
    const {
        updateMyPresence,
        liveblocks: { others },
      } = useLiveBlocksStore()

    useEffect(() => {
        const position = reactFlowInstance.project({ x: cursorPos.x, y: cursorPos.y });
        //Method to set the current cursor position using Liveblocks
        updateMyPresence({
            cursor: { x: Math.round(position.x), y: Math.round(position.y) }
        })
    }, [cursorPos])
    return (
        <>
            {
                others.map((other) => {
                    if (other.presence.cursor == null) {
                        return null
                    }
                    // get current Reactflow screen viewPort
                    const otherViewPort = reactFlowInstance.getViewport();

                    let xPos = other.presence.cursor.x * otherViewPort.zoom + otherViewPort.x;
                    let yPos = other.presence.cursor.y * otherViewPort.zoom + otherViewPort.y;

                    return (
                        /* The cursor component takes the x and y coordinates of the cursor 
                        and displays it accurately on other users' screens. */
                    <Cursor key={other.id} x={xPos} y={yPos} />
                    )
                })
            }
        </>
}
export default LiveCursor

Include your component as a child component within the ReactFlow component, ensuring its position is set to absolute.

const [cursorPos, setCurosrPos] = useState({ x: 0, y: 0 })
const handleMouseMove = (event: React.MouseEvent) => {
    setCurosrPos({ x: event.clientX, y: event.clientY });
};
return <div style={{position:"absolute",left:0, top:0, overflowY:"auto", width:"100vw" height:"100vh"}}  >
    <ReactFlow
        fitView
        nodes={nodes}
        edges={edges}
        onMouseMove={handleMouseMove}
    >
        <div style={{zIndex:10,position:"absolute"}} >
            <LiveCursors cursorPos={cursorPos} />
        </div>
    </ReactFlow>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Enhancing Angular Material: requiring more user engagement for rendering to occur

Encountering an unusual issue with Angular Material: certain components require an additional event, like a click or mouse movement on the targeted div, to trigger the actual rendering process. For instance, when loading new rows in mat-table, some empty ...

For editing values that have been dynamically inserted

In my JSON data, there is a variable named address that contains multiple objects (i.e., multiple addresses). I am displaying these multiple addresses as shown in the following image: When clicking on a specific address (e.g., addressType: Business), t ...

JavaScript - Cannot access the 'name' property on an empty object

I am currently following a React tutorial that demonstrates how to create a useForm hook for linking form input to state. Here is the implementation of the hook: const useForm = (initial = {}) => { const [inputs, setInputs] = useState(initial) ...

What is a dynamic route that does not include a slash?

I currently have a Next.js application set up with an SSR component that includes routes like /product1232312321. Previously, my solution was to create two folders: one named product and another nested folder inside it called [id]. Then I would redirect f ...

The useEffect function is repeatedly making API calls within a component, despite not having any dependencies specified

As a newcomer to React.Js, I'm encountering an issue with useEffect repeatedly calling an API without any specified Dependency. Is there another approach I should consider? The relevant file is located at: /pages/dashboard/speaking/[slug].js } else i ...

Issue: Failed to load images while attempting to upload to Supabase

I am currently facing an issue in my next.js app while trying to upload images from a form. Every time I attempt to do so, I encounter the following error message: [Error] Unhandled Promise Rejection: TypeError: Load failed. Unfortunately, the file does no ...

Initiating Next.js

What is the optimal location to initialize my Next JS application? I am currently doing this at the beginning of my _app.tsx component. Will these be configured before getInitialProps runs on the server? // pages/_app.js import axios from 'axios&apos ...

Utilizing TypeScript to spread properties onto a component and destructure them from within components

I'm trying to optimize my use of props spreading and destructuring when working with components. Currently, I spread my props in this manner: <RepositoryItem {...node} /> Then, within the component, I destructure the props like so: interface ...

Set up Admin SDK using appropriate credentials for the given environment

As someone new to Node.js, Firebase Cloud Functions, and TypeScript, my objective is to create a cloud function that acts as an HTTP endpoint for clients to authenticate with Firebase. The desired outcome is for the cloud function to provide a custom acces ...

Filtering the data in the table was successful, but upon searching again, nothing was found. [Using Angular, Pagination, and

Having a table with pagination, I created a function that filters the object and displays the result in the table. The issue arises when I perform a new search. The data from the initial search gets removed and cannot be found in subsequent searches. Bel ...

Filtering an RXJS BehaviorSubject: A step-by-step guide

Looking to apply filtering on data using a BehaviorSubject but encountering some issues: public accounts: BehaviorSubject<any> = new BehaviorSubject(this.list); this.accounts.pipe(filter((poiData: any) => { console.log(poiData) } ...

What is the most efficient way to retrieve a single type from a union that consists of either a single type or an array of types

Is there a way to determine the type of an exported union type by extracting it from an array, as illustrated in the example above? How can this be achieved without directly referencing the non-exported Type itself? interface CurrentType { a: string; b ...

Include quotation marks around a string in C# to convert it into JSON format

I am utilizing a service that operates with JSON format. However, the JSON data I am receiving does not include double quotes around keys and values. Here is an example of the data I have: [{name:{buyerfirstname:Randy, buyermiddlename:null, buyerlastnam ...

There seems to be a console error in Angular 5 when using IE 11

I've developed an Angular 4 application using MVC and Visual Studio 2015. Everything runs smoothly when I access the application on Chrome, but I encounter the following exception on IE 11: XHR error: (404 Not Found) loading http://localhost/src/ma ...

I am currently analyzing a JSON file that contains deeply nested JavaScript Objects. My goal is to rearrange the data so that objects containing a specific field value are placed at the top of the list

Currently, I am parsing a JSON file which contains a map of JavaScript objects. For instance: { offers : { "1":{"id":"1", "category":"a", "offerType":"LS"}, "2":{"id":"2", "category":"a", "offerType":"EX"}, ...

Error: Property 'xxx' is not a valid attribute for this type

Hey there! I recently converted my React Native JavaScript project into TypeScript and everything seems to be working fine. However, I'm encountering some warnings that I could use some help with. Specifically, I need assistance on how to properly pas ...

React-Bootstrap columns are not displaying in a side by side manner and are instead appearing on separate lines

I am currently integrating Bootstrap into my React project alongside Material UI components. Below is a sample of one of my components: import { styled } from "@mui/material/styles"; import Paper from "@mui/material/Paper"; import Cont ...

What is causing these TypeScript type assertions to go unnoticed?

While reviewing type assertions, I noticed something interesting about the last three variable assignments - they don't produce errors. It's perplexing because I thought I was trying to change 'helo' into 'hello', which should ...

Issues arise when Typescript fails to convert an image URL into a base64 encoded string

My current challenge involves converting an image to base 64 format using its URL. This is the method I am currently using: convertToBase64(img) { var canvas = document.createElement("canvas"); canvas.width = img.width; canvas.height = img.he ...

Tips for implementing a cascading dropdown feature in Angular 7 Reactive Formarray: Ensuring saved data loads correctly in the UI form

I recently found a helpful guide on stackoverflow related to creating cascading dropdowns in an Angular reactive FormArray, you can check it out here After following the instructions, I managed to achieve my desired outcome. However, I now face a new chal ...