Finished the selection tool

This commit is contained in:
unsettledgames 2020-03-05 16:13:23 +01:00
parent b81e3f36a9
commit f1ae36c54c
9 changed files with 180 additions and 102 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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
*/

View File

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

View File

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

View File

@ -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);

View File

@ -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<imageData.data.length; i++) {
console.log("rgba(" + imageData.data[i] + ',' + imageData.data[i + 1] + ',' + imageData.data[i + 2] + ',' + imageData.data[i + 3] + ')');
}
// NOW
// Select the move tool
// the move tool moves stuff only if the cursor is on the selected area
// the move tool stops working when esc is pressed
// when the move tool is disabled, the control is given to the brush tool
// on click: start dragging
// on drag: render preview by changing the position of the image data and change the position of the selection rect
// IMPORTANT: the image data must be deleted from the original layer
// the image data must be copied to a temporary layer
// the image data is added to the original layer when the move tool is disabled
currentLayer.context.putImageData(imageData, startX, startY);
//currentLayer.context.putImageData(imageData, startX, startY);
}
function drawRect(x, y) {
@ -108,4 +128,25 @@ function cursorInSelectedArea() {
}
return false;
}
function moveSelection(x, y, width, height) {
// Getting the vfx context
let vfxContext = VFXCanvas.getContext("2d");
// Clearing the vfx canvas
vfxContext.clearRect(0, 0, VFXCanvas.width, VFXCanvas.height);
vfxContext.lineWidth = 1;
vfxContext.setLineDash([4]);
startX = Math.round(Math.round(x) - Math.round(width / 2)) + 0.5;
startY = Math.round(Math.round(y) - Math.round(height / 2)) + 0.5;
endX = startX + Math.round(width);
endY = startY + Math.round(height);
// Drawing the rect
vfxContext.beginPath();
vfxContext.rect(startX, startY, width, height);
vfxContext.stroke();
}

View File

@ -13,6 +13,7 @@ function updateCursor () {
brushPreview.style.height = eraserSize * zoom + 'px';
} else if (currentTool == 'moveselection') {
if (cursorInSelectedArea()) {
canMoveSelection = true;
canvasView.style.cursor = 'move';
brushPreview.style.display = 'none';
}