mirror of
https://github.com/lospec/pixel-editor.git
synced 2023-08-10 21:12:51 +03:00
Added back fill tool
This commit is contained in:
@ -3,9 +3,11 @@ const ToolManager = (() => {
|
|||||||
eraserTool = new EraserTool("eraser", {type: 'html'}, switchTool);
|
eraserTool = new EraserTool("eraser", {type: 'html'}, switchTool);
|
||||||
rectangleTool = new RectangleTool("rectangle", {type: 'html'}, switchTool);
|
rectangleTool = new RectangleTool("rectangle", {type: 'html'}, switchTool);
|
||||||
lineTool = new LineTool("line", {type: 'html'}, switchTool);
|
lineTool = new LineTool("line", {type: 'html'}, switchTool);
|
||||||
|
fillTool = new FillTool("fill", {type: 'cursor', pic: 'fill.png'}, switchTool);
|
||||||
|
|
||||||
currTool = brushTool;
|
currTool = brushTool;
|
||||||
currTool.onSelect();
|
currTool.onSelect();
|
||||||
|
canvasView.style.cursor = 'default';
|
||||||
|
|
||||||
Events.on("mouseup", window, onMouseUp);
|
Events.on("mouseup", window, onMouseUp);
|
||||||
Events.on("mousemove", window, onMouseMove);
|
Events.on("mousemove", window, onMouseMove);
|
||||||
@ -20,7 +22,7 @@ const ToolManager = (() => {
|
|||||||
switch(mouseEvent.which) {
|
switch(mouseEvent.which) {
|
||||||
case 1:
|
case 1:
|
||||||
if (!Input.isDragging()) {
|
if (!Input.isDragging()) {
|
||||||
currTool.onStart(mousePos);
|
currTool.onStart(mousePos, mouseEvent.target);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
|
111
js/_fill.js
111
js/_fill.js
@ -1,111 +0,0 @@
|
|||||||
// REFACTOR: fill tool onMouseDown
|
|
||||||
function fill(cursorLocation) {
|
|
||||||
|
|
||||||
//changes a pixels color
|
|
||||||
function colorPixel(tempImage, pixelPos, fillColor) {
|
|
||||||
//console.log('colorPixel:',pixelPos);
|
|
||||||
tempImage.data[pixelPos] = fillColor.r;
|
|
||||||
tempImage.data[pixelPos + 1] = fillColor.g;
|
|
||||||
tempImage.data[pixelPos + 2] = fillColor.b;
|
|
||||||
tempImage.data[pixelPos + 3] = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
//change x y to color value passed from the function and use that as the original color
|
|
||||||
function matchStartColor(tempImage, pixelPos, color) {
|
|
||||||
//console.log('matchPixel:',x,y)
|
|
||||||
|
|
||||||
var r = tempImage.data[pixelPos];
|
|
||||||
var g = tempImage.data[pixelPos + 1];
|
|
||||||
var b = tempImage.data[pixelPos + 2];
|
|
||||||
var a = tempImage.data[pixelPos + 3];
|
|
||||||
//console.log(r == color[0] && g == color[1] && b == color[2]);
|
|
||||||
return (r == color[0] && g == color[1] && b == color[2] && a == color[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//save history state
|
|
||||||
new HistoryState().EditCanvas();
|
|
||||||
//saveHistoryState({type: 'canvas', canvas: context.getImageData(0, 0, canvasSize[0], canvasSize[1])});
|
|
||||||
//console.log('filling at '+ Math.floor(cursorLocation[0]/zoom) + ','+ Math.floor(cursorLocation[1]/zoom));
|
|
||||||
|
|
||||||
//temporary image holds the data while we change it
|
|
||||||
var tempImage = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]);
|
|
||||||
|
|
||||||
//this is an array that holds all of the pixels at the top of the cluster
|
|
||||||
var topmostPixelsArray = [[Math.floor(cursorLocation[0]/zoom), Math.floor(cursorLocation[1]/zoom)]];
|
|
||||||
//console.log('topmostPixelsArray:',topmostPixelsArray)
|
|
||||||
|
|
||||||
//the offset of the pixel in the temp image data to start with
|
|
||||||
var startingPosition = (topmostPixelsArray[0][1] * canvasSize[0] + topmostPixelsArray[0][0]) * 4;
|
|
||||||
|
|
||||||
//the color of the cluster that is being filled
|
|
||||||
var clusterColor = [tempImage.data[startingPosition],tempImage.data[startingPosition+1],tempImage.data[startingPosition+2], tempImage.data[startingPosition+3]];
|
|
||||||
|
|
||||||
//the new color to fill with
|
|
||||||
var fillColor = Color.hexToRgb(currentLayer.context.fillStyle);
|
|
||||||
|
|
||||||
//if you try to fill with the same color that's already there, exit the function
|
|
||||||
if (clusterColor[0] == fillColor.r &&
|
|
||||||
clusterColor[1] == fillColor.g &&
|
|
||||||
clusterColor[2] == fillColor.b &&
|
|
||||||
clusterColor[3] != 0) {
|
|
||||||
console.log("Returned");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//loop until there are no more values left in this array
|
|
||||||
while (topmostPixelsArray.length) {
|
|
||||||
var reachLeft, reachRight;
|
|
||||||
|
|
||||||
//move the most recent pixel from the array and set it as our current working pixels
|
|
||||||
var currentPixel = topmostPixelsArray.pop();
|
|
||||||
|
|
||||||
//set the values of this pixel to x/y variables just for readability
|
|
||||||
var x = currentPixel[0];
|
|
||||||
var y = currentPixel[1];
|
|
||||||
|
|
||||||
//this variable holds the index of where the starting values for the current pixel are in the data array
|
|
||||||
//we multiply the number of rows down (y) times the width of each row, then add x. at the end we multiply by 4 because
|
|
||||||
//each pixel has 4 values, rgba
|
|
||||||
var pixelPos = (y * canvasSize[0] + x) * 4;
|
|
||||||
|
|
||||||
//move up in the image until you reach the top or the pixel you hit was not the right color
|
|
||||||
while (y-- >= 0 && matchStartColor(tempImage, pixelPos, clusterColor)) {
|
|
||||||
pixelPos -= canvasSize[0] * 4;
|
|
||||||
}
|
|
||||||
pixelPos += canvasSize[0] * 4;
|
|
||||||
++y;
|
|
||||||
reachLeft = false;
|
|
||||||
reachRight = false;
|
|
||||||
while (y++ < canvasSize[1] - 1 && matchStartColor(tempImage, pixelPos, clusterColor)) {
|
|
||||||
colorPixel(tempImage, pixelPos, fillColor);
|
|
||||||
if (x > 0) {
|
|
||||||
if (matchStartColor(tempImage, pixelPos - 4, clusterColor)) {
|
|
||||||
if (!reachLeft) {
|
|
||||||
topmostPixelsArray.push([x - 1, y]);
|
|
||||||
reachLeft = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (reachLeft) {
|
|
||||||
reachLeft = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x < canvasSize[0] - 1) {
|
|
||||||
if (matchStartColor(tempImage, pixelPos + 4, clusterColor)) {
|
|
||||||
if (!reachRight) {
|
|
||||||
topmostPixelsArray.push([x + 1, y]);
|
|
||||||
reachRight = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (reachRight) {
|
|
||||||
reachRight = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pixelPos += canvasSize[0] * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentLayer.context.putImageData(tempImage, 0, 0);
|
|
||||||
//console.log('done filling')
|
|
||||||
}
|
|
||||||
|
@ -27,11 +27,6 @@ Events.on('click',"ellipse-smaller-button", function(e){
|
|||||||
tool.ellipse.brushSize--;
|
tool.ellipse.brushSize--;
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
//fill
|
|
||||||
Events.on('click',"fill-button", function(){
|
|
||||||
tool.fill.switchTo();
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
//pan
|
//pan
|
||||||
Events.on('click',"pan-button", function(){
|
Events.on('click',"pan-button", function(){
|
||||||
tool.pan.switchTo();
|
tool.pan.switchTo();
|
||||||
|
49
js/_tools.js
49
js/_tools.js
@ -37,20 +37,18 @@ class Tool {
|
|||||||
onSelect() {
|
onSelect() {
|
||||||
this.mainButton.parentElement.classList.add("selected");
|
this.mainButton.parentElement.classList.add("selected");
|
||||||
this.isSelected = true;
|
this.isSelected = true;
|
||||||
/*
|
|
||||||
//copy options to this object
|
|
||||||
if (options.cursor) {
|
|
||||||
//passed statically as a string
|
|
||||||
if (typeof options.cursor == 'string') this.cursor = options.cursor;
|
|
||||||
//passed a function which should be used as a getter function
|
|
||||||
if (typeof options.cursor == 'function') Object.defineProperty(this, 'cursor', { get: options.cursor});
|
|
||||||
|
|
||||||
if (options.imageCursor) this.cursor = "url(\'/pixel-editor/"+options.imageCursor+".png\'), auto";
|
switch (this.cursorType.type) {
|
||||||
|
case 'html':
|
||||||
if (options.brushPreview) {
|
canvasView.style.cursor = 'default';
|
||||||
this.brushPreview = true;
|
break;
|
||||||
}
|
case 'cursor':
|
||||||
}*/
|
this.cursor = "crosshair";
|
||||||
|
canvasView.style.cursor = this.cursor || 'default';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCursor() {}
|
updateCursor() {}
|
||||||
@ -68,22 +66,17 @@ class Tool {
|
|||||||
brushPreview.style.left = (Math.floor(cursorLocation[0] / zoom) * zoom + currentLayer.canvas.offsetLeft - this.currSize * zoom / 2 - zoom / 2 + toSub * zoom) + 'px';
|
brushPreview.style.left = (Math.floor(cursorLocation[0] / zoom) * zoom + currentLayer.canvas.offsetLeft - this.currSize * zoom / 2 - zoom / 2 + toSub * zoom) + 'px';
|
||||||
brushPreview.style.top = (Math.floor(cursorLocation[1] / zoom) * zoom + currentLayer.canvas.offsetTop - this.currSize * zoom / 2 - zoom / 2 + toSub * zoom) + 'px';
|
brushPreview.style.top = (Math.floor(cursorLocation[1] / zoom) * zoom + currentLayer.canvas.offsetTop - this.currSize * zoom / 2 - zoom / 2 + toSub * zoom) + 'px';
|
||||||
|
|
||||||
switch (this.cursorType.type) {
|
if (this.cursorType.type == 'html') {
|
||||||
case 'html':
|
if (cursorTarget == 'drawingCanvas'|| cursorTarget.className == 'drawingCanvas') {
|
||||||
if (cursorTarget == 'drawingCanvas'|| cursorTarget.className == 'drawingCanvas')
|
brushPreview.style.visibility = 'visible';
|
||||||
brushPreview.style.visibility = 'visible';
|
}
|
||||||
else
|
else {
|
||||||
brushPreview.style.visibility = 'hidden';
|
brushPreview.style.visibility = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
brushPreview.style.display = 'block';
|
brushPreview.style.display = 'block';
|
||||||
brushPreview.style.width = this.currSize * zoom + 'px';
|
brushPreview.style.width = this.currSize * zoom + 'px';
|
||||||
brushPreview.style.height = this.currSize * zoom + 'px';
|
brushPreview.style.height = this.currSize * zoom + 'px';
|
||||||
break;
|
|
||||||
case 'cursor':
|
|
||||||
canvasView.style.cursor = this.cursor || 'default';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,139 @@
|
|||||||
|
class FillTool extends Tool {
|
||||||
|
constructor(name, options, switchFunction) {
|
||||||
|
super(name, options);
|
||||||
|
|
||||||
|
Events.on('click', this.mainButton, switchFunction, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onStart(mousePos, target) {
|
||||||
|
super.onStart(mousePos);
|
||||||
|
|
||||||
|
if (target.className != 'drawingCanvas')
|
||||||
|
return;
|
||||||
|
this.fill(mousePos);
|
||||||
|
currentLayer.updateLayerPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fill(cursorLocation) {
|
||||||
|
//changes a pixels color
|
||||||
|
function colorPixel(tempImage, pixelPos, fillColor) {
|
||||||
|
//console.log('colorPixel:',pixelPos);
|
||||||
|
tempImage.data[pixelPos] = fillColor.r;
|
||||||
|
tempImage.data[pixelPos + 1] = fillColor.g;
|
||||||
|
tempImage.data[pixelPos + 2] = fillColor.b;
|
||||||
|
tempImage.data[pixelPos + 3] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
//change x y to color value passed from the function and use that as the original color
|
||||||
|
function matchStartColor(tempImage, pixelPos, color) {
|
||||||
|
//console.log('matchPixel:',x,y)
|
||||||
|
|
||||||
|
let r = tempImage.data[pixelPos];
|
||||||
|
let g = tempImage.data[pixelPos + 1];
|
||||||
|
let b = tempImage.data[pixelPos + 2];
|
||||||
|
let a = tempImage.data[pixelPos + 3];
|
||||||
|
//console.log(r == color[0] && g == color[1] && b == color[2]);
|
||||||
|
return (r == color[0] && g == color[1] && b == color[2] && a == color[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//save history state
|
||||||
|
new HistoryState().EditCanvas();
|
||||||
|
|
||||||
|
//temporary image holds the data while we change it
|
||||||
|
let tempImage = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]);
|
||||||
|
|
||||||
|
//this is an array that holds all of the pixels at the top of the cluster
|
||||||
|
let topmostPixelsArray = [[Math.floor(cursorLocation[0]/zoom), Math.floor(cursorLocation[1]/zoom)]];
|
||||||
|
//console.log('topmostPixelsArray:',topmostPixelsArray)
|
||||||
|
|
||||||
|
//the offset of the pixel in the temp image data to start with
|
||||||
|
let startingPosition = (topmostPixelsArray[0][1] * canvasSize[0] + topmostPixelsArray[0][0]) * 4;
|
||||||
|
|
||||||
|
//the color of the cluster that is being filled
|
||||||
|
let clusterColor = [tempImage.data[startingPosition],tempImage.data[startingPosition+1],tempImage.data[startingPosition+2], tempImage.data[startingPosition+3]];
|
||||||
|
|
||||||
|
//the new color to fill with
|
||||||
|
let fillColor = Color.hexToRgb(currentLayer.context.fillStyle);
|
||||||
|
|
||||||
|
//if you try to fill with the same color that's already there, exit the function
|
||||||
|
if (clusterColor[0] == fillColor.r &&
|
||||||
|
clusterColor[1] == fillColor.g &&
|
||||||
|
clusterColor[2] == fillColor.b &&
|
||||||
|
clusterColor[3] != 0) {
|
||||||
|
console.log("Returned");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//loop until there are no more values left in this array
|
||||||
|
while (topmostPixelsArray.length) {
|
||||||
|
let reachLeft, reachRight;
|
||||||
|
|
||||||
|
//move the most recent pixel from the array and set it as our current working pixels
|
||||||
|
let currentPixel = topmostPixelsArray.pop();
|
||||||
|
|
||||||
|
//set the values of this pixel to x/y variables just for readability
|
||||||
|
let x = currentPixel[0];
|
||||||
|
let y = currentPixel[1];
|
||||||
|
|
||||||
|
//this variable holds the index of where the starting values for the current pixel are in the data array
|
||||||
|
//we multiply the number of rows down (y) times the width of each row, then add x. at the end we multiply by 4 because
|
||||||
|
//each pixel has 4 values, rgba
|
||||||
|
let pixelPos = (y * canvasSize[0] + x) * 4;
|
||||||
|
|
||||||
|
//move up in the image until you reach the top or the pixel you hit was not the right color
|
||||||
|
while (y-- >= 0 && matchStartColor(tempImage, pixelPos, clusterColor)) {
|
||||||
|
pixelPos -= canvasSize[0] * 4;
|
||||||
|
}
|
||||||
|
pixelPos += canvasSize[0] * 4;
|
||||||
|
++y;
|
||||||
|
reachLeft = false;
|
||||||
|
reachRight = false;
|
||||||
|
while (y++ < canvasSize[1] - 1 && matchStartColor(tempImage, pixelPos, clusterColor)) {
|
||||||
|
colorPixel(tempImage, pixelPos, fillColor);
|
||||||
|
if (x > 0) {
|
||||||
|
if (matchStartColor(tempImage, pixelPos - 4, clusterColor)) {
|
||||||
|
if (!reachLeft) {
|
||||||
|
topmostPixelsArray.push([x - 1, y]);
|
||||||
|
reachLeft = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (reachLeft) {
|
||||||
|
reachLeft = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x < canvasSize[0] - 1) {
|
||||||
|
if (matchStartColor(tempImage, pixelPos + 4, clusterColor)) {
|
||||||
|
if (!reachRight) {
|
||||||
|
topmostPixelsArray.push([x + 1, y]);
|
||||||
|
reachRight = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (reachRight) {
|
||||||
|
reachRight = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pixelPos += canvasSize[0] * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentLayer.context.putImageData(tempImage, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrag(mousePos, cursorTarget) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnd(mousePos) {
|
||||||
|
super.onEnd(mousePos);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelect() {
|
||||||
|
super.onSelect();
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeselect() {
|
||||||
|
super.onDeselect();
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,6 @@ new Tool('eyedropper', {
|
|||||||
imageCursor: 'eyedropper',
|
imageCursor: 'eyedropper',
|
||||||
});
|
});
|
||||||
|
|
||||||
new Tool('fill', {
|
|
||||||
imageCursor: 'fill',
|
|
||||||
});
|
|
||||||
|
|
||||||
new Tool('resizeline', {
|
new Tool('resizeline', {
|
||||||
cursor: 'default',
|
cursor: 'default',
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user