You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
395 lines
12 KiB
395 lines
12 KiB
2 years ago
|
class Drawer{
|
||
|
|
||
|
constructor(){
|
||
|
|
||
|
this.dim = {x: 5000, y: 5000};
|
||
|
this.viewport = {
|
||
|
x: (this.dim.x - p.width) / 2,
|
||
|
y: (this.dim.y - p.height) / 2,
|
||
|
maxX: this.dim.x,
|
||
|
maxY: this.dim.y,
|
||
|
scroll: 10,
|
||
|
zoom: 1,
|
||
|
zoomV: 2
|
||
|
};
|
||
|
this.oldMouseX = this.mouseX;
|
||
|
this.oldMouseY = this.mouseY;
|
||
|
this.map = new MiniMap($("#minimap"), "#minimap > canvas", true);
|
||
|
|
||
|
//Free draw
|
||
|
this.lines = [];
|
||
|
this.linesToDraw = [];
|
||
|
this.linesImage = p.createGraphics(this.dim.x, this.dim.y);
|
||
|
this.linesImage.background(255);
|
||
|
|
||
|
//Pixel art
|
||
|
this.pixels = [];
|
||
|
this.pixelsToFill = [];
|
||
|
this.gridPixelsToFill = [];
|
||
|
this.gridActive = false;
|
||
|
this.pixelsImage = p.createGraphics(this.dim.x, this.dim.y);
|
||
|
this.pixelsImage.background(255);
|
||
|
this.gridImage = p.createGraphics(this.dim.x, this.dim.y);
|
||
|
this.gridImage.background(255, 0);
|
||
|
this.gridImage.noStroke();
|
||
|
this.gridImage.fill(0, 255 * 0.1);
|
||
|
this.pixelCount = {x: 1000, y: 1000};
|
||
|
this.pixelSize = {x: this.dim.x / this.pixelCount.x, y: this.dim.y / this.pixelCount.y};
|
||
|
for (let x = 0; x < this.pixelCount.x; x++){
|
||
|
let column = [];
|
||
|
for (let y = 0; y < this.pixelCount.y; y++){
|
||
|
let pixel = {x: x, y: y, c: "#FFFFFF"};
|
||
|
column.push(pixel);
|
||
|
if (x % 2 == 0 && (y + 1) % 2 == 0
|
||
|
|| y % 2 == 0 && (x + 1) % 2 == 0)
|
||
|
this.gridPixelsToFill.push(pixel);
|
||
|
}
|
||
|
this.pixels.push(column);
|
||
|
}
|
||
|
|
||
|
this.isCopying = false;
|
||
|
this.drawType = null;
|
||
|
this.thickness = parseInt($("#thickness").val());
|
||
|
|
||
|
this.pixelsMap = new MiniMap($("#pixels_map_holder"), "#pixels_map_holder > canvas", false);
|
||
|
this.linesMap = new MiniMap($("#lines_map_holder"), "#lines_map_holder > canvas", false);
|
||
|
}
|
||
|
|
||
|
get image(){
|
||
|
if (this.type === 'free') return this.linesImage;
|
||
|
if (this.type === 'pixel') return this.pixelsImage;
|
||
|
}
|
||
|
|
||
|
get scrollSpeed(){
|
||
|
return this.viewport.scroll;
|
||
|
}
|
||
|
|
||
|
get mouseX(){
|
||
|
return p.mouseX * this.viewport.zoom + this.viewport.x;
|
||
|
}
|
||
|
|
||
|
get mouseY(){
|
||
|
return p.mouseY * this.viewport.zoom + this.viewport.y;
|
||
|
}
|
||
|
|
||
|
sendDrawing(){
|
||
|
if (this.isDrawing && this.hasDrawnAllLines && this.hasFilledAllPixels){
|
||
|
|
||
|
if (this.type === 'free'){
|
||
|
let pos1 = {x: p.round(this.oldMouseX), y: p.round(this.oldMouseY)};
|
||
|
let pos2 = {x: p.round(this.mouseX), y: p.round(this.mouseY)};
|
||
|
let color = colorPicker.getColor();
|
||
|
|
||
|
let line = {p1: pos1, p2: pos2, c: color, t: this.thickness};
|
||
|
socket.emit('add-line', line);
|
||
|
}
|
||
|
|
||
|
if (this.type === 'pixel'){
|
||
|
let x = p.floor(this.mouseX / (this.dim.x / this.pixelCount.x));
|
||
|
x = p.constrain(x, 0, this.pixelCount.x);
|
||
|
|
||
|
let y = p.floor(this.mouseY / (this.dim.y / this.pixelCount.y));
|
||
|
y = p.constrain(y, 0, this.pixelCount.y);
|
||
|
|
||
|
let color = colorPicker.getColor();
|
||
|
if (color === this.pixels[x][y].c)
|
||
|
return;
|
||
|
|
||
|
let pixel = {x: x, y: y, c: color};
|
||
|
socket.emit('fill-pixel', pixel);
|
||
|
}
|
||
|
|
||
|
let color = colorPicker.getColor();
|
||
|
if (colorPicker.lastSetUsedColor != color)
|
||
|
colorPicker.setUsed(color);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
draw(){
|
||
|
p.clear();
|
||
|
|
||
|
if (this.hasDrawnAllLines && this.hasFilledAllPixels){
|
||
|
this.moveViewport();
|
||
|
this.map.draw(this.image, this.dim, this.viewport);
|
||
|
|
||
|
|
||
|
let x = this.viewport.x;
|
||
|
let y = this.viewport.y;
|
||
|
let w = p.width * this.viewport.zoom;
|
||
|
let h = p.height * this.viewport.zoom;
|
||
|
p.image(this.image, 0, 0, p.width, p.height, x, y, w, h);
|
||
|
|
||
|
if (this.type === 'pixel' && this.gridActive){
|
||
|
p.image(this.gridImage, 0, 0, p.width, p.height, x, y, w, h);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
this.pixelsMap.draw(this.pixelsImage, this.dim, this.viewport);
|
||
|
this.linesMap.draw(this.linesImage, this.dim, this.viewport);
|
||
|
this.updateProgress();
|
||
|
}
|
||
|
|
||
|
let drawSpeed = 800;
|
||
|
|
||
|
for (let line of this.linesToDraw.slice(0, drawSpeed))
|
||
|
this.drawLine(line);
|
||
|
this.linesToDraw.splice(0, drawSpeed);
|
||
|
if (this.linesToDraw.length === 0 && !this.hasDrawnAllLines && this.receivedLines && this.receivedPixels){
|
||
|
this.hasDrawnAllLines = true;
|
||
|
if (this.hasFilledAllPixels)
|
||
|
$("#loading_drawings").fadeOut(200);
|
||
|
}
|
||
|
|
||
|
for (let pixel of this.pixelsToFill.slice(0, drawSpeed))
|
||
|
this.drawPixel(pixel);
|
||
|
this.pixelsToFill.splice(0, drawSpeed);
|
||
|
if (this.pixelsToFill.length === 0 && !this.hasFilledAllPixels && this.receivedPixels && this.receivedLines){
|
||
|
this.hasFilledAllPixels = true;
|
||
|
if (this.hasDrawnAllLines)
|
||
|
$("#loading_drawings").fadeOut(200);
|
||
|
}
|
||
|
|
||
|
for (let pixel of this.gridPixelsToFill.slice(0, drawSpeed))
|
||
|
this.drawGridPixel(pixel);
|
||
|
this.gridPixelsToFill.splice(0, drawSpeed);
|
||
|
|
||
|
|
||
|
this.oldMouseX = this.mouseX;
|
||
|
this.oldMouseY = this.mouseY;
|
||
|
}
|
||
|
|
||
|
moveViewport(){
|
||
|
if (givesFeedback)
|
||
|
return;
|
||
|
|
||
|
let y = 0, x = 0;
|
||
|
if (p.keyIsDown(40) || p.keyIsDown(83))
|
||
|
y += this.scrollSpeed;
|
||
|
if (p.keyIsDown(38) || p.keyIsDown(87))
|
||
|
y -= this.scrollSpeed;
|
||
|
if (p.keyIsDown(37) || p.keyIsDown(65))
|
||
|
x -= this.scrollSpeed;
|
||
|
if (p.keyIsDown(39) || p.keyIsDown(68))
|
||
|
x += this.scrollSpeed;
|
||
|
|
||
|
this.viewport.x += x;
|
||
|
this.viewport.y += y;
|
||
|
|
||
|
let maxX = this.viewport.maxX - p.width * this.viewport.zoom;
|
||
|
let maxY = this.viewport.maxY - p.height * this.viewport.zoom;
|
||
|
if (this.viewport.x > maxX) this.viewport.x = maxX;
|
||
|
if (this.viewport.y > maxY) this.viewport.y = maxY;
|
||
|
if (this.viewport.x < 0) this.viewport.x = 0;
|
||
|
if (this.viewport.y < 0) this.viewport.y = 0;
|
||
|
|
||
|
if (x != 0 || y != 0)
|
||
|
this.sendDrawing();
|
||
|
}
|
||
|
|
||
|
addAll(lines){
|
||
|
for (let line of lines)
|
||
|
this.addLine(line);
|
||
|
}
|
||
|
|
||
|
drawLine(line){
|
||
|
this.linesImage.strokeWeight(line.t);
|
||
|
this.linesImage.stroke(line.c);
|
||
|
this.linesImage.line(line.p1.x, line.p1.y, line.p2.x, line.p2.y);
|
||
|
}
|
||
|
|
||
|
addLine(line){
|
||
|
this.lines.push(line);
|
||
|
this.linesToDraw.push(line);
|
||
|
}
|
||
|
|
||
|
fillPixel(pixel){
|
||
|
this.pixels[pixel.x][pixel.y].c = pixel.c
|
||
|
this.pixelsToFill.push(pixel);
|
||
|
}
|
||
|
|
||
|
fillAll(pixels){
|
||
|
pixels.forEach(c => {
|
||
|
if (!c) return;
|
||
|
c.forEach(p => {
|
||
|
if (!p) return;
|
||
|
this.fillPixel(p);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
drawPixel(pixel){
|
||
|
let px = pixel.x * this.pixelSize.x;
|
||
|
let py = pixel.y * this.pixelSize.y;
|
||
|
let w = this.pixelSize.x;
|
||
|
let h = this.pixelSize.y;
|
||
|
|
||
|
this.pixelsImage.fill(pixel.c);
|
||
|
this.pixelsImage.strokeWeight(1);
|
||
|
this.pixelsImage.noStroke();
|
||
|
this.pixelsImage.rect(px, py, w, h);
|
||
|
}
|
||
|
|
||
|
drawGridPixel(pixel){
|
||
|
let px = pixel.x * this.pixelSize.x;
|
||
|
let py = pixel.y * this.pixelSize.y;
|
||
|
let w = this.pixelSize.x;
|
||
|
let h = this.pixelSize.y;
|
||
|
|
||
|
this.gridImage.rect(px, py, w, h);
|
||
|
}
|
||
|
|
||
|
onLinesLoaded(lines){
|
||
|
this.receivedLines = lines;
|
||
|
console.log('Received all lines from server');
|
||
|
|
||
|
if (this.receivedPixels)
|
||
|
this.startDrawing();
|
||
|
}
|
||
|
onPixelsLoaded(pixels){
|
||
|
this.receivedPixels = pixels;
|
||
|
console.log('Received all pixels from server');
|
||
|
|
||
|
if (this.receivedLines)
|
||
|
this.startDrawing();
|
||
|
}
|
||
|
startDrawing(){
|
||
|
$("#action").html('Drawing...');
|
||
|
$('#loading_drawings > *:not(#action)').show();
|
||
|
|
||
|
this.receivedPixels.forEach((c, i, a) => {
|
||
|
a[i] = c.filter(p => p.c !== '#ffffff' && p.c !== '#FFFFFF');
|
||
|
});
|
||
|
|
||
|
this.addAll(this.receivedLines);
|
||
|
this.fillAll(this.receivedPixels);
|
||
|
|
||
|
console.log('Started drawing...');
|
||
|
}
|
||
|
|
||
|
updateProgress(){
|
||
|
if (!(this.receivedLines && this.receivedPixels))
|
||
|
return;
|
||
|
let pixelCountDraw = 0;
|
||
|
this.receivedPixels.forEach(c => pixelCountDraw += c.length);
|
||
|
let allThingsToDraw = this.receivedLines.length + pixelCountDraw;
|
||
|
let thingsToDraw = this.pixelsToFill.length + this.linesToDraw.length;
|
||
|
let progress = thingsToDraw / allThingsToDraw;
|
||
|
progress = progress * 100;
|
||
|
progress = isNaN(progress) ? 0 : progress;
|
||
|
$("#loading_drawings > progress").val(progress);
|
||
|
}
|
||
|
|
||
|
isLineVisible(line){
|
||
|
return this.isPointVisible(line.pos1) || this.isPointVisible(line.pos2);
|
||
|
}
|
||
|
isPointVisible(point){
|
||
|
if (!point) return;
|
||
|
let viewX = this.viewport.x;
|
||
|
let viewY = this.viewport.y;
|
||
|
return point.x - viewX > 0 && point.x - viewX < p.width
|
||
|
&& point.y - viewY > 0 && point.y - viewY < p.height
|
||
|
}
|
||
|
|
||
|
onMouseDown(){
|
||
|
if (p.mouseX > 0 && p.mouseX < p.width){
|
||
|
if (this.isCopying){
|
||
|
this.isCopying = false;
|
||
|
$("body").css('cursor', 'default');
|
||
|
} else {
|
||
|
this.isDrawing = true;
|
||
|
this.sendDrawing();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.map.onMouseDown();
|
||
|
}
|
||
|
onMouseUp(){
|
||
|
this.isDrawing = false;
|
||
|
this.map.onMouseUp();
|
||
|
}
|
||
|
onMouseDragged(){
|
||
|
if (this.isDrawing){
|
||
|
this.sendDrawing();
|
||
|
}
|
||
|
|
||
|
|
||
|
this.map.onMouseDragged();
|
||
|
}
|
||
|
onMouseMoved(){
|
||
|
if (this.isCopying){
|
||
|
let vp = this.viewport;
|
||
|
let image = this.image.get(vp.x, vp.y, p.width * vp.zoom, p.height * vp.zoom);
|
||
|
let pixel = image.get(p.mouseX * vp.zoom, p.mouseY * vp.zoom);
|
||
|
colorPicker.updateFromRGB(pixel);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
zoom(delta){
|
||
|
let oldZoom = this.viewport.zoom;
|
||
|
this.viewport.zoom += delta / 100 * this.viewport.zoomV;
|
||
|
if (p.width * this.viewport.zoom > this.dim.x)
|
||
|
this.viewport.zoom = this.dim.x / p.width;
|
||
|
if (p.height * this.viewport.zoom > this.dim.y)
|
||
|
this.viewport.zoom = this.dim.y / height;
|
||
|
if (this.viewport.zoom < 0.1)
|
||
|
this.viewport.zoom = 0.1;
|
||
|
|
||
|
let addZoom = this.viewport.zoom - oldZoom;
|
||
|
this.viewport.x -= addZoom * p.mouseX;
|
||
|
this.viewport.y -= addZoom * p.mouseY;
|
||
|
}
|
||
|
|
||
|
skipDrawing(html){
|
||
|
if (!this.receivedLines || !this.receivedPixels)
|
||
|
return;
|
||
|
|
||
|
$(html).attr('disabled', 'disabled');
|
||
|
|
||
|
setTimeout(() => {
|
||
|
for (let pixel of this.pixelsToFill){
|
||
|
this.drawPixel(pixel);
|
||
|
}
|
||
|
this.pixelsToFill = [];
|
||
|
|
||
|
for (let line of this.linesToDraw){
|
||
|
this.drawLine(line);
|
||
|
}
|
||
|
this.linesToDraw = [];
|
||
|
}, 0);
|
||
|
}
|
||
|
|
||
|
requestServerSave(html){
|
||
|
$(html).attr('disabled', 'disabled');
|
||
|
socket.emit('save-all');
|
||
|
}
|
||
|
|
||
|
answerServerSave(){
|
||
|
console.log('Drawings successfully saved on server');
|
||
|
$('#server_answer').fadeIn(200, 'swing', () => {
|
||
|
setTimeout(() =>
|
||
|
$('#server_answer').fadeOut(200)
|
||
|
, 1000 * 5);
|
||
|
setTimeout(() =>
|
||
|
$('#server_save').attr('disabled', false)
|
||
|
, 1000 * 60 * 5);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function updateDrawType(drawType){
|
||
|
drawer.type = drawType;
|
||
|
if (drawType === 'pixel'){
|
||
|
p.noSmooth();
|
||
|
$("#free_settings").hide();
|
||
|
$('#pixel_settings').show();
|
||
|
}
|
||
|
if (drawType === 'free'){
|
||
|
p.smooth();
|
||
|
$("#free_settings").show();
|
||
|
$('#pixel_settings').hide();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function startCopyColor(){
|
||
|
drawer.isCopying = true;
|
||
|
$("body").css('cursor', 'crosshair');
|
||
|
}
|