diff --git a/css/pixel-editor.scss b/css/pixel-editor.scss index afdccca..8553d5a 100644 --- a/css/pixel-editor.scss +++ b/css/pixel-editor.scss @@ -52,6 +52,7 @@ svg { position: fixed; display:none; box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.64); + background-color:transparent; } #checkerboard { @@ -64,7 +65,7 @@ svg { } #tmp-canvas { - z-index:1; + z-index:3; background:transparent; } diff --git a/js/_changeTool.js b/js/_changeTool.js index e2af449..9b59317 100644 --- a/js/_changeTool.js +++ b/js/_changeTool.js @@ -1,5 +1,8 @@ function changeTool (selectedTool) { - + // Ending any selection in progress + if (currentTool.includes("select") && !selectedTool.includes("select")) { + endSelection(); + } //set tool and temp tje tje tpp; currentTool = selectedTool; currentToolTemp = selectedTool; diff --git a/js/_hotkeyListener.js b/js/_hotkeyListener.js index 1142508..6bdd922 100644 --- a/js/_hotkeyListener.js +++ b/js/_hotkeyListener.js @@ -1,69 +1,75 @@ var spacePressed = false; function KeyPress(e) { - var keyboardEvent = window.event? event : e; - - //if the user is typing in an input field, ignore these hotkeys - if (document.activeElement.tagName == 'INPUT') return; - - //if no document has been created yet, - //orthere is a dialog box open - //ignore hotkeys - if (!documentCreated || dialogueOpen) return; - - // - switch (keyboardEvent.keyCode) { - //pencil tool - 1, b - case 49: case 66: - changeTool('pencil'); - break; - //fill tool - 2, f - case 50: case 70: - changeTool('fill'); - break; - //eyedropper - 3, e - case 51: case 69: - changeTool('eyedropper'); - break; - //pan - 4, p, - case 52: case 80: - changeTool('pan'); - break; - //zoom - 5 - case 53: - changeTool('zoom'); - break; - // eraser -6, r - case 54: case 82: - console.log("Pressed r"); - changeTool('eraser'); - break; - // Rectangular selection - case 77: case 109: - changeTool('rectselect'); - break; - //Z - case 90: - console.log('PRESSED Z ', keyboardEvent.ctrlKey) - //CTRL+ALT+Z redo - if (keyboardEvent.altKey && keyboardEvent.ctrlKey) - redo(); - //CTRL+Z undo - else if (keyboardEvent.ctrlKey) - undo(); - //Z switch to zoom tool - else + var keyboardEvent = window.event? event : e; + + //if the user is typing in an input field, ignore these hotkeys + if (document.activeElement.tagName == 'INPUT') return; + + //if no document has been created yet, + //orthere is a dialog box open + //ignore hotkeys + if (!documentCreated || dialogueOpen) return; + + // + if (e.key === "Escape") { + endSelection(); + changeTool('pencil'); + } + else { + switch (keyboardEvent.keyCode) { + //pencil tool - 1, b + case 49: case 66: + changeTool('pencil'); + break; + //fill tool - 2, f + case 50: case 70: + changeTool('fill'); + break; + //eyedropper - 3, e + case 51: case 69: + changeTool('eyedropper'); + break; + //pan - 4, p, + case 52: case 80: + changeTool('pan'); + break; + //zoom - 5 + case 53: changeTool('zoom'); - break; - //redo - ctrl y - case 89: - if (keyboardEvent.ctrlKey) - redo(); - break; - case 32: - spacePressed=true; - break; - } + break; + // eraser -6, r + case 54: case 82: + console.log("Pressed r"); + changeTool('eraser'); + break; + // Rectangular selection + case 77: case 109: + changeTool('rectselect'); + break; + //Z + case 90: + console.log('PRESSED Z ', keyboardEvent.ctrlKey) + //CTRL+ALT+Z redo + if (keyboardEvent.altKey && keyboardEvent.ctrlKey) + redo(); + //CTRL+Z undo + else if (keyboardEvent.ctrlKey) + undo(); + //Z switch to zoom tool + else + changeTool('zoom'); + break; + //redo - ctrl y + case 89: + if (keyboardEvent.ctrlKey) + redo(); + break; + case 32: + spacePressed=true; + break; + } + } } document.onkeydown = KeyPress; diff --git a/js/_layer.js b/js/_layer.js index 7243be9..7f68915 100644 --- a/js/_layer.js +++ b/js/_layer.js @@ -2,6 +2,9 @@ - move the tmp layer so that it's always right below the active layer - when the move tool is selected (to move a selection), the tmp layer must be put right above the active layer to show a preview + - mouse events will always have at least a canvas target, so evey time there's an event, we'll have to check + the actual element type instead of the current layer and then apply the tool on the currentLayer, not on + the first one in order of z-index */ diff --git a/js/_mouseEvents.js b/js/_mouseEvents.js index ff65a71..2bcb43c 100644 --- a/js/_mouseEvents.js +++ b/js/_mouseEvents.js @@ -15,12 +15,11 @@ window.addEventListener("mousedown", function (mouseEvent) { dragging = true; //left or right click if (mouseEvent.which == 1) { - if (spacePressed) currentTool = 'pan'; else if (mouseEvent.altKey) currentTool = 'eyedropper'; - else if (mouseEvent.target == currentLayer.canvas && (currentTool == 'pencil' || currentTool == 'eraser')) + else if (mouseEvent.target.className == 'drawingCanvas' && (currentTool == 'pencil' || currentTool == 'eraser')) new HistoryStateEditCanvas(); //saveHistoryState({type: 'canvas', canvas: context.getImageData(0, 0, canvasSize[0], canvasSize[1])}); @@ -37,7 +36,7 @@ window.addEventListener("mousedown", function (mouseEvent) { prevEraserSize = eraserSize; } - if (currentTool == 'eyedropper' && mouseEvent.target == currentLayer.canvas) + if (currentTool == 'eyedropper' && mouseEvent.target.className == 'drawingCanvas') eyedropperPreview.style.display = 'block'; return false; @@ -54,7 +53,7 @@ window.addEventListener("mouseup", function (mouseEvent) { if (!documentCreated || dialogueOpen) return; - if (currentTool == 'eyedropper' && mouseEvent.target == currentLayer.canvas) { + if (currentTool == 'eyedropper' && mouseEvent.target.className == 'drawingCanvas') { var cursorLocation = getCursorPosition(mouseEvent); var selectedColor = context.getImageData(Math.floor(cursorLocation[0]/zoom),Math.floor(cursorLocation[1]/zoom),1,1); var newColor = rgbToHex(selectedColor.data[0],selectedColor.data[1],selectedColor.data[2]); @@ -84,10 +83,8 @@ window.addEventListener("mouseup", function (mouseEvent) { } } } - else if (currentTool == 'fill' && mouseEvent.target == currentLayer.canvas) { + else if (currentTool == 'fill' && mouseEvent.target.className == 'drawingCanvas') { console.log('filling') - //if you clicked on anything but the canvas, do nothing - if (!mouseEvent.target == currentLayer.canvas) return; //get cursor postion var cursorLocation = getCursorPosition(mouseEvent); @@ -99,7 +96,7 @@ window.addEventListener("mouseup", function (mouseEvent) { //fill starting at the location fill(cursorLocation); } - else if (currentTool == 'zoom' && mouseEvent.target == canvasView) { + else if (currentTool == 'zoom' && mouseEvent.target.className == 'drawingCanvas') { let mode; if (mouseEvent.which == 1){ mode = "in"; @@ -148,14 +145,14 @@ function draw (mouseEvent) { brushPreview.style.top = cursorLocation[1] + currentLayer.canvas.offsetTop - brushSize * zoom / 2 + 'px'; //hide brush preview outside of canvas / canvas view - if (mouseEvent.target == currentLayer.canvas || mouseEvent.target == canvasView) + if (mouseEvent.target.className == 'drawingCanvas'|| mouseEvent.target.className == 'drawingCanvas') brushPreview.style.visibility = 'visible'; else brushPreview.style.visibility = 'hidden'; //draw line to current pixel if (dragging) { - if (mouseEvent.target == currentLayer.canvas || mouseEvent.target == canvasView) { + if (mouseEvent.target.className == 'drawingCanvas' || mouseEvent.target.className == 'drawingCanvas') { line(Math.floor(lastPos[0]/zoom),Math.floor(lastPos[1]/zoom),Math.floor(cursorLocation[0]/zoom),Math.floor(cursorLocation[1]/zoom)); lastPos = cursorLocation; } @@ -177,14 +174,14 @@ function draw (mouseEvent) { brushPreview.style.top = cursorLocation[1] + canvas.offsetTop - eraserSize * zoom / 2 + 'px'; //hide brush preview outside of canvas / canvas view - if (mouseEvent.target == currentLayer.canvas || mouseEvent.target == canvasView) + if (mouseEvent.target.className == 'drawingCanvas' || mouseEvent.target.className == 'drawingCanvas') brushPreview.style.visibility = 'visible'; else brushPreview.style.visibility = 'hidden'; //draw line to current pixel if (dragging) { - if (mouseEvent.target == currentLayer.canvas || mouseEvent.target == canvasView) { + if (mouseEvent.target.className == 'drawingCanvas' || mouseEvent.target.className == 'drawingCanvas') { line(Math.floor(lastPos[0]/zoom),Math.floor(lastPos[1]/zoom),Math.floor(cursorLocation[0]/zoom),Math.floor(cursorLocation[1]/zoom)); lastPos = cursorLocation; } @@ -198,7 +195,7 @@ function draw (mouseEvent) { layers[i].copyData(layers[0]); } } - else if (currentTool == 'eyedropper' && dragging && mouseEvent.target == currentLayer.canvas) { + else if (currentTool == 'eyedropper' && dragging && mouseEvent.target.className == 'drawingCanvas') { var selectedColor = context.getImageData(Math.floor(cursorLocation[0]/zoom),Math.floor(cursorLocation[1]/zoom),1,1).data; eyedropperPreview.style.borderColor = '#'+rgbToHex(selectedColor[0],selectedColor[1],selectedColor[2]); eyedropperPreview.style.display = 'block'; @@ -256,9 +253,13 @@ function draw (mouseEvent) { } } else if (currentTool == 'moveselection') { - console.log("Aggiorno il cursore"); + // Updating the cursor (move if inside rect, cross if not) updateCursor(); - updateMovePreview(); + + // If I'm dragging, I move the preview + if (dragging && cursorInSelectedArea()) { + updateMovePreview(mouseEvent); + } } } diff --git a/js/_move.js b/js/_move.js index d970200..977a258 100644 --- a/js/_move.js +++ b/js/_move.js @@ -1,5 +1,27 @@ var imageDataToMove; +var canMoveSelection = false; +let lastMousePos; -function updateMovePreview() { - +// TODO: move with arrows +function updateMovePreview(mouseEvent) { + lastMousePos = getCursorPosition(mouseEvent); + // clear the entire tmp layer + TMPLayer.context.clearRect(0, 0, TMPLayer.canvas.width, TMPLayer.canvas.height); + // put the image data with offset + TMPLayer.context.putImageData( + imageDataToMove, + Math.round(lastMousePos[0] / zoom - imageDataToMove.width / 2), + Math.round(lastMousePos[1] / zoom - imageDataToMove.height / 2)); + + moveSelection(lastMousePos[0] / zoom, lastMousePos[1] / zoom, imageDataToMove.width, imageDataToMove.height) +} + +function endSelection() { + TMPLayer.context.clearRect(0, 0, TMPLayer.canvas.width, TMPLayer.canvas.height); + VFXLayer.context.clearRect(0, 0, VFXLayer.canvas.width, VFXLayer.canvas.height); + + currentLayer.context.putImageData( + imageDataToMove, + Math.round(lastMousePos[0] / zoom - imageDataToMove.width / 2), + Math.round(lastMousePos[1] / zoom - imageDataToMove.height / 2)); } \ No newline at end of file diff --git a/js/_newPixel.js b/js/_newPixel.js index 0d47292..5b887e4 100644 --- a/js/_newPixel.js +++ b/js/_newPixel.js @@ -1,4 +1,3 @@ - function newPixel (width, height, palette) { // Setting the current layer currentLayer = new Layer(width, height, canvas); @@ -19,6 +18,7 @@ function newPixel (width, height, palette) { // Adding the first layer and the checkerboard to the list of layers layers.push(VFXLayer); + layers.push(TMPLayer); layers.push(currentLayer); layers.push(checkerBoard); diff --git a/js/_rectSelect.js b/js/_rectSelect.js index e00e18a..8cfa392 100644 --- a/js/_rectSelect.js +++ b/js/_rectSelect.js @@ -4,7 +4,6 @@ let startY; let endX; let endY; let workingLayer; -let imageData; function startRectSelection(mouseEvent) { // Putting the vfx layer on top of everything @@ -14,8 +13,23 @@ function startRectSelection(mouseEvent) { // Saving the start coords of the rect let cursorPos = getCursorPosition(mouseEvent); - startX = Math.floor(cursorPos[0] / zoom) + 0.5; - startY = Math.floor(cursorPos[1] / zoom) + 0.5; + startX = Math.round(cursorPos[0] / zoom) + 0.5; + startY = Math.round(cursorPos[1] / zoom) + 0.5; + + // Avoiding external selections + if (startX < 0) { + startX = 0; + } + else if (startX > currentLayer.canvas.width) { + startX = currentLayer.canvas.width; + } + + if (startY < 0) { + startY = 0; + } + else if (startY > currentLayer.canvas.height) { + startY = currentLayer.canvas.height; + } // Drawing the rect drawRect(startX, startY); @@ -25,19 +39,36 @@ function updateRectSelection(mouseEvent) { let pos = getCursorPosition(mouseEvent); // Drawing the rect - drawRect(Math.floor(pos[0] / zoom) + 0.5, Math.floor(pos[1] / zoom) + 0.5); + drawRect(Math.round(pos[0] / zoom) + 0.5, Math.round(pos[1] / zoom) + 0.5); } function endRectSelection(mouseEvent) { // Getting the end position let currentPos = getCursorPosition(mouseEvent); - endX = currentPos[0] / zoom; - endY = currentPos[1] / zoom; + endX = Math.round(currentPos[0] / zoom); + endY = Math.round(currentPos[1] / zoom); - // Putting the vfx layer behind everything + // Inverting end and start (start must always be the top left corner) + if (endX < startX) { + let tmp = endX; + endX = startX; + startX = tmp; + } + // Same for the y + if (endY < startY) { + let tmp = endY; + endY = startY; + startY = tmp; + } + + // Resetting this isRectSelecting = false; // Getting the selected pixels - imageData = currentLayer.context.createImageData(endX - startX, endY - startY); + imageDataToMove = currentLayer.context.getImageData(startX, startY, endX - startX, endY - startY); + + currentLayer.context.clearRect(startX, startY, endX - startX - 1, endY - startY - 1); + // Moving those pixels from the current layer to the tmp layer + TMPLayer.context.putImageData(imageDataToMove, startX, startY); // Selecting the move tool currentTool = 'moveselection'; @@ -45,23 +76,12 @@ function endRectSelection(mouseEvent) { // Updating the cursor updateCursor(); - // TODO: find out why the imagedata is blank - for (i=0; i