sd-demo-pan / multiplayer.js
victor's picture
victor HF staff
init
3f5af45
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}`;
}
}