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'); }