Merge pull request #6 from unsettledgames/master

Added rectangle tool and rectangular selection
This commit is contained in:
Lospec 2020-04-09 21:12:26 -04:00 committed by GitHub
commit a10453c7cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1052 additions and 200 deletions

41
_ext/svg/fullrect.svg Normal file
View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M497,51H15C6.716,51,0,57.716,0,66v380c0,8.284,6.716,15,15,15h482c8.284,0,15-6.716,15-15V66
C512,57.716,505.284,51,497,51z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 695 B

41
_ext/svg/rectangle.svg Normal file
View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M497,51H15C6.716,51,0,57.716,0,66v380c0,8.284,6.716,15,15,15h482c8.284,0,15-6.716,15-15V66
C512,57.716,505.284,51,497,51z M482,431H30V81h452V431z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 719 B

108
_ext/svg/rectselect.svg Normal file
View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M160.003,21.333h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667S165.913,21.333,160.003,21.333z"/>
</g>
</g>
<g>
<g>
<path d="M288.003,21.333h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667S293.913,21.333,288.003,21.333z"/>
</g>
</g>
<g>
<g>
<path d="M160.003,352h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667S165.913,352,160.003,352z"/>
</g>
</g>
<g>
<g>
<path d="M288.003,352h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.888,0,10.667-4.779,10.667-10.667S293.913,352,288.003,352z"/>
</g>
</g>
<g>
<g>
<path d="M32.003,234.667c-5.909,0-10.667,4.779-10.667,10.667V288c0,5.888,4.779,10.667,10.667,10.667S42.67,293.888,42.67,288
v-42.667C42.67,239.445,37.913,234.667,32.003,234.667z"/>
</g>
</g>
<g>
<g>
<path d="M32.003,106.667c-5.909,0-10.667,4.779-10.667,10.667V160c0,5.888,4.779,10.667,10.667,10.667
c5.909,0,10.667-4.779,10.667-10.667v-42.667C42.67,111.445,37.913,106.667,32.003,106.667z"/>
</g>
</g>
<g>
<g>
<path d="M373.337,234.667c-5.888,0-10.667,4.779-10.667,10.667V288c0,5.888,4.779,10.667,10.667,10.667
c5.888,0,10.667-4.779,10.667-10.667v-42.667C384.003,239.445,379.246,234.667,373.337,234.667z"/>
</g>
</g>
<g>
<g>
<path d="M373.337,106.667c-5.909,0-10.667,4.779-10.667,10.667V160c0,5.888,4.779,10.667,10.667,10.667
c5.888,0,10.667-4.779,10.667-10.667v-42.667C384.003,111.445,379.246,106.667,373.337,106.667z"/>
</g>
</g>
<g>
<g>
<path d="M394.67,0h-42.667c-5.888,0-10.667,4.779-10.667,10.667v42.667c0,5.888,4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667V10.667C405.337,4.779,400.579,0,394.67,0z"/>
</g>
</g>
<g>
<g>
<path d="M53.337,0H10.67C4.782,0,0.003,4.779,0.003,10.667v42.667C0.003,59.221,4.782,64,10.67,64h42.667
c5.909,0,10.667-4.779,10.667-10.667V10.667C64.003,4.779,59.246,0,53.337,0z"/>
</g>
</g>
<g>
<g>
<path d="M53.337,330.667H10.67c-5.888,0-10.667,4.779-10.667,10.667V384c0,5.888,4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667v-42.667C64.003,335.445,59.246,330.667,53.337,330.667z"/>
</g>
</g>
<g>
<g>
<path d="M506.521,385.344l-192-106.667c-3.968-2.197-8.875-1.664-12.224,1.323c-3.392,2.987-4.544,7.765-2.859,11.968
l85.333,213.333c1.6,4.011,5.461,6.656,9.771,6.699c0.043,0,0.085,0,0.128,0c4.267,0,8.128-2.539,9.813-6.464l30.315-70.741
l70.741-30.315c3.733-1.6,6.229-5.205,6.443-9.259C512.195,391.168,510.062,387.328,506.521,385.344z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -52,6 +52,7 @@ svg {
position: fixed; position: fixed;
display:none; display:none;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.64); box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.64);
background-color:transparent;
} }
#checkerboard { #checkerboard {
@ -63,6 +64,16 @@ svg {
background:transparent; background:transparent;
} }
#tmp-canvas {
z-index:3;
background:transparent;
}
#vfx-canvas {
z-index:-5000;
background:transparent;
}
#eyedropper-preview { #eyedropper-preview {
position: absolute; position: absolute;
width: 45px; width: 45px;
@ -429,13 +440,15 @@ svg {
#tools-menu li button#pencil-bigger-button, #tools-menu li button#pencil-bigger-button,
#tools-menu li button#zoom-in-button, #tools-menu li button#zoom-in-button,
#tools-menu li button#eraser-bigger-button{ #tools-menu li button#eraser-bigger-button,
#tools-menu li button#rectangle-bigger-button{
left: 0; left: 0;
} }
#tools-menu li button#pencil-smaller-button, #tools-menu li button#pencil-smaller-button,
#tools-menu li button#zoom-out-button, #tools-menu li button#zoom-out-button,
#tools-menu li button#eraser-smaller-button{ #tools-menu li button#eraser-smaller-button,
#tools-menu li button#rectangle-smaller-button{
right: 0; right: 0;
} }
@ -444,7 +457,9 @@ svg {
#tools-menu li.selected button#zoom-in-button, #tools-menu li.selected button#zoom-in-button,
#tools-menu li.selected button#zoom-out-button, #tools-menu li.selected button#zoom-out-button,
#tools-menu li.selected button#eraser-bigger-button, #tools-menu li.selected button#eraser-bigger-button,
#tools-menu li.selected button#eraser-smaller-button{ #tools-menu li.selected button#eraser-smaller-button,
#tools-menu li.selected button#rectangle-bigger-button,
#tools-menu li.selected button#rectangle-smaller-button{
display: block; display: block;
} }

BIN
images/layout.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
images/rectangle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
images/rectselect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -1,5 +1,8 @@
function changeTool (selectedTool) { function changeTool (selectedTool) {
// Ending any selection in progress
if (currentTool.includes("select") && !selectedTool.includes("select") && !selectionCanceled) {
endSelection();
}
//set tool and temp tje tje tpp; //set tool and temp tje tje tpp;
currentTool = selectedTool; currentTool = selectedTool;
currentToolTemp = selectedTool; currentToolTemp = selectedTool;

View File

@ -10,6 +10,7 @@ function clickedColor (e){
//set current color //set current color
currentLayer.context.fillStyle = this.style.backgroundColor; currentLayer.context.fillStyle = this.style.backgroundColor;
currentGlobalColor = this.style.backgroundColor;
//make color selected //make color selected
e.target.parentElement.classList.add('selected'); e.target.parentElement.classList.add('selected');

View File

@ -28,9 +28,6 @@ function colorChanged(e) {
var newColor = hexToRgb(e.target.value); var newColor = hexToRgb(e.target.value);
var oldColor = e.target.oldColor; var oldColor = e.target.oldColor;
console.log('newColor',newColor)
console.log('oldColor',oldColor)
//save undo state //save undo state
//saveHistoryState({type: 'colorchange', newColor: e.target.value, oldColor: rgbToHex(oldColor), canvas: context.getImageData(0, 0, canvasSize[0], canvasSize[1])}); //saveHistoryState({type: 'colorchange', newColor: e.target.value, oldColor: rgbToHex(oldColor), canvas: context.getImageData(0, 0, canvasSize[0], canvasSize[1])});
new HistoryStateEditColor(e.target.value.toLowerCase(), rgbToHex(oldColor)); new HistoryStateEditColor(e.target.value.toLowerCase(), rgbToHex(oldColor));
@ -50,15 +47,14 @@ function colorChanged(e) {
//loop through all colors in palette //loop through all colors in palette
for (var i = 0; i < colors.length; i++) { for (var i = 0; i < colors.length; i++) {
console.log('%c'+newColorHex +' '+ colors[i].jscolor.toString(), colorCheckingStyle)
//if generated color matches this color //if generated color matches this color
if (newColorHex == colors[i].jscolor.toString()) { if (newColorHex == colors[i].jscolor.toString()) {
console.log('%ccolor already exists'+(colors[i].parentElement.classList.contains('jscolor-active')?' (but is the current color)':''), colorCheckingStyle); //console.log('%ccolor already exists'+(colors[i].parentElement.classList.contains('jscolor-active')?' (but is the current color)':''), colorCheckingStyle);
//if the color isnt the one that has the picker currently open //if the color isnt the one that has the picker currently open
if (!colors[i].parentElement.classList.contains('jscolor-active')) { if (!colors[i].parentElement.classList.contains('jscolor-active')) {
console.log('%cColor is duplicate', colorCheckingStyle) //console.log('%cColor is duplicate', colorCheckingStyle)
//show the duplicate color warning //show the duplicate color warning
duplicateColorWarning.style.visibility = 'visible'; duplicateColorWarning.style.visibility = 'visible';
@ -83,13 +79,12 @@ function colorChanged(e) {
//set new old color to changed color //set new old color to changed color
e.target.oldColor = newColor; e.target.oldColor = newColor;
console.log(e.target.colorElement);
//if this is the current color, update the drawing color //if this is the current color, update the drawing color
if (e.target.colorElement.parentElement.classList.contains('selected')) { if (e.target.colorElement.parentElement.classList.contains('selected')) {
console.log('this color is the current color'); //console.log('this color is the current color');
context.fillStyle = '#'+ rgbToHex(newColor.r,newColor.g,newColor.b); context.fillStyle = currentColor;
} }
/* this is wrong and bad /* this is wrong and bad
if (settings.switchToChangedColor) { if (settings.switchToChangedColor) {

2
js/_consts.js Normal file
View File

@ -0,0 +1,2 @@
const MIN_Z_INDEX = -5000;
const MAX_Z_INDEX = 5000;

View File

@ -1,5 +1,5 @@
//draw a line between two points on canvas //draw a line between two points on canvas
function line(x0,y0,x1,y1) { function line(x0,y0,x1,y1, brushSize) {
var dx = Math.abs(x1-x0); var dx = Math.abs(x1-x0);
var dy = Math.abs(y1-y0); var dy = Math.abs(y1-y0);
@ -10,7 +10,7 @@ function line(x0,y0,x1,y1) {
while (true) { while (true) {
//set pixel //set pixel
// If the current tool is the brush // If the current tool is the brush
if (currentTool == 'pencil') { if (currentTool == 'pencil' || currentTool == 'rectangle') {
// I fill the rect // I fill the rect
currentLayer.context.fillRect(x0-Math.floor(brushSize/2), y0-Math.floor(brushSize/2), brushSize, brushSize); currentLayer.context.fillRect(x0-Math.floor(brushSize/2), y0-Math.floor(brushSize/2), brushSize, brushSize);
} else if (currentTool == 'eraser') { } else if (currentTool == 'eraser') {
@ -18,6 +18,34 @@ function line(x0,y0,x1,y1) {
currentLayer.context.clearRect(x0-Math.floor(eraserSize/2), y0-Math.floor(eraserSize/2), eraserSize, eraserSize); currentLayer.context.clearRect(x0-Math.floor(eraserSize/2), y0-Math.floor(eraserSize/2), eraserSize, eraserSize);
} }
//if we've reached the end goal, exit the loop
if ((x0==x1) && (y0==y1)) break;
var e2 = 2*err;
if (e2 >-dy) {err -=dy; x0+=sx;}
if (e2 < dx) {err +=dx; y0+=sy;}
}
}
//draw a line between two points on canvas
function lineOnLayer(x0,y0,x1,y1, brushSize, context) {
var dx = Math.abs(x1-x0);
var dy = Math.abs(y1-y0);
var sx = (x0 < x1 ? 1 : -1);
var sy = (y0 < y1 ? 1 : -1);
var err = dx-dy;
while (true) {
//set pixel
// If the current tool is the brush
if (currentTool == 'pencil' || currentTool == 'rectangle') {
// I fill the rect
context.fillRect(x0-Math.floor(brushSize/2), y0-Math.floor(brushSize/2), brushSize, brushSize);
} else if (currentTool == 'eraser') {
// In case I'm using the eraser I must clear the rect
context.clearRect(x0-Math.floor(eraserSize/2), y0-Math.floor(eraserSize/2), eraserSize, eraserSize);
}
//if we've reached the end goal, exit the loop //if we've reached the end goal, exit the loop
if ((x0==x1) && (y0==y1)) break; if ((x0==x1) && (y0==y1)) break;
var e2 = 2*err; var e2 = 2*err;

View File

@ -2,6 +2,7 @@
function getCursorPosition(e) { function getCursorPosition(e) {
var x; var x;
var y; var y;
if (e.pageX != undefined && e.pageY != undefined) { if (e.pageX != undefined && e.pageY != undefined) {
x = e.pageX; x = e.pageX;
y = e.pageY; y = e.pageY;
@ -14,5 +15,29 @@ function getCursorPosition(e) {
x -= canvas.offsetLeft; x -= canvas.offsetLeft;
y -= canvas.offsetTop; y -= canvas.offsetTop;
return [x,y];
}
// TODO: apply the function below to every getCursorPosition call
// TODO: FIX THIS BELOW
//get cursor position relative to canvas
function getCursorPositionRelative(e, layer) {
var x;
var y;
if (e.pageX != undefined && e.pageY != undefined) {
x = e.pageX;
y = e.pageY;
}
else {
x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
x -= layer.canvas.offsetLeft;
y -= layer.canvas.offsetTop;
return [x,y]; return [x,y];
} }

View File

@ -1,65 +1,86 @@
var spacePressed = false; var spacePressed = false;
function KeyPress(e) { function KeyPress(e) {
var keyboardEvent = window.event? event : e; var keyboardEvent = window.event? event : e;
//if the user is typing in an input field, ignore these hotkeys //if the user is typing in an input field, ignore these hotkeys
if (document.activeElement.tagName == 'INPUT') return; if (document.activeElement.tagName == 'INPUT') return;
//if no document has been created yet, //if no document has been created yet,
//orthere is a dialog box open //orthere is a dialog box open
//ignore hotkeys //ignore hotkeys
if (!documentCreated || dialogueOpen) return; if (!documentCreated || dialogueOpen) return;
// //
switch (keyboardEvent.keyCode) { if (e.key === "Escape") {
//pencil tool - 1, b if (!selectionCanceled) {
case 49: case 66: endSelection();
changeTool('pencil'); changeTool('pencil');
break; }
//fill tool - 2, f }
case 50: case 70: else {
changeTool('fill'); switch (keyboardEvent.keyCode) {
break; //pencil tool - 1, b
//eyedropper - 3, e case 49: case 66:
case 51: case 69: changeTool('pencil');
changeTool('eyedropper'); break;
break; //fill tool - 2, f
//pan - 4, p, m case 50: case 70:
case 52: case 80: case 77: changeTool('fill');
changeTool('pan'); break;
break; //eyedropper - 3, e
//zoom - 5 case 51: case 69:
case 53: changeTool('eyedropper');
changeTool('zoom'); break;
break; //pan - 4, p,
// eraser -6, r case 52: case 80:
case 54: case 82: changeTool('pan');
console.log("Pressed r"); break;
changeTool('eraser'); //zoom - 5
break; case 53:
//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'); changeTool('zoom');
break; break;
//redo - ctrl y // eraser -6, r
case 89: case 54: case 82:
if (keyboardEvent.ctrlKey) console.log("Pressed r");
redo(); changeTool('eraser');
break; break;
case 32: // Rectangular selection
spacePressed=true; case 77: case 109:
break; changeTool('rectselect');
} break;
//Z
case 90:
console.log('PRESSED Z ', keyboardEvent.ctrlKey)
//CTRL+ALT+Z redo
if (keyboardEvent.altKey && keyboardEvent.ctrlKey)
redo();
if (!selectionCanceled) {
endSelection();
changeTool('pencil');
}
//CTRL+Z undo
else if (keyboardEvent.ctrlKey) {
undo();
if (!selectionCanceled) {
endSelection();
changeTool('pencil');
}
}
//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; document.onkeydown = KeyPress;

View File

@ -1,48 +1,61 @@
/** Handler class for a single canvas (a single layer) /** TODO LIST FOR LAYERS
* - move the tmp layer so that it's always right below the active layer
* @param width Canvas width - when the move tool is selected (to move a selection), the tmp layer must be put right above the
* @param height Canvas height active layer to show a preview
* @param canvas HTML canvas element - 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
function Canvas(width, height, canvas) { the first one in order of z-index
this.canvasSize = [width, height], */
this.canvas = canvas,
this.context = this.canvas.getContext("2d"),
// Initializes the canvas /** Handler class for a single canvas (a single layer)
this.initialize = function() { *
var maxHorizontalZoom = Math.floor(window.innerWidth/this.canvasSize[0]*0.75); * @param width Canvas width
var maxVerticalZoom = Math.floor(window.innerHeight/this.canvasSize[1]*0.75); * @param height Canvas height
* @param canvas HTML canvas element
zoom = Math.min(maxHorizontalZoom,maxVerticalZoom); */
if (zoom < 1) zoom = 1; function Layer(width, height, canvas) {
this.canvasSize = [width, height],
//resize canvas this.canvas = canvas,
this.canvas.width = this.canvasSize[0]; this.context = this.canvas.getContext("2d"),
this.canvas.height = this.canvasSize[1]; // Initializes the canvas
this.canvas.style.width = (this.canvas.width*zoom)+'px'; this.initialize = function() {
this.canvas.style.height = (this.canvas.height*zoom)+'px'; var maxHorizontalZoom = Math.floor(window.innerWidth/this.canvasSize[0]*0.75);
var maxVerticalZoom = Math.floor(window.innerHeight/this.canvasSize[1]*0.75);
//unhide canvas
this.canvas.style.display = 'block'; zoom = Math.min(maxHorizontalZoom,maxVerticalZoom);
if (zoom < 1) zoom = 1;
//center canvas in window
this.canvas.style.left = 64+canvasView.clientWidth/2-(this.canvasSize[0]*zoom/2)+'px'; //resize canvas
this.canvas.style.top = 48+canvasView.clientHeight/2-(this.canvasSize[1]*zoom/2)+'px'; this.canvas.width = this.canvasSize[0];
}, this.canvas.height = this.canvasSize[1];
// Resizes canvas this.canvas.style.width = (this.canvas.width*zoom)+'px';
this.resize = function() { this.canvas.style.height = (this.canvas.height*zoom)+'px';
let newWidth = (this.canvas.width * zoom) + 'px';
let newHeight = (this.canvas.height *zoom)+ 'px'; //unhide canvas
this.canvas.style.display = 'block';
this.canvas.style.width = newWidth;
this.canvas.style.height = newHeight; //center canvas in window
}, this.canvas.style.left = 64+canvasView.clientWidth/2-(this.canvasSize[0]*zoom/2)+'px';
// Copies the otherCanvas' position and size this.canvas.style.top = 48+canvasView.clientHeight/2-(this.canvasSize[1]*zoom/2)+'px';
this.copyData = function(otherCanvas) {
this.canvas.style.width = otherCanvas.canvas.style.width; this.context.imageSmoothingEnabled = false;
this.canvas.style.height = otherCanvas.canvas.style.height; this.context.mozImageSmoothingEnabled = false;
},
this.canvas.style.left = otherCanvas.canvas.style.left; // Resizes canvas
this.canvas.style.top = otherCanvas.canvas.style.top; this.resize = function() {
} let newWidth = (this.canvas.width * zoom) + 'px';
let newHeight = (this.canvas.height *zoom)+ 'px';
this.canvas.style.width = newWidth;
this.canvas.style.height = newHeight;
},
// Copies the otherCanvas' position and size
this.copyData = function(otherCanvas) {
this.canvas.style.width = otherCanvas.canvas.style.width;
this.canvas.style.height = otherCanvas.canvas.style.height;
this.canvas.style.left = otherCanvas.canvas.style.left;
this.canvas.style.top = otherCanvas.canvas.style.top;
}
} }

View File

@ -1,6 +1,12 @@
var currentMouseEvent;
// TODO: replace every position calculation with lastMousePos
var lastMousePos;
//mousedown - start drawing //mousedown - start drawing
window.addEventListener("mousedown", function (mouseEvent) { window.addEventListener("mousedown", function (mouseEvent) {
// Saving the event in case something else needs it
currentMouseEvent = mouseEvent;
canDraw = true;
//if no document has been created yet, or this is a dialog open //if no document has been created yet, or this is a dialog open
if (!documentCreated || dialogueOpen) return; if (!documentCreated || dialogueOpen) return;
@ -10,31 +16,43 @@ window.addEventListener("mousedown", function (mouseEvent) {
lastPos = getCursorPosition(mouseEvent); lastPos = getCursorPosition(mouseEvent);
dragging = true; dragging = true;
//left or right click //left or right click ?
if (mouseEvent.which == 1) { if (mouseEvent.which == 1) {
if (spacePressed) if (spacePressed)
currentTool = 'pan'; currentTool = 'pan';
else if (mouseEvent.altKey) else if (mouseEvent.altKey)
currentTool = 'eyedropper'; currentTool = 'eyedropper';
else if (mouseEvent.target == currentLayer.canvas && (currentTool == 'pencil' || currentTool == 'eraser')) else if (mouseEvent.target.className == 'drawingCanvas' &&
(currentTool == 'pencil' || currentTool == 'eraser' || currentTool == 'rectangle'))
new HistoryStateEditCanvas(); new HistoryStateEditCanvas();
else if (currentTool == 'moveselection') {
if (!cursorInSelectedArea()) {
changeTool('pencil');
canDraw = false;
}
}
//saveHistoryState({type: 'canvas', canvas: context.getImageData(0, 0, canvasSize[0], canvasSize[1])}); //saveHistoryState({type: 'canvas', canvas: context.getImageData(0, 0, canvasSize[0], canvasSize[1])});
updateCursor(); updateCursor();
draw(mouseEvent); if (canDraw) {
draw(mouseEvent);
}
} }
else if (currentTool == 'pencil' && mouseEvent.which == 3) { else if (currentTool == 'pencil' && mouseEvent.which == 3) {
currentTool = 'resize-brush'; currentTool = 'resize-brush';
prevBrushSize = brushSize; prevBrushSize = pencilSize;
} }
else if (currentTool == 'eraser' && mouseEvent.which == 3) { else if (currentTool == 'eraser' && mouseEvent.which == 3) {
currentTool = 'resize-eraser'; currentTool = 'resize-eraser';
prevEraserSize = eraserSize; prevEraserSize = eraserSize;
} }
else if (currentTool == 'rectangle' && mouseEvent.which == 3) {
if (currentTool == 'eyedropper' && mouseEvent.target == currentLayer.canvas) currentTool = 'resize-rectangle';
prevRectangleSize = rectangleSize;
}
if (currentTool == 'eyedropper' && mouseEvent.target.className == 'drawingCanvas')
eyedropperPreview.style.display = 'block'; eyedropperPreview.style.display = 'block';
return false; return false;
@ -44,47 +62,45 @@ window.addEventListener("mousedown", function (mouseEvent) {
//mouseup - end drawing //mouseup - end drawing
window.addEventListener("mouseup", function (mouseEvent) { window.addEventListener("mouseup", function (mouseEvent) {
// Saving the event in case something else needs it
currentMouseEvent = mouseEvent;
closeMenu(); closeMenu();
if (!documentCreated || dialogueOpen) return; if (!documentCreated || dialogueOpen) return;
if (currentTool == 'eyedropper' && mouseEvent.target == currentLayer.canvas) { if (currentTool == 'eyedropper' && mouseEvent.target.className == 'drawingCanvas') {
var cursorLocation = getCursorPosition(mouseEvent); var cursorLocation = getCursorPosition(mouseEvent);
var selectedColor = context.getImageData(Math.floor(cursorLocation[0]/zoom),Math.floor(cursorLocation[1]/zoom),1,1); 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]); var newColor = rgbToHex(selectedColor.data[0],selectedColor.data[1],selectedColor.data[2]);
console.log(newColor); currentGlobalColor = "#" + newColor;
var colors = document.getElementsByClassName('color-button'); var colors = document.getElementsByClassName('color-button');
for (var i = 0; i < colors.length; i++) { for (var i = 0; i < colors.length; i++) {
console.log(colors[i].jscolor.toString()); console.log(colors[i].jscolor.toString());
//if picked color matches this color //if picked color matches this color
if (newColor == colors[i].jscolor.toString()) { if (newColor == colors[i].jscolor.toString()) {
console.log('color found'); console.log('color found');
//remove current color selection //remove current color selection
var selectedColor = document.querySelector("#colors-menu li.selected") var selectedColor = document.querySelector("#colors-menu li.selected")
if (selectedColor) selectedColor.classList.remove("selected"); if (selectedColor) selectedColor.classList.remove("selected");
//set current color //set current color
context.fillStyle = '#'+newColor; context.fillStyle = '#'+newColor;
//make color selected //make color selected
colors[i].parentElement.classList.add('selected'); colors[i].parentElement.classList.add('selected');
//hide eyedropper //hide eyedropper
eyedropperPreview.style.display = 'none'; eyedropperPreview.style.display = 'none';
} }
} }
} }
else if (currentTool == 'fill' && mouseEvent.target == currentLayer.canvas) { else if (currentTool == 'fill' && mouseEvent.target.className == 'drawingCanvas') {
console.log('filling') console.log('filling')
//if you clicked on anything but the canvas, do nothing
if (!mouseEvent.target == currentLayer.canvas) return;
//get cursor postion //get cursor postion
var cursorLocation = getCursorPosition(mouseEvent); var cursorLocation = getCursorPosition(mouseEvent);
@ -96,7 +112,7 @@ window.addEventListener("mouseup", function (mouseEvent) {
//fill starting at the location //fill starting at the location
fill(cursorLocation); fill(cursorLocation);
} }
else if (currentTool == 'zoom' && mouseEvent.target == canvasView) { else if (currentTool == 'zoom' && mouseEvent.target.className == 'drawingCanvas') {
let mode; let mode;
if (mouseEvent.which == 1){ if (mouseEvent.which == 1){
mode = "in"; mode = "in";
@ -111,6 +127,12 @@ window.addEventListener("mouseup", function (mouseEvent) {
layers[i].copyData(layers[0]); layers[i].copyData(layers[0]);
} }
} }
else if (currentTool == 'rectselect' && isRectSelecting) {
endRectSelection(mouseEvent);
}
else if (currentTool == 'rectangle') {
endRectDrawing(mouseEvent);
}
dragging = false; dragging = false;
currentTool = currentToolTemp; currentTool = currentToolTemp;
@ -121,10 +143,16 @@ window.addEventListener("mouseup", function (mouseEvent) {
}, false); }, false);
// OPTIMIZABLE: redundant || mouseEvent.target.className in currentTool ifs
//mouse is moving on canvas //mouse is moving on canvas
window.addEventListener("mousemove", draw, false); window.addEventListener("mousemove", draw, false);
function draw (mouseEvent) { function draw (mouseEvent) {
var cursorLocation = getCursorPosition(mouseEvent); lastMousePos = getCursorPosition(mouseEvent);
// Saving the event in case something else needs it
currentMouseEvent = mouseEvent;
var cursorLocation = lastMousePos;
//if a document hasnt yet been created, exit this function //if a document hasnt yet been created, exit this function
if (!documentCreated || dialogueOpen) return; if (!documentCreated || dialogueOpen) return;
@ -133,21 +161,20 @@ function draw (mouseEvent) {
eyedropperPreview.style.display = 'none'; eyedropperPreview.style.display = 'none';
if (currentTool == 'pencil') { if (currentTool == 'pencil') {
//move the brush preview //move the brush preview
brushPreview.style.left = cursorLocation[0] + currentLayer.canvas.offsetLeft - brushSize * zoom / 2 + 'px'; brushPreview.style.left = cursorLocation[0] + currentLayer.canvas.offsetLeft - pencilSize * zoom / 2 + 'px';
brushPreview.style.top = cursorLocation[1] + currentLayer.canvas.offsetTop - brushSize * zoom / 2 + 'px'; brushPreview.style.top = cursorLocation[1] + currentLayer.canvas.offsetTop - pencilSize * zoom / 2 + 'px';
//hide brush preview outside of canvas / canvas view //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'; brushPreview.style.visibility = 'visible';
else else
brushPreview.style.visibility = 'hidden'; brushPreview.style.visibility = 'hidden';
//draw line to current pixel //draw line to current pixel
if (dragging) { 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)); line(Math.floor(lastPos[0]/zoom),Math.floor(lastPos[1]/zoom),Math.floor(cursorLocation[0]/zoom),Math.floor(cursorLocation[1]/zoom), pencilSize);
lastPos = cursorLocation; lastPos = cursorLocation;
} }
} }
@ -168,19 +195,38 @@ function draw (mouseEvent) {
brushPreview.style.top = cursorLocation[1] + canvas.offsetTop - eraserSize * zoom / 2 + 'px'; brushPreview.style.top = cursorLocation[1] + canvas.offsetTop - eraserSize * zoom / 2 + 'px';
//hide brush preview outside of canvas / canvas view //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'; brushPreview.style.visibility = 'visible';
else else
brushPreview.style.visibility = 'hidden'; brushPreview.style.visibility = 'hidden';
//draw line to current pixel //draw line to current pixel
if (dragging) { 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)); line(Math.floor(lastPos[0]/zoom),Math.floor(lastPos[1]/zoom),Math.floor(cursorLocation[0]/zoom),Math.floor(cursorLocation[1]/zoom), eraserSize);
lastPos = cursorLocation; lastPos = cursorLocation;
} }
} }
} }
else if (currentTool == 'rectangle')
{
//move the brush preview
brushPreview.style.left = cursorLocation[0] + currentLayer.canvas.offsetLeft - rectangleSize * zoom / 2 + 'px';
brushPreview.style.top = cursorLocation[1] + currentLayer.canvas.offsetTop - rectangleSize * zoom / 2 + 'px';
//hide brush preview outside of canvas / canvas view
if (mouseEvent.target.className == 'drawingCanvas'|| mouseEvent.target.className == 'drawingCanvas')
brushPreview.style.visibility = 'visible';
else
brushPreview.style.visibility = 'hidden';
if (!isDrawingRect && dragging) {
startRectDrawing(mouseEvent);
}
else if (dragging){
updateRectDrawing(mouseEvent);
}
}
else if (currentTool == 'pan' && dragging) { else if (currentTool == 'pan' && dragging) {
// Setting first layer position // Setting first layer position
setCanvasOffset(layers[0].canvas, layers[0].canvas.offsetLeft + (cursorLocation[0] - lastPos[0]), layers[0].canvas.offsetTop + (cursorLocation[1] - lastPos[1])); setCanvasOffset(layers[0].canvas, layers[0].canvas.offsetLeft + (cursorLocation[0] - lastPos[0]), layers[0].canvas.offsetTop + (cursorLocation[1] - lastPos[1]));
@ -189,8 +235,9 @@ function draw (mouseEvent) {
layers[i].copyData(layers[0]); 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; 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.borderColor = '#'+rgbToHex(selectedColor[0],selectedColor[1],selectedColor[2]);
eyedropperPreview.style.display = 'block'; eyedropperPreview.style.display = 'block';
@ -212,11 +259,11 @@ function draw (mouseEvent) {
var newBrushSize = prevBrushSize + brushSizeChange; var newBrushSize = prevBrushSize + brushSizeChange;
//set the brush to the new size as long as its bigger than 1 //set the brush to the new size as long as its bigger than 1
brushSize = Math.max(1,newBrushSize); pencilSize = Math.max(1,newBrushSize);
//fix offset so the cursor stays centered //fix offset so the cursor stays centered
brushPreview.style.left = lastPos[0] + currentLayer.canvas.offsetLeft - brushSize * zoom / 2 + 'px'; brushPreview.style.left = lastPos[0] + currentLayer.canvas.offsetLeft - pencilSize * zoom / 2 + 'px';
brushPreview.style.top = lastPos[1] + currentLayer.canvas.offsetTop - brushSize * zoom / 2 + 'px'; brushPreview.style.top = lastPos[1] + currentLayer.canvas.offsetTop - pencilSize * zoom / 2 + 'px';
updateCursor(); updateCursor();
} }
@ -237,6 +284,45 @@ function draw (mouseEvent) {
updateCursor(); updateCursor();
} }
else if (currentTool == 'resize-rectangle' && dragging) {
//get new brush size based on x distance from original clicking location
var distanceFromClick = cursorLocation[0] - lastPos[0];
//var roundingAmount = 20 - Math.round(distanceFromClick/10);
//this doesnt work in reverse... because... it's not basing it off of the brush size which it should be
var rectangleSizeChange = Math.round(distanceFromClick/10);
var newRectangleSize = prevRectangleSize + rectangleSizeChange;
//set the brush to the new size as long as its bigger than 1
rectangleSize = Math.max(1,newRectangleSize);
//fix offset so the cursor stays centered
brushPreview.style.left = lastPos[0] + currentLayer.canvas.offsetLeft - rectangleSize * zoom / 2 + 'px';
brushPreview.style.top = lastPos[1] + currentLayer.canvas.offsetTop - rectangleSize * zoom / 2 + 'px';
updateCursor();
}
else if (currentTool == 'rectselect') {
if (dragging && !isRectSelecting && mouseEvent.target.className == 'drawingCanvas') {
isRectSelecting = true;
console.log("cominciata selezione su " + mouseEvent.target.className);
startRectSelection(mouseEvent);
}
else if (dragging && isRectSelecting) {
updateRectSelection(mouseEvent);
}
else if (isRectSelecting) {
endRectSelection();
}
}
else if (currentTool == 'moveselection') {
// Updating the cursor (move if inside rect, cross if not)
updateCursor();
// If I'm dragging, I move the preview
if (dragging && cursorInSelectedArea()) {
updateMovePreview(mouseEvent);
}
}
} }
//mousewheel scrroll //mousewheel scrroll

72
js/_move.js Normal file
View File

@ -0,0 +1,72 @@
var imageDataToMove;
var originalDataPosition;
var canMoveSelection = false;
var lastMovePos;
var selectionCanceled = true;
var firstTimeMove = true;
// TODO: move with arrows
function updateMovePreview(mouseEvent) {
// ISSUE
selectionCanceled = false;
if (firstTimeMove) {
cutSelection(mouseEvent);
}
firstTimeMove = false;
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));
lastMovePos = lastMousePos;
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);
if (imageDataToMove !== undefined) {
let underlyingImageData = currentLayer.context.getImageData(startX, startY, endX - startX, endY - startY);
for (let i=0; i<underlyingImageData.data.length; i+=4) {
let currentMovePixel = [
imageDataToMove.data[i], imageDataToMove.data[i+1],
imageDataToMove.data[i+2], imageDataToMove.data[i+3]
];
let currentUnderlyingPixel = [
underlyingImageData.data[i], underlyingImageData.data[i+1],
underlyingImageData.data[i+2], underlyingImageData.data[i+3]
];
if (isPixelEmpty(currentMovePixel)) {
if (!isPixelEmpty(underlyingImageData)) {
imageDataToMove.data[i] = currentUnderlyingPixel[0];
imageDataToMove.data[i+1] = currentUnderlyingPixel[1];
imageDataToMove.data[i+2] = currentUnderlyingPixel[2];
imageDataToMove.data[i+3] = currentUnderlyingPixel[3];
}
}
}
if (lastMovePos !== undefined) {
currentLayer.context.putImageData(
imageDataToMove,
Math.round(lastMovePos[0] / zoom - imageDataToMove.width / 2),
Math.round(lastMovePos[1] / zoom - imageDataToMove.height / 2));
}
}
selectionCanceled = true;
isRectSelecting = false;
firstTimeMove = true;
imageDataToMove = undefined;
}

View File

@ -1,16 +1,27 @@
function newPixel (width, height, palette) { function newPixel (width, height, palette) {
currentLayer = new Canvas(width, height, canvas); // Setting the current layer
currentLayer = new Layer(width, height, canvas);
currentLayer.initialize(); currentLayer.initialize();
checkerBoard = new Canvas(width, height, checkerBoardCanvas); // Adding the checkerboard behind it
checkerBoard = new Layer(width, height, checkerBoardCanvas);
checkerBoard.initialize(); checkerBoard.initialize();
// Creating the vfx layer on top of everything
VFXLayer = new Layer(width, height, VFXCanvas);
VFXLayer.initialize();
TMPLayer = new Layer(width, height, TMPCanvas);
TMPLayer.initialize();
canvasSize = currentLayer.canvasSize; canvasSize = currentLayer.canvasSize;
// Adding the first layer and the checkerboard to the list of layers
layers.push(VFXLayer);
layers.push(TMPLayer);
layers.push(currentLayer); layers.push(currentLayer);
layers.push(checkerBoard); layers.push(checkerBoard);
//remove current palette //remove current palette
colors = document.getElementsByClassName('color-button'); colors = document.getElementsByClassName('color-button');
while (colors.length > 0) { while (colors.length > 0) {
@ -55,6 +66,7 @@ function newPixel (width, height, palette) {
//set current drawing color as foreground color //set current drawing color as foreground color
currentLayer.context.fillStyle = '#'+defaultForegroundColor; currentLayer.context.fillStyle = '#'+defaultForegroundColor;
currentGlobalColor = '#' + defaultForegroundColor;
selectedPalette = 'none'; selectedPalette = 'none';
} }

View File

@ -0,0 +1,7 @@
function isPixelEmpty(pixel) {
if ((pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 0) || pixel[3] == 0) {
return true;
}
return false;
}

151
js/_rectSelect.js Normal file
View File

@ -0,0 +1,151 @@
var isRectSelecting = false;
let startX;
let startY;
let endX;
let endY;
function startRectSelection(mouseEvent) {
// Saving the canvas
new HistoryStateEditCanvas();
// Putting the vfx layer on top of everything
VFXCanvas.style.zIndex = MAX_Z_INDEX;
// Saving the start coords of the rect
let cursorPos = getCursorPosition(mouseEvent);
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);
selectionCanceled = false;
}
function updateRectSelection(mouseEvent) {
let pos = getCursorPosition(mouseEvent);
// Drawing the rect
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 = Math.round(currentPos[0] / zoom) + 0.5;
endY = Math.round(currentPos[1] / zoom) + 0.5;
// 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;
}
// Selecting the move tool
currentTool = 'moveselection';
currentToolTemp = currentTool;
// Resetting this
isRectSelecting = false;
// Updating the cursor
updateCursor();
}
function cutSelection(mouseEvent) {
console.log("Coordinate: start x, y: " + startX + ", " + startY + " end x, y: " + endX + ", " + endY);
// Getting the selected pixels
imageDataToMove = currentLayer.context.getImageData(startX, startY, endX - startX + 1, endY - startY + 1);
currentLayer.context.clearRect(startX - 0.5, startY - 0.5, endX - startX + 1, endY - startY + 1);
// Moving those pixels from the current layer to the tmp layer
TMPLayer.context.putImageData(imageDataToMove, startX + 1, startY);
//originalDataPosition = [currentPos[0], currentPos[1]];
}
function drawRect(x, y) {
// 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.strokeStyle = "black";
vfxContext.setLineDash([4]);
// Drawing the rect
vfxContext.beginPath();
vfxContext.rect(startX, startY, x - startX, y - startY);
vfxContext.stroke();
// TODO: make the rect blink from black to white in case of dark backgrounds
}
function applyChanges() {
VFXCanvas.style.zIndex = MIN_Z_INDEX;
}
// Checks whether the pointer is inside the selected area or not
function cursorInSelectedArea() {
let cursorPos = getCursorPosition(currentMouseEvent);
let x = cursorPos[0] / zoom;
let y = cursorPos[1] / zoom;
let leftX = Math.min(startX, endX);
let rightX = Math.max(startX, endX);
let topY = Math.max(startY, endY);
let bottomY = Math.min(startY, endY);
if (leftX <= x && x <= rightX) {
if (bottomY <= y && y <= topY) {
return true;
}
return false;
}
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();
}

121
js/_rectangle.js Normal file
View File

@ -0,0 +1,121 @@
var rectangleSize = 1;
var prevRectangleSie = rectangleSize;
var emptySVG = document.getElementById("empty-button-svg");
var fullSVG = document.getElementById("full-button-svg");
var drawMode = 'empty';
var isDrawingRect = false;
let startRectX;
let startRectY;
let endRectX;
let endRectY;
function startRectDrawing(mouseEvent) {
// Putting the vfx layer on top of everything
VFXCanvas.style.zIndex = MAX_Z_INDEX;
// Updating flag
isDrawingRect = true;
// Saving the start coords of the rect
let cursorPos = getCursorPosition(mouseEvent);
startRectX = Math.round(cursorPos[0] / zoom) - 0.5;
startRectY = Math.round(cursorPos[1] / zoom) - 0.5;
drawRectangle(startRectX, startRectY);
}
function updateRectDrawing(mouseEvent) {
let pos = getCursorPosition(mouseEvent);
// Drawing the rect
drawRectangle(Math.round(pos[0] / zoom) + 0.5, Math.round(pos[1] / zoom) + 0.5);
}
function endRectDrawing(mouseEvent) {
// Getting the end position
let currentPos = getCursorPosition(mouseEvent);
let vfxContext = VFXCanvas.getContext("2d");
endRectX = Math.round(currentPos[0] / zoom) + 0.5;
endRectY = Math.round(currentPos[1] / zoom) + 0.5;
// Inverting end and start (start must always be the top left corner)
if (endRectX < startRectX) {
let tmp = endRectX;
endRectX = startRectX;
startRectX = tmp;
}
// Same for the y
if (endRectY < startRectY) {
let tmp = endRectY;
endRectY = startRectY;
startRectY = tmp;
}
let hexColor = hexToRgb(currentLayer.context.fillStyle);
// Resetting this
isDrawingRect = false;
// Drawing the rect
startRectY -= 0.5;
endRectY -= 0.5;
endRectX -= 0.5;
startRectX -= 0.5;
currentLayer.context.lineWidth = rectangleSize;
currentLayer.context.fillStyle = currentGlobalColor;
line(startRectX, startRectY, endRectX, startRectY, rectangleSize);
line(endRectX, startRectY, endRectX, endRectY, rectangleSize);
line(endRectX, endRectY, startRectX, endRectY, rectangleSize);
line(startRectX, endRectY, startRectX, startRectY, rectangleSize);
if (drawMode == 'fill') {
currentLayer.context.fillRect(startRectX, startRectY, endRectX - startRectX, endRectY - startRectY);
}
// Clearing the vfx canvas
vfxContext.clearRect(0, 0, VFXCanvas.width, VFXCanvas.height);
}
function drawRectangle(x, y) {
// Getting the vfx context
let vfxContext = VFXCanvas.getContext("2d");
// Clearing the vfx canvas
vfxContext.clearRect(0, 0, VFXCanvas.width, VFXCanvas.height);
// Drawing the rect
vfxContext.lineWidth = rectangleSize;
vfxContext.strokeStyle = currentGlobalColor;
// Drawing the rect
vfxContext.beginPath();
if ((rectangleSize % 2 ) == 0) {
vfxContext.rect(startRectX - 0.5, startRectY - 0.5, x - startRectX, y - startRectY);
}
else {
vfxContext.rect(startRectX, startRectY, x - startRectX, y - startRectY);
}
vfxContext.setLineDash([]);
vfxContext.stroke();
}
function setRectToolSvg() {
if (drawMode == 'empty') {
emptySVG.setAttribute("display", "visible");
fullSVG.setAttribute("display", "none");
}
else {
emptySVG.setAttribute("display", "none");
fullSVG.setAttribute("display", "visible");
}
}
function applyChanges() {
VFXCanvas.style.zIndex = MIN_Z_INDEX;
}

View File

@ -32,6 +32,36 @@ on('click',"eraser-smaller-button", function(e){
updateCursor(); updateCursor();
}, false); }, false);
// rectangle
on('click',"rectangle-button", function(){
// If the user clicks twice on the button, they change the draw mode
if (currentTool == 'rectangle') {
if (drawMode == 'empty') {
drawMode = 'fill';
setRectToolSvg();
}
else {
drawMode = 'empty';
setRectToolSvg();
}
}
else {
changeTool('rectangle');
}
}, false);
// rectangle bigger
on('click',"rectangle-bigger-button", function(){
rectangleSize++;
updateCursor();
}, false);
// rectangle smaller
on('click',"rectangle-smaller-button", function(e){
if(rectangleSize > 1) rectangleSize--;
updateCursor();
}, false);
//fill //fill
on('click',"fill-button", function(){ on('click',"fill-button", function(){
changeTool('fill'); changeTool('fill');
@ -69,4 +99,9 @@ on('click',"zoom-out-button", function(){
for (let i=1; i<layers.length; i++) { for (let i=1; i<layers.length; i++) {
layers[i].copyData(layers[0]); layers[i].copyData(layers[0]);
} }
}, false);
//rectangular selection button
on('click', "rectselect-button", function(){
changeTool('rectselect');
}, false); }, false);

View File

@ -4,14 +4,32 @@ function updateCursor () {
if (currentTool == 'pencil' || currentTool == 'resize-brush') { if (currentTool == 'pencil' || currentTool == 'resize-brush') {
canvasView.style.cursor = 'crosshair'; canvasView.style.cursor = 'crosshair';
brushPreview.style.display = 'block'; brushPreview.style.display = 'block';
brushPreview.style.width = brushSize * zoom + 'px'; brushPreview.style.width = pencilSize * zoom + 'px';
brushPreview.style.height = brushSize * zoom + 'px'; brushPreview.style.height = pencilSize * zoom + 'px';
} else if (currentTool == 'eraser' || currentTool == 'resize-eraser') { } else if (currentTool == 'eraser' || currentTool == 'resize-eraser') {
canvasView.style.cursor = 'crosshair'; canvasView.style.cursor = 'crosshair';
brushPreview.style.display = 'block'; brushPreview.style.display = 'block';
brushPreview.style.width = eraserSize * zoom + 'px'; brushPreview.style.width = eraserSize * zoom + 'px';
brushPreview.style.height = eraserSize * zoom + 'px'; brushPreview.style.height = eraserSize * zoom + 'px';
} else } else if (currentTool == 'rectangle' || currentTool == 'resize-rectangle') {
canvasView.style.cursor = 'crosshair';
brushPreview.style.display = 'block';
brushPreview.style.width = rectangleSize * zoom + 'px';
brushPreview.style.height = rectangleSize * zoom + 'px';
}
else if (currentTool == 'moveselection') {
if (cursorInSelectedArea()) {
canMoveSelection = true;
canvasView.style.cursor = 'move';
brushPreview.style.display = 'none';
}
else {
canvasView.style.cursor = 'crosshair';
}
}
else if (currentTool == 'rectselect')
canvasView.style.cursor = 'crosshair';
else
brushPreview.style.display = 'none'; brushPreview.style.display = 'none';
if (currentTool == 'eyedropper') { if (currentTool == 'eyedropper') {

File diff suppressed because one or more lines are too long

View File

@ -13,10 +13,12 @@
//=include utilities/rgbToHsl.js //=include utilities/rgbToHsl.js
//=include utilities/hslToRgb.js //=include utilities/hslToRgb.js
//=include libraries/cookies.js //=include libraries/cookies.js
//=include _pixelEditorUtility.js
/**init**/ /**init**/
//=include _consts.js
//=include _variables.js //=include _variables.js
//=include _settings.js //=include _settings.js
@ -42,7 +44,7 @@
//=include _deleteColor.js //=include _deleteColor.js
//=include _replaceAllOfColor.js //=include _replaceAllOfColor.js
//=include _checkerboard.js //=include _checkerboard.js
//=include _canvas.js //=include _layer.js
/**load file**/ /**load file**/
@ -59,6 +61,9 @@
//=include _clickedColor.js //=include _clickedColor.js
//=include _fileMenu.js //=include _fileMenu.js
//=include _createButton.js //=include _createButton.js
//=include _rectSelect.js
//=include _move.js
//=include _rectangle.js
/**onload**/ /**onload**/

41
package-lock.json generated
View File

@ -1220,7 +1220,8 @@
}, },
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true "bundled": true,
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -1238,11 +1239,13 @@
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true "bundled": true,
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -1255,15 +1258,18 @@
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true,
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true "bundled": true,
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true,
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -1366,7 +1372,8 @@
}, },
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true "bundled": true,
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -1376,6 +1383,7 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -1388,17 +1396,20 @@
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true "bundled": true,
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -1415,6 +1426,7 @@
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -1487,7 +1499,8 @@
}, },
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true "bundled": true,
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -1497,6 +1510,7 @@
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -1572,7 +1586,8 @@
}, },
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true "bundled": true,
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -1602,6 +1617,7 @@
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -1619,6 +1635,7 @@
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -1657,11 +1674,13 @@
}, },
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true "bundled": true,
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true "bundled": true,
"optional": true
} }
} }
}, },

View File

@ -1,4 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<!--todo: credit RECTANGULAR SELECTION ICON BY https://www.flaticon.com/authors/pixel-perfect or
design an original icon (this is just a placeholder)
Must also credit this guy for the rectangle tool
Icons made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon"> www.flaticon.com</a>
-->
<html> <html>
<head> <head>
@ -10,7 +16,6 @@
<meta name="ROBOTS" content="NOINDEX, NOFOLLOW"> <meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
{{{google-analytics}}} {{{google-analytics}}}
{{{favicons}}} {{{favicons}}}
</head> </head>
<body oncontextmenu="return false;"> <body oncontextmenu="return false;">
@ -34,7 +39,10 @@
<img src="/pixel-editor/pencil.png" /> <img src="/pixel-editor/pencil.png" />
<img src="/pixel-editor/zoom-in.png" /> <img src="/pixel-editor/zoom-in.png" />
<img src = "/pixel-editor/eraser.png"/> <img src = "/pixel-editor/eraser.png"/>
<img src = "/pixel-editor/rectselect.png"/>
<img src= "/pixel-editor/rectangle.png">
</div> </div>
<ul id="main-menu"> <ul id="main-menu">
<li class="logo">Lospec Pixel Editor</li> <li class="logo">Lospec Pixel Editor</li>
<li> <li>
@ -70,19 +78,32 @@
<button title="Increase Brush Size" id="pencil-bigger-button" class="tools-menu-sub-button">{{svg "plus.svg" width="12" height="12"}}</button> <button title="Increase Brush Size" id="pencil-bigger-button" class="tools-menu-sub-button">{{svg "plus.svg" width="12" height="12"}}</button>
<button title="Decrease Brush Size" id="pencil-smaller-button" class="tools-menu-sub-button">{{svg "minus.svg" width="12" height="12"}}</button> <button title="Decrease Brush Size" id="pencil-smaller-button" class="tools-menu-sub-button">{{svg "minus.svg" width="12" height="12"}}</button>
</li> </li>
<li class = "expanded">
<button title="Eraser tool (R)" id="eraser-button">{{svg "eraser.svg" width="32" height="32"}}</button>
<button title="Increase Eraser Size" id="eraser-bigger-button" class="tools-menu-sub-button">{{svg "plus.svg" width="12" height="12"}}</button>
<button title="Decrease Eraser Size" id="eraser-smaller-button" class="tools-menu-sub-button">{{svg "minus.svg" width="12" height="12"}}</button>
</li>
<li class="expanded">
<button title="Rectangle Tool (U)" id="rectangle-button">{{svg "rectangle.svg" width="32" height="32" id = "empty-button-svg"}}
{{svg "fullrect.svg" width="32" height="32" id = "full-button-svg" display = "none"}}</button>
<button title="Increase Brush Size" id="rectangle-bigger-button" class="tools-menu-sub-button">{{svg "plus.svg" width="12" height="12"}}</button>
<button title="Decrease Brush Size" id="rectangle-smaller-button" class="tools-menu-sub-button">{{svg "minus.svg" width="12" height="12"}}</button>
</li>
<li><button title="Fill Tool (F)" id="fill-button">{{svg "fill.svg" width="32" height="32"}}</button></li> <li><button title="Fill Tool (F)" id="fill-button">{{svg "fill.svg" width="32" height="32"}}</button></li>
<li><button title="Eyedropper Tool (E)" id="eyedropper-button">{{svg "eyedropper.svg" width="32" height="32"}}</button></li> <li><button title="Eyedropper Tool (E)" id="eyedropper-button">{{svg "eyedropper.svg" width="32" height="32"}}</button></li>
<li><button title="Pan Tool (P)" id="pan-button">{{svg "pan.svg" width="32" height="32"}}</button></li> <li><button title="Pan Tool (P)" id="pan-button">{{svg "pan.svg" width="32" height="32"}}</button></li>
<li class="expanded"> <li class="expanded">
<button title="Zoom Tool (Z)" id="zoom-button">{{svg "zoom.svg" width="32" height="32"}}</button> <button title="Zoom Tool (Z)" id="zoom-button">{{svg "zoom.svg" width="32" height="32"}}</button>
<button title="Zoom In" id="zoom-in-button" class="tools-menu-sub-button">{{svg "plus.svg" width="12" height="12"}}</button> <button title="Zoom In" id="zoom-in-button" class="tools-menu-sub-button">{{svg "plus.svg" width="12" height="12"}}</button>
<button title="Zoom Out" id="zoom-out-button" class="tools-menu-sub-button">{{svg "minus.svg" width="12" height="12"}}</button> <button title="Zoom Out" id="zoom-out-button" class="tools-menu-sub-button">{{svg "minus.svg" width="12" height="12"}}</button>
</li> </li>
<li class = "expanded">
<button title="Eraser tool (R)" id="eraser-button">{{svg "eraser.svg" width="32" height="32"}}</button> <li><button title = "Rectangular Selection Tool (M)" id = "rectselect-button">{{svg "rectselect.svg" width = "32" height = "32"}}</button><li>
<button title="Increase Eraser Size" id="eraser-bigger-button" class="tools-menu-sub-button">{{svg "plus.svg" width="12" height="12"}}</button>
<button title="Decrease Eraser Size" id="eraser-smaller-button" class="tools-menu-sub-button">{{svg "minus.svg" width="12" height="12"}}</button>
</li>
</ul> </ul>
<ul id="colors-menu"> <ul id="colors-menu">
@ -98,6 +119,8 @@
<div id="brush-preview"></div> <div id="brush-preview"></div>
<div id="canvas-view"> <div id="canvas-view">
<canvas id="vfx-canvas" class = "drawingCanvas"></canvas>
<canvas id = "tmp-canvas" class = "drawingCanvas"></canvas>
<canvas id="pixel-canvas" class = "drawingCanvas"></canvas> <canvas id="pixel-canvas" class = "drawingCanvas"></canvas>
<canvas id="checkerboard" class = "drawingCanvas"></canvas> <canvas id="checkerboard" class = "drawingCanvas"></canvas>
</div> </div>