fullscreen drawing
This commit is contained in:
committed by
Juraj Kubrican
parent
0505964854
commit
7ed413648c
138
js/draw.ts
Normal file
138
js/draw.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
(() => {
|
||||
const drawElement = document.getElementById(
|
||||
"drawDiv"
|
||||
) as HTMLDivElement | null;
|
||||
if (!drawElement) {
|
||||
throw new Error("canvas not found");
|
||||
}
|
||||
|
||||
type DrawPoint = {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
type DrawEvent = {
|
||||
from: DrawPoint;
|
||||
to: DrawPoint;
|
||||
};
|
||||
type Events = {
|
||||
draw: DrawEvent;
|
||||
};
|
||||
|
||||
const drawEmitter = mitt<Events>();
|
||||
|
||||
let drawing = false;
|
||||
const socketUrl = "/draw/ws";
|
||||
|
||||
let socket = new WebSocket(socketUrl);
|
||||
|
||||
socket.onerror = console.error;
|
||||
socket.onclose = console.warn;
|
||||
|
||||
const serializeDraw = ({from, to }: DrawEvent) =>
|
||||
`${from.x},${from.y},${to.x},${to.y}`;
|
||||
|
||||
const deserializeDraw = (message: string): DrawEvent => {
|
||||
const parts = message.split(",");
|
||||
return {
|
||||
from: {
|
||||
x: Number(parts[0]),
|
||||
y: Number(parts[1]),
|
||||
},
|
||||
to: {
|
||||
x: Number(parts[2]),
|
||||
y: Number(parts[3]),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
drawEmitter.on("draw", (e) => sendMessage(e));
|
||||
const sendMessage = (e: DrawEvent) => {
|
||||
if (socket.readyState !== socket.OPEN) {
|
||||
socket = new WebSocket(socketUrl);
|
||||
}
|
||||
socket.send(serializeDraw(e));
|
||||
};
|
||||
|
||||
const mouseDown = () => {
|
||||
drawing = true;
|
||||
previous=null
|
||||
};
|
||||
|
||||
const mouseUp = () => {
|
||||
drawing = false;
|
||||
};
|
||||
|
||||
let previous: DrawPoint | null = null;
|
||||
const mouseMove = (e: Pick<MouseEvent, "offsetX" | "offsetY">) => {
|
||||
if (!drawing) return;
|
||||
if (previous) {
|
||||
drawEmitter.emit("draw", {
|
||||
from: previous,
|
||||
to: { x: e.offsetX, y: e.offsetY },
|
||||
});
|
||||
}
|
||||
previous = { x: e.offsetX, y: e.offsetY };
|
||||
};
|
||||
|
||||
const touchMove = (e: TouchEvent) => {
|
||||
e.preventDefault();
|
||||
mouseMove({
|
||||
offsetX: e.touches[0].clientX - drawElement.offsetLeft,
|
||||
offsetY: e.touches[0].clientY - drawElement.offsetTop,
|
||||
});
|
||||
};
|
||||
|
||||
drawElement.addEventListener("mousedown", mouseDown);
|
||||
drawElement.addEventListener("mouseup", mouseUp);
|
||||
drawElement.addEventListener("mousemove", mouseMove);
|
||||
|
||||
drawElement.addEventListener("touchstart", mouseDown);
|
||||
drawElement.addEventListener("touchend", mouseUp);
|
||||
drawElement.addEventListener("touchmove", touchMove);
|
||||
|
||||
const receiveCanvas = document.getElementById(
|
||||
"receiveCanvas"
|
||||
) as HTMLCanvasElement | null;
|
||||
const recCtx = receiveCanvas?.getContext("2d");
|
||||
|
||||
if (!recCtx || !receiveCanvas) {
|
||||
throw new Error("canvas not found");
|
||||
}
|
||||
//@ts-expect-error
|
||||
window.ctx = recCtx;
|
||||
|
||||
setTimeout(()=>{
|
||||
recCtx.lineWidth = 2;
|
||||
recCtx.lineCap = "round";
|
||||
recCtx.strokeStyle = "white";
|
||||
},10)
|
||||
|
||||
|
||||
|
||||
|
||||
socket.addEventListener("message", (event) => {
|
||||
if(event.data==="ping" || event.data.startsWith('pong')) return
|
||||
const { from, to } = deserializeDraw(event.data);
|
||||
|
||||
recCtx.beginPath();
|
||||
recCtx.moveTo(from.x, from.y);
|
||||
recCtx.lineTo(to.x, to.y);
|
||||
recCtx.closePath();
|
||||
recCtx.stroke();
|
||||
console.log(from, to);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
if (socket.readyState !== socket.OPEN) {
|
||||
socket = new WebSocket(socketUrl);
|
||||
}
|
||||
socket.send("ping");
|
||||
}, 10000);
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
const entry = entries.at(0);
|
||||
receiveCanvas.height = entry?.contentRect.height ?? 500;
|
||||
receiveCanvas.width = entry?.contentRect.width ?? 500;
|
||||
});
|
||||
resizeObserver.observe(drawElement);
|
||||
})();
|
||||
Reference in New Issue
Block a user