game Of Life
This commit is contained in:
128
js/boxes.js
128
js/boxes.js
@@ -1,68 +1,64 @@
|
||||
const socketUrl =
|
||||
(window.location.protocol.startsWith("https") ? "wss://" : "ws://") +
|
||||
window.location.host +
|
||||
"/ws";
|
||||
|
||||
let socket = new WebSocket(socketUrl);
|
||||
|
||||
socket.addEventListener("message", function (event) {
|
||||
if (event.data.startsWith("u:")) {
|
||||
const items = event.data.split(";");
|
||||
items.forEach((i) => {
|
||||
const parts = event.data.split(":");
|
||||
document.getElementById("box-" + parts[1]).checked = parts[2] === "+";
|
||||
console.log("box-" + parts[1]);
|
||||
"use strict";
|
||||
(() => {
|
||||
const socket = getSocket("/boxes/ws");
|
||||
const deserializeBox = (msg) => {
|
||||
msg = msg.replaceAll("b:", "");
|
||||
const parts = msg.split(":");
|
||||
return {
|
||||
id: Number(parts[0]),
|
||||
value: parts[1] === "+",
|
||||
};
|
||||
};
|
||||
const handleInstruction = (instruction) => {
|
||||
if (instruction.startsWith("b:")) {
|
||||
const items = instruction.split(";");
|
||||
items.forEach((i) => {
|
||||
const box = deserializeBox(i);
|
||||
const el = document.getElementById("box-" + box.id);
|
||||
el.checked = box.value;
|
||||
// console.log(i,box,el)
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
socket.addEventListener("message", (event) => {
|
||||
const instructions = event.data.split("\n");
|
||||
instructions.forEach(handleInstruction);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.startsWith("i:")) {
|
||||
const str = event.data.split("i:")[1];
|
||||
const items = str.split(";");
|
||||
if (items.length === 0) {
|
||||
return;
|
||||
}
|
||||
document.querySelectorAll("input").forEach((input) => {
|
||||
input.checked = false;
|
||||
document.querySelectorAll(".boxes input").forEach((input) => {
|
||||
input.addEventListener("change", (event) => {
|
||||
const target = event.target;
|
||||
const id = target?.id.split("-")[1];
|
||||
const value = target.checked ? "+" : "-";
|
||||
socket.send("b:" + id + ":" + value);
|
||||
});
|
||||
});
|
||||
items.forEach((i) => {
|
||||
if (!i) {
|
||||
return;
|
||||
}
|
||||
console.log(i, document.getElementById("box-" + i));
|
||||
document.getElementById("box-" + i).checked = true;
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
socket.send("ping");
|
||||
}, 10000);
|
||||
|
||||
document.querySelectorAll(".boxes input").forEach((input) => {
|
||||
input.addEventListener("change", (event) => {
|
||||
if (socket.readyState !== socket.OPEN) {
|
||||
socket = new WebSocket(socketUrl);
|
||||
}
|
||||
const id = event.target.id.split("-")[1];
|
||||
const value = event.target.checked ? "+" : "-";
|
||||
socket.send("u:" + id + ":" + value);
|
||||
});
|
||||
});
|
||||
|
||||
var timer = null
|
||||
document.querySelector("#auto-boxes").addEventListener("change",(e)=>{
|
||||
if (e.target.checked){
|
||||
timer = setInterval(()=>{
|
||||
var id = Math.round(Math.random() * 1000)
|
||||
const value = document.querySelector('#box-'+id).checked ? "-" : "+";
|
||||
if (socket.readyState !== socket.OPEN) {
|
||||
socket = new WebSocket(socketUrl);
|
||||
}
|
||||
socket.send("u:" + id + ":" + value);
|
||||
},500)
|
||||
}else{
|
||||
clearInterval(timer)
|
||||
}
|
||||
})
|
||||
var autoPlayTimer = undefined;
|
||||
const handleAutoPlay = (el) => {
|
||||
if (el.checked) {
|
||||
autoPlayTimer = setInterval(() => {
|
||||
socket.send("random");
|
||||
}, 50);
|
||||
}
|
||||
else {
|
||||
clearInterval(autoPlayTimer);
|
||||
}
|
||||
};
|
||||
const autoPlayEl = document.querySelector("#auto-boxes");
|
||||
handleAutoPlay(autoPlayEl);
|
||||
autoPlayEl?.addEventListener("change", (e) => handleAutoPlay(e.target));
|
||||
var golTimer = undefined;
|
||||
const handleGol = (el) => {
|
||||
if (el.checked) {
|
||||
golTimer = setInterval(() => {
|
||||
socket.send("gol");
|
||||
}, 500);
|
||||
}
|
||||
else {
|
||||
clearInterval(golTimer);
|
||||
}
|
||||
};
|
||||
const golEl = document.querySelector("#game-of-life");
|
||||
handleGol(golEl);
|
||||
golEl.addEventListener("change", (e) => handleGol(e.target));
|
||||
})();
|
||||
|
||||
80
js/boxes.ts
Normal file
80
js/boxes.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
type CheckboxEl = HTMLInputElement & { checked: boolean; id: string };
|
||||
type Box = {
|
||||
id: number;
|
||||
value: boolean;
|
||||
};
|
||||
|
||||
(() => {
|
||||
const socket = getSocket("/boxes/ws");
|
||||
|
||||
const deserializeBox = (msg: string): Box => {
|
||||
msg = msg.replaceAll("b:", "");
|
||||
const parts = msg.split(":");
|
||||
|
||||
return {
|
||||
id: Number(parts[0]),
|
||||
value: parts[1] === "+",
|
||||
};
|
||||
};
|
||||
|
||||
const handleInstruction = (instruction: string) => {
|
||||
if (instruction.startsWith("b:")) {
|
||||
const items = instruction.split(";");
|
||||
items.forEach((i) => {
|
||||
const box = deserializeBox(i);
|
||||
|
||||
const el = document.getElementById("box-" + box.id) as CheckboxEl;
|
||||
el.checked = box.value;
|
||||
// console.log(i,box,el)
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
socket.addEventListener("message", (event: MessageEvent<string>) => {
|
||||
const instructions = event.data.split("\n");
|
||||
instructions.forEach(handleInstruction);
|
||||
});
|
||||
|
||||
document.querySelectorAll(".boxes input").forEach((input) => {
|
||||
input.addEventListener("change", (event) => {
|
||||
const target = event.target as CheckboxEl;
|
||||
|
||||
const id = target?.id.split("-")[1];
|
||||
const value = target.checked ? "+" : "-";
|
||||
socket.send("b:" + id + ":" + value);
|
||||
});
|
||||
});
|
||||
|
||||
var autoPlayTimer: number | undefined = undefined;
|
||||
const handleAutoPlay = (el: CheckboxEl) => {
|
||||
if (el.checked) {
|
||||
autoPlayTimer = setInterval(() => {
|
||||
socket.send("random");
|
||||
}, 50);
|
||||
} else {
|
||||
clearInterval(autoPlayTimer);
|
||||
}
|
||||
};
|
||||
|
||||
const autoPlayEl = document.querySelector("#auto-boxes") as CheckboxEl;
|
||||
handleAutoPlay(autoPlayEl);
|
||||
autoPlayEl?.addEventListener("change", (e) =>
|
||||
handleAutoPlay(e.target as CheckboxEl)
|
||||
);
|
||||
|
||||
var golTimer: number | undefined = undefined;
|
||||
const handleGol = (el: CheckboxEl) => {
|
||||
if (el.checked) {
|
||||
golTimer = setInterval(() => {
|
||||
socket.send("gol");
|
||||
}, 500);
|
||||
} else {
|
||||
clearInterval(golTimer);
|
||||
}
|
||||
};
|
||||
|
||||
const golEl = document.querySelector("#game-of-life") as CheckboxEl;
|
||||
handleGol(golEl);
|
||||
golEl.addEventListener("change", (e) => handleGol(e.target as CheckboxEl));
|
||||
})();
|
||||
62
js/draw.js
62
js/draw.js
@@ -4,33 +4,20 @@
|
||||
if (!drawElement) {
|
||||
throw new Error("canvas not found");
|
||||
}
|
||||
const drawEmitter = mitt();
|
||||
const emitter = mitt();
|
||||
let drawing = false;
|
||||
const socketUrl = "/draw/ws";
|
||||
let socket = new WebSocket(socketUrl);
|
||||
socket.onerror = console.error;
|
||||
socket.onclose = console.warn;
|
||||
let previous = null;
|
||||
const socket = getSocket("/draw/ws");
|
||||
const serializeDraw = ({ from, to }) => `${from.x},${from.y},${to.x},${to.y}`;
|
||||
const deserializeDraw = (message) => {
|
||||
const parts = message.split(",");
|
||||
return {
|
||||
from: {
|
||||
x: Number(parts[0]),
|
||||
y: Number(parts[1]),
|
||||
},
|
||||
to: {
|
||||
x: Number(parts[2]),
|
||||
y: Number(parts[3]),
|
||||
},
|
||||
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) => {
|
||||
if (socket.readyState !== socket.OPEN) {
|
||||
socket = new WebSocket(socketUrl);
|
||||
}
|
||||
socket.send(serializeDraw(e));
|
||||
};
|
||||
emitter.on("mouseDraw", (e) => sendMessage(e));
|
||||
const sendMessage = (e) => socket.send(serializeDraw(e));
|
||||
const mouseDown = () => {
|
||||
drawing = true;
|
||||
previous = null;
|
||||
@@ -38,12 +25,11 @@
|
||||
const mouseUp = () => {
|
||||
drawing = false;
|
||||
};
|
||||
let previous = null;
|
||||
const mouseMove = (e) => {
|
||||
if (!drawing)
|
||||
return;
|
||||
if (previous) {
|
||||
drawEmitter.emit("draw", {
|
||||
emitter.emit("mouseDraw", {
|
||||
from: previous,
|
||||
to: { x: e.offsetX, y: e.offsetY },
|
||||
});
|
||||
@@ -68,30 +54,26 @@
|
||||
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);
|
||||
const render = (data) => {
|
||||
const { from, to } = data;
|
||||
if (recCtx.strokeStyle != "white") {
|
||||
recCtx.lineWidth = 2;
|
||||
recCtx.lineCap = "round";
|
||||
recCtx.strokeStyle = "white";
|
||||
}
|
||||
recCtx.beginPath();
|
||||
recCtx.moveTo(from.x, from.y);
|
||||
recCtx.lineTo(to.x, to.y);
|
||||
recCtx.closePath();
|
||||
recCtx.stroke();
|
||||
console.log(from, to);
|
||||
};
|
||||
emitter.on("mouseDraw", render);
|
||||
emitter.on("netDraw", render);
|
||||
socket.addEventListener("message", (event) => {
|
||||
if (event.data === "ping" || event.data.startsWith("pong"))
|
||||
return;
|
||||
emitter.emit("netDraw", deserializeDraw(event.data));
|
||||
});
|
||||
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;
|
||||
|
||||
74
js/draw.ts
74
js/draw.ts
@@ -15,58 +15,44 @@
|
||||
to: DrawPoint;
|
||||
};
|
||||
type Events = {
|
||||
draw: DrawEvent;
|
||||
mouseDraw: DrawEvent;
|
||||
netDraw: DrawEvent;
|
||||
};
|
||||
|
||||
const drawEmitter = mitt<Events>();
|
||||
const emitter = mitt<Events>();
|
||||
|
||||
let drawing = false;
|
||||
const socketUrl = "/draw/ws";
|
||||
let previous: DrawPoint | null = null;
|
||||
|
||||
let socket = new WebSocket(socketUrl);
|
||||
const socket = getSocket("/draw/ws");
|
||||
|
||||
socket.onerror = console.error;
|
||||
socket.onclose = console.warn;
|
||||
|
||||
const serializeDraw = ({from, to }: DrawEvent) =>
|
||||
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]),
|
||||
},
|
||||
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));
|
||||
};
|
||||
emitter.on("mouseDraw", (e) => sendMessage(e));
|
||||
const sendMessage = (e: DrawEvent) => socket.send(serializeDraw(e));
|
||||
|
||||
const mouseDown = () => {
|
||||
drawing = true;
|
||||
previous=null
|
||||
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", {
|
||||
emitter.emit("mouseDraw", {
|
||||
from: previous,
|
||||
to: { x: e.offsetX, y: e.offsetY },
|
||||
});
|
||||
@@ -98,36 +84,30 @@
|
||||
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)
|
||||
const render = (data: DrawEvent) => {
|
||||
const { from, to } = data;
|
||||
|
||||
|
||||
|
||||
|
||||
socket.addEventListener("message", (event) => {
|
||||
if(event.data==="ping" || event.data.startsWith('pong')) return
|
||||
const { from, to } = deserializeDraw(event.data);
|
||||
if (recCtx.strokeStyle != "white") {
|
||||
recCtx.lineWidth = 2;
|
||||
recCtx.lineCap = "round";
|
||||
recCtx.strokeStyle = "white";
|
||||
}
|
||||
|
||||
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);
|
||||
emitter.on("mouseDraw", render);
|
||||
emitter.on("netDraw", render);
|
||||
|
||||
socket.addEventListener("message", (event) => {
|
||||
if (event.data === "ping" || event.data.startsWith("pong")) return;
|
||||
emitter.emit("netDraw", deserializeDraw(event.data));
|
||||
});
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
const entry = entries.at(0);
|
||||
|
||||
7
js/ws.js
Normal file
7
js/ws.js
Normal file
@@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
const getSocket = (url) => {
|
||||
let ws = new WebSocket(url);
|
||||
ws.onclose = () => setTimeout(() => (ws = getSocket(url)), 100);
|
||||
ws.onerror = () => ws.close();
|
||||
return ws;
|
||||
};
|
||||
Reference in New Issue
Block a user