improvements

This commit is contained in:
sample-text-here 2022-01-07 22:03:43 -08:00
parent 96f1a447db
commit 7f3d67884d
3 changed files with 98 additions and 59 deletions

View file

@ -13,6 +13,6 @@
<body> <body>
<div id="loading">loading...</div> <div id="loading">loading...</div>
<canvas id="canvas"></canvas> <canvas id="canvas"></canvas>
<div id="bottom"><div id="picker"></div></div> <div id="bottom"><div id="picker"></div><div id="status">loading</div></div>
</body> </body>
</html> </html>

View file

@ -1,9 +1,11 @@
const $ = e => document.getElementById(e); const $ = e => document.getElementById(e);
const setStatus = str => $("status").innerText = str;
const socket = io(); const socket = io();
const size = 15000;
class Drawer { class Drawer {
constructor() { constructor() {
this.canvas = new OffscreenCanvas(1e4, 1e4); this.canvas = new OffscreenCanvas(size, size);
this.ctx = this.canvas.getContext("2d"); this.ctx = this.canvas.getContext("2d");
this.history = []; this.history = [];
this.pens = new Map(); this.pens = new Map();
@ -33,15 +35,20 @@ class Drawer {
this.ctx.lineWidth = pen.stroke; this.ctx.lineWidth = pen.stroke;
this.ctx.stroke(pen.path); this.ctx.stroke(pen.path);
} }
} }
render() { render() {
this.ctx.clearRect(0, 0, 1e9, 1e9); this.ctx.clearRect(0, 0, size, size);
for(let event of this.history) this.chain(event); for(let event of this.history) this.chain(event);
} }
add(event) { add(event) {
for(let i = this.history.length - 1; i > 0; i--) {
if(this.history[i].id === event.id) {
if(!this.history[i].save) this.history.splice(i, 1);
break;
}
}
this.history.push(event); this.history.push(event);
this.chain(event); this.chain(event);
} }
@ -52,7 +59,7 @@ class Renderer {
this.drawer = new Drawer(); this.drawer = new Drawer();
this.canvas = canvas; this.canvas = canvas;
this.ctx = canvas.getContext("2d"); this.ctx = canvas.getContext("2d");
this.pan = [0, 0]; this.pan = [size/-2, size/-2];
this.resize(); this.resize();
} }
@ -61,7 +68,7 @@ class Renderer {
this.canvas.width = window.innerWidth; this.canvas.width = window.innerWidth;
this.ctx.height = window.innerHeight; this.ctx.height = window.innerHeight;
this.ctx.width = window.innerWidth; this.ctx.width = window.innerWidth;
this.ctx.clearRect(0, 0, 99999, 99999); this.ctx.clearRect(0, 0, size, size);
this.render(); this.render();
} }
@ -113,6 +120,7 @@ class ColorSelection {
} }
} }
const cursor = { pressed: false, x: 0, y: 0 };
const renderer = new Renderer($("canvas")); const renderer = new Renderer($("canvas"));
const colors = new ColorSelection($("picker")); const colors = new ColorSelection($("picker"));
colors.addAll([ colors.addAll([
@ -127,54 +135,73 @@ colors.addAll([
colors.random(); colors.random();
colors.add("white"); colors.add("white");
let pressed = false; function parseType(e) {
function mousedown(e) { switch(e.type) {
e = e.clientX ? e : e.touches?.[0]; case "mousedown":
if(!e) return; case "touchstart":
pressed = true; return "drawstart";
if(e.which !== 1) return; case "mousemove":
const event = { case "touchmove":
type: "drawstart", return "drawmove";
x: e.clientX - renderer.pan[0], case "mouseup":
y: e.clientY - renderer.pan[1], case "touchend":
color: colors.color, return "drawend";
stroke: colors.color === "white" ? 30 : 5,
};
renderer.add(event);
socket.emit("draw", event);
}
function mousemove(e) {
if(!pressed) return;
e = e.clientX ? e : e.touches?.[0];
if(!e) return;
if(e.which !== 1) {
renderer.pan[0] += e.movementX;
renderer.pan[1] += e.movementY;
renderer.render();
return;
} }
const event = {
type: "drawmove",
x: e.clientX - renderer.pan[0],
y: e.clientY - renderer.pan[1],
};
renderer.add(event);
socket.emit("draw", event);
} }
function mouseup(e) { function parseCoords(e) {
e = e.clientX ? e : e.touches?.[0]; const norm = e.clientX ? e : e.touches?.[0];
if(!e) return; if(!norm) return null;
pressed = false; return { x: norm.clientX, y: norm.clientY };
if(e.which !== 1) return; }
const event = {
type: "drawend", function parseDrawEvent(coords, type) {
x: e.clientX - renderer.pan[0], if(type === "drawstart") {
y: e.clientY - renderer.pan[1], if(cursor.pressed) return null;
}; return {
renderer.add(event); type,
socket.emit("draw", event); save: true,
x: coords.x - renderer.pan[0],
y: coords.y - renderer.pan[1],
color: colors.color,
stroke: colors.color === "white" ? 30 : 5,
};
} else {
if(!cursor.pressed) return null;
return {
type,
save: true,
x: coords.x - renderer.pan[0],
y: coords.y - renderer.pan[1],
};
}
}
function handle(e) {
const coords = parseCoords(e);
if(!coords) return;
const type = parseType(e);
if(e.which === 1) {
setStatus("drawing");
const event = parseDrawEvent(coords, type);
if(!event) return;
renderer.add(event);
socket.emit("draw", event);
} else if(cursor.pressed && e.which === 2) {
setStatus("panning");
renderer.pan[0] += coords.x - cursor.x;
renderer.pan[1] += coords.y - cursor.y;
renderer.render();
}
if(type === "drawstart") cursor.pressed = true;
if(type === "drawend") {
setStatus("ready");
cursor.pressed = false;
}
cursor.x = coords.x;
cursor.y = coords.y;
} }
socket.on("draw", (event) => { socket.on("draw", (event) => {
@ -185,6 +212,7 @@ socket.on("draw", (event) => {
socket.on("sync", (data) => { socket.on("sync", (data) => {
renderer.addAll(data); renderer.addAll(data);
if($("loading")) $("loading").remove(); if($("loading")) $("loading").remove();
setStatus("ready");
}); });
socket.on("connect", () => { socket.on("connect", () => {
@ -192,12 +220,12 @@ socket.on("connect", () => {
}); });
const canvas = $("canvas"); const canvas = $("canvas");
canvas.addEventListener("mousedown", mousedown); canvas.addEventListener("mousedown", handle);
canvas.addEventListener("mouseup", mouseup); canvas.addEventListener("mouseup", handle);
canvas.addEventListener("mousemove", mousemove); canvas.addEventListener("mousemove", handle);
canvas.addEventListener("touchstart", mousedown); canvas.addEventListener("touchstart", handle);
canvas.addEventListener("touchmove", mousemove); canvas.addEventListener("touchmove", handle);
canvas.addEventListener("touchend", mouseup); canvas.addEventListener("touchend", handle);
canvas.addEventListener("touchcancel", mouseup); canvas.addEventListener("touchcancel", handle);
window.addEventListener("resize", renderer.resize); window.addEventListener("resize", () => renderer.resize());

View file

@ -10,6 +10,7 @@ body {
#bottom { #bottom {
position: fixed; position: fixed;
display: flex;
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 100%;
@ -18,6 +19,10 @@ body {
padding: 8px; padding: 8px;
} }
#picker {
flex: 1;
}
#picker button { #picker button {
height: 2em; height: 2em;
width: 2em; width: 2em;
@ -33,6 +38,12 @@ body {
transform: scale(0.8); transform: scale(0.8);
} }
#status {
flex: 0;
display: flex;
align-items: center;
}
#loading { #loading {
z-index: 9999; z-index: 9999;
position: fixed; position: fixed;