improvements
This commit is contained in:
parent
96f1a447db
commit
7f3d67884d
3 changed files with 98 additions and 59 deletions
|
@ -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>
|
||||||
|
|
144
public/client.js
144
public/client.js
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue