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';
@ -84,12 +80,11 @@ 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') {
@ -25,3 +25,31 @@ function line(x0,y0,x1,y1) {
if (e2 < dx) {err +=dx; y0+=sy;} 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 ((x0==x1) && (y0==y1)) break;
var e2 = 2*err;
if (e2 >-dy) {err -=dy; x0+=sx;}
if (e2 < dx) {err +=dx; y0+=sy;}
}
}

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;
@ -16,3 +17,27 @@ function getCursorPosition(e) {
return [x,y]; 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];
}

View File

@ -12,6 +12,13 @@ function KeyPress(e) {
if (!documentCreated || dialogueOpen) return; if (!documentCreated || dialogueOpen) return;
// //
if (e.key === "Escape") {
if (!selectionCanceled) {
endSelection();
changeTool('pencil');
}
}
else {
switch (keyboardEvent.keyCode) { switch (keyboardEvent.keyCode) {
//pencil tool - 1, b //pencil tool - 1, b
case 49: case 66: case 49: case 66:
@ -25,8 +32,8 @@ function KeyPress(e) {
case 51: case 69: case 51: case 69:
changeTool('eyedropper'); changeTool('eyedropper');
break; break;
//pan - 4, p, m //pan - 4, p,
case 52: case 80: case 77: case 52: case 80:
changeTool('pan'); changeTool('pan');
break; break;
//zoom - 5 //zoom - 5
@ -38,15 +45,28 @@ function KeyPress(e) {
console.log("Pressed r"); console.log("Pressed r");
changeTool('eraser'); changeTool('eraser');
break; break;
// Rectangular selection
case 77: case 109:
changeTool('rectselect');
break;
//Z //Z
case 90: case 90:
console.log('PRESSED Z ', keyboardEvent.ctrlKey) console.log('PRESSED Z ', keyboardEvent.ctrlKey)
//CTRL+ALT+Z redo //CTRL+ALT+Z redo
if (keyboardEvent.altKey && keyboardEvent.ctrlKey) if (keyboardEvent.altKey && keyboardEvent.ctrlKey)
redo(); redo();
if (!selectionCanceled) {
endSelection();
changeTool('pencil');
}
//CTRL+Z undo //CTRL+Z undo
else if (keyboardEvent.ctrlKey) else if (keyboardEvent.ctrlKey) {
undo(); undo();
if (!selectionCanceled) {
endSelection();
changeTool('pencil');
}
}
//Z switch to zoom tool //Z switch to zoom tool
else else
changeTool('zoom'); changeTool('zoom');
@ -61,6 +81,7 @@ function KeyPress(e) {
break; break;
} }
} }
}
document.onkeydown = KeyPress; document.onkeydown = KeyPress;

View File

@ -1,10 +1,20 @@
/** TODO LIST FOR LAYERS
- 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
*/
/** Handler class for a single canvas (a single layer) /** Handler class for a single canvas (a single layer)
* *
* @param width Canvas width * @param width Canvas width
* @param height Canvas height * @param height Canvas height
* @param canvas HTML canvas element * @param canvas HTML canvas element
*/ */
function Canvas(width, height, canvas) { function Layer(width, height, canvas) {
this.canvasSize = [width, height], this.canvasSize = [width, height],
this.canvas = canvas, this.canvas = canvas,
this.context = this.canvas.getContext("2d"), this.context = this.canvas.getContext("2d"),
@ -28,6 +38,9 @@ function Canvas(width, height, canvas) {
//center canvas in window //center canvas in window
this.canvas.style.left = 64+canvasView.clientWidth/2-(this.canvasSize[0]*zoom/2)+'px'; this.canvas.style.left = 64+canvasView.clientWidth/2-(this.canvasSize[0]*zoom/2)+'px';
this.canvas.style.top = 48+canvasView.clientHeight/2-(this.canvasSize[1]*zoom/2)+'px'; this.canvas.style.top = 48+canvasView.clientHeight/2-(this.canvasSize[1]*zoom/2)+'px';
this.context.imageSmoothingEnabled = false;
this.context.mozImageSmoothingEnabled = false;
}, },
// Resizes canvas // Resizes canvas
this.resize = function() { this.resize = function() {

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();
if (canDraw) {
draw(mouseEvent); 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) {
currentTool = 'resize-rectangle';
prevRectangleSize = rectangleSize;
}
if (currentTool == 'eyedropper' && mouseEvent.target == currentLayer.canvas) if (currentTool == 'eyedropper' && mouseEvent.target.className == 'drawingCanvas')
eyedropperPreview.style.display = 'block'; eyedropperPreview.style.display = 'block';
return false; return false;
@ -44,17 +62,19 @@ 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++) {
@ -78,13 +98,9 @@ window.addEventListener("mouseup", function (mouseEvent) {
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,13 +1,24 @@
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);
@ -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');
@ -70,3 +100,8 @@ on('click',"zoom-out-button", function(){
layers[i].copyData(layers[0]); layers[i].copyData(layers[0]);
} }
}, false); }, false);
//rectangular selection button
on('click', "rectselect-button", function(){
changeTool('rectselect');
}, 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') {

View File

@ -4,7 +4,7 @@ var dragging = false;
var lastPos = [0,0]; var lastPos = [0,0];
var currentTool = 'pencil'; var currentTool = 'pencil';
var currentToolTemp = 'pencil'; var currentToolTemp = 'pencil';
var brushSize = 1; var pencilSize = 1;
var eraserSize = 1; var eraserSize = 1;
var prevBrushSize = 1; var prevBrushSize = 1;
var prevEraserSize = 1; var prevEraserSize = 1;
@ -32,9 +32,19 @@ var popUpContainer = document.getElementById("pop-up-container");
// main canvas // main canvas
var canvas = document.getElementById("pixel-canvas"); var canvas = document.getElementById("pixel-canvas");
var context = canvas.getContext("2d"); var context = canvas.getContext("2d");
var currentGlobalColor;
// Layers // Layers
var layers = []; var layers = [];
// Currently selected layer // Currently selected layer
var currentLayer; var currentLayer;
// VFX layer used to draw previews of the selection and things like that
var VFXLayer;
// VFX canvas
var VFXCanvas = document.getElementById("vfx-canvas");
// TMP layer
var TMPLayer;
// TMP canvas
var TMPCanvas = document.getElementById("tmp-canvas");

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>