Spaces:
Running
Running
| import { createClient } from "https://cdn.skypack.dev/@liveblocks/client"; | |
| let PUBLIC_KEY = "pk_test_L8JkCoBm0bYACwp5oOJQsj2n"; | |
| let roomId = "javascript-live-cursors"; | |
| overrideApiKeyAndRoomId(); | |
| if (!/^pk_(live|test)/.test(PUBLIC_KEY)) { | |
| console.warn( | |
| `Replace "${PUBLIC_KEY}" by your public key from https://liveblocks.io/dashboard/apikeys.\n` + | |
| `Learn more: https://github.com/liveblocks/liveblocks/tree/main/examples/javascript-live-cursors#getting-started.` | |
| ); | |
| } | |
| const client = createClient({ | |
| publicApiKey: PUBLIC_KEY, | |
| }); | |
| const room = client.enter(roomId, { initialPresence: { cursor: null } }); | |
| const cursorsContainer = document.getElementById("cursors-container"); | |
| const text = document.getElementById("text"); | |
| room.subscribe("my-presence", (presence) => { | |
| const cursor = presence?.cursor ?? null; | |
| text.innerHTML = cursor | |
| ? `${cursor.x} × ${cursor.y}` | |
| : "Move your cursor to broadcast its position to other people in the room."; | |
| }); | |
| /** | |
| * Subscribe to every others presence updates. | |
| * The callback will be called if you or someone else enters or leaves the room | |
| * or when someone presence is updated | |
| */ | |
| room.subscribe("others", (others, event) => { | |
| switch (event.type) { | |
| case "reset": { | |
| // Clear all cursors | |
| cursorsContainer.innerHTML = ""; | |
| for (const user of others.toArray()) { | |
| updateCursor(user); | |
| } | |
| break; | |
| } | |
| case "leave": { | |
| deleteCursor(event.user); | |
| break; | |
| } | |
| case "enter": | |
| case "update": { | |
| updateCursor(event.user); | |
| break; | |
| } | |
| } | |
| }); | |
| // get mouse position relative to an element | |
| function getMousePosition(event, element) { | |
| const rect = element.getBoundingClientRect(); | |
| return { | |
| x: event.clientX - rect.left, | |
| y: event.clientY - rect.top, | |
| }; | |
| } | |
| // Get mouse position related to a transform and a scale | |
| // function getMousePosition(event, transform, scale) { | |
| // console.log(scale); | |
| // const rect = event.target.getBoundingClientRect(); | |
| // const x = (event.offsetX - transform.x) / scale; | |
| // const y = (event.offsetY - transform.y) / scale; | |
| // return { x, y }; | |
| // } | |
| document.addEventListener("pointermove", (e) => { | |
| e.preventDefault(); | |
| // const { offsetX, offsetY, clientX, clientY } = e; | |
| // console.log(offsetX, offsetY, clientX, clientY); | |
| // console.log(getMousePosition(e, board)); | |
| room.updatePresence({ | |
| cursor: getMousePosition(e, board), | |
| }); | |
| }); | |
| document.addEventListener("pointerleave", (e) => { | |
| room.updatePresence({ cursor: null }); | |
| }); | |
| const COLORS = ["#DC2626", "#D97706", "#059669", "#7C3AED", "#DB2777"]; | |
| // Update cursor position based on user presence | |
| function updateCursor(user) { | |
| const cursor = getCursorOrCreate(user.connectionId); | |
| if (user.presence?.cursor) { | |
| cursor.style.transform = `translateX(${user.presence.cursor.x}px) translateY(${user.presence.cursor.y}px)`; | |
| cursor.style.opacity = "1"; | |
| } else { | |
| cursor.style.opacity = "0"; | |
| } | |
| } | |
| function getCursorOrCreate(connectionId) { | |
| let cursor = document.getElementById(`cursor-${connectionId}`); | |
| if (cursor == null) { | |
| cursor = document.getElementById("cursor-template").cloneNode(true); | |
| cursor.id = `cursor-${connectionId}`; | |
| cursor.style.fill = COLORS[connectionId % COLORS.length]; | |
| cursorsContainer.appendChild(cursor); | |
| } | |
| return cursor; | |
| } | |
| function deleteCursor(user) { | |
| const cursor = document.getElementById(`cursor-${user.connectionId}`); | |
| if (cursor) { | |
| cursor.parentNode.removeChild(cursor); | |
| } | |
| } | |
| /** | |
| * This function is used when deploying an example on liveblocks.io. | |
| * You can ignore it completely if you run the example locally. | |
| */ | |
| function overrideApiKeyAndRoomId() { | |
| const query = new URLSearchParams(window?.location?.search); | |
| const apiKey = query.get("apiKey"); | |
| const roomIdSuffix = query.get("roomId"); | |
| if (apiKey) { | |
| PUBLIC_KEY = apiKey; | |
| } | |
| if (roomIdSuffix) { | |
| roomId = `${roomId}-${roomIdSuffix}`; | |
| } | |
| } | |