mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Issue #311 : Add lasso tool. Implementation and cleanup
This commit is contained in:
@@ -163,7 +163,8 @@
|
||||
cursor: url(../img/icons/hand.png) 7 7, pointer;
|
||||
}
|
||||
|
||||
.tool-rectangle-select .drawing-canvas-container:hover {
|
||||
.tool-rectangle-select .drawing-canvas-container:hover,
|
||||
.tool-lasso-select .drawing-canvas-container:hover {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
toDescriptor('rectangle', 'R', new pskl.tools.drawing.Rectangle()),
|
||||
toDescriptor('circle', 'C', new pskl.tools.drawing.Circle()),
|
||||
toDescriptor('move', 'M', new pskl.tools.drawing.Move()),
|
||||
toDescriptor('rectangleSelect', 'S', new pskl.tools.drawing.RectangleSelect()),
|
||||
toDescriptor('lassoSelect', 'S', new pskl.tools.drawing.LassoSelect()),
|
||||
toDescriptor('shapeSelect', 'Z', new pskl.tools.drawing.ShapeSelect()),
|
||||
toDescriptor('rectangleSelect', 'S', new pskl.tools.drawing.selection.RectangleSelect()),
|
||||
toDescriptor('lassoSelect', 'H', new pskl.tools.drawing.selection.LassoSelect()),
|
||||
toDescriptor('shapeSelect', 'Z', new pskl.tools.drawing.selection.ShapeSelect()),
|
||||
toDescriptor('lighten', 'U', new pskl.tools.drawing.Lighten()),
|
||||
toDescriptor('dithering', 'T', new pskl.tools.drawing.DitheringTool()),
|
||||
toDescriptor('colorPicker', 'O', new pskl.tools.drawing.ColorPicker())
|
||||
@@ -97,22 +97,12 @@
|
||||
};
|
||||
|
||||
ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) {
|
||||
|
||||
var tools = [];
|
||||
for (var i = 0 ; i < this.tools.length ; i++) {
|
||||
var tool = this.tools[i];
|
||||
if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) {
|
||||
tools.push(tool);
|
||||
this.selectTool_(tool);
|
||||
}
|
||||
}
|
||||
|
||||
if (tools.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var currentToolIndex = tools.indexOf(this.currentSelectedTool);
|
||||
|
||||
this.selectTool_(tools[(currentToolIndex+1) % tools.length]);
|
||||
};
|
||||
|
||||
ns.ToolController.prototype.getToolById_ = function (toolId) {
|
||||
|
||||
73
src/js/selection/LassoSelection.js
Normal file
73
src/js/selection/LassoSelection.js
Normal file
@@ -0,0 +1,73 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.selection');
|
||||
|
||||
var OUTSIDE = -1;
|
||||
var INSIDE = 1;
|
||||
var VISITED = 2;
|
||||
|
||||
ns.LassoSelection = function (pixels, frame) {
|
||||
// transform the selected pixels array to a Map to get a faster lookup
|
||||
this.pixelsMap = {};
|
||||
pixels.forEach(function (pixel) {
|
||||
this.setPixelInMap_(pixel, INSIDE);
|
||||
}.bind(this));
|
||||
|
||||
this.pixels = this.getLassoPixels_(frame);
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.LassoSelection, ns.BaseSelection);
|
||||
|
||||
ns.LassoSelection.prototype.getLassoPixels_ = function (frame) {
|
||||
var lassoPixels = [];
|
||||
|
||||
frame.forEachPixel(function (color, pixelCol, pixelRow) {
|
||||
var pixel = {col : pixelCol, row : pixelRow};
|
||||
if (this.isInSelection_(pixel, frame)) {
|
||||
lassoPixels.push(pixel);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
return lassoPixels;
|
||||
};
|
||||
|
||||
ns.LassoSelection.prototype.isInSelection_ = function (pixel, frame) {
|
||||
var alreadyVisited = this.getPixelInMap_(pixel);
|
||||
if (!alreadyVisited) {
|
||||
this.visitPixel_(pixel, frame);
|
||||
}
|
||||
|
||||
return this.getPixelInMap_(pixel) == INSIDE;
|
||||
};
|
||||
|
||||
ns.LassoSelection.prototype.visitPixel_ = function (pixel, frame) {
|
||||
var frameBorderReached = false;
|
||||
var visitedPixels = pskl.PixelUtils.visitConnectedPixels(pixel, frame, function (connectedPixel) {
|
||||
var alreadyVisited = this.getPixelInMap_(connectedPixel);
|
||||
if (alreadyVisited) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!frame.containsPixel(connectedPixel.col, connectedPixel.row)) {
|
||||
frameBorderReached = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.setPixelInMap_(connectedPixel, VISITED);
|
||||
return true;
|
||||
}.bind(this));
|
||||
|
||||
visitedPixels.forEach(function (visitedPixel) {
|
||||
this.setPixelInMap_(visitedPixel, frameBorderReached ? OUTSIDE : INSIDE);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
ns.LassoSelection.prototype.setPixelInMap_ = function (pixel, value) {
|
||||
this.pixelsMap[pixel.col] = this.pixelsMap[pixel.col] || {};
|
||||
this.pixelsMap[pixel.col][pixel.row] = value;
|
||||
};
|
||||
|
||||
ns.LassoSelection.prototype.getPixelInMap_ = function (pixel) {
|
||||
return this.pixelsMap[pixel.col] && this.pixelsMap[pixel.col][pixel.row];
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -41,7 +41,7 @@
|
||||
* @private
|
||||
*/
|
||||
ns.SelectionManager.prototype.onToolSelected_ = function(evt, tool) {
|
||||
var isSelectionTool = tool instanceof pskl.tools.drawing.BaseSelect;
|
||||
var isSelectionTool = tool instanceof pskl.tools.drawing.selection.BaseSelect;
|
||||
if (!isSelectionTool) {
|
||||
this.cleanSelection_();
|
||||
}
|
||||
|
||||
49
src/js/tools/drawing/selection/AbstractDragSelect.js
Normal file
49
src/js/tools/drawing/selection/AbstractDragSelect.js
Normal file
@@ -0,0 +1,49 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.tools.drawing.selection');
|
||||
|
||||
ns.AbstractDragSelect = function () {
|
||||
ns.BaseSelect.call(this);
|
||||
this.hasSelection = false;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.AbstractDragSelect, ns.BaseSelect);
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
ns.AbstractDragSelect.prototype.onSelectStart_ = function (col, row, color, frame, overlay) {
|
||||
if (this.hasSelection) {
|
||||
this.hasSelection = false;
|
||||
overlay.clear();
|
||||
$.publish(Events.SELECTION_DISMISSED);
|
||||
} else {
|
||||
this.hasSelection = true;
|
||||
this.startDragSelection_(col, row);
|
||||
overlay.setPixel(col, row, this.getTransparentVariant_(Constants.SELECTION_TRANSPARENT_COLOR));
|
||||
}
|
||||
};
|
||||
|
||||
ns.AbstractDragSelect.prototype.onSelect_ = function (col, row, color, frame, overlay) {
|
||||
if (!this.hasSelection && (this.startCol !== col || this.startRow !== row)) {
|
||||
this.hasSelection = true;
|
||||
this.startDragSelection_(col, row);
|
||||
}
|
||||
|
||||
if (this.hasSelection) {
|
||||
this.updateDragSelection_(col, row, color, frame, overlay);
|
||||
}
|
||||
};
|
||||
|
||||
ns.AbstractDragSelect.prototype.onSelectEnd_ = function (col, row, color, frame, overlay) {
|
||||
if (this.hasSelection) {
|
||||
this.endDragSelection_(col, row, color, frame, overlay);
|
||||
}
|
||||
};
|
||||
|
||||
/** @protected */
|
||||
ns.AbstractDragSelect.prototype.startDragSelection_ = function (col, row, color, frame, overlay) {};
|
||||
/** @protected */
|
||||
ns.AbstractDragSelect.prototype.updateDragSelection_ = function (col, row, color, frame, overlay) {};
|
||||
/** @protected */
|
||||
ns.AbstractDragSelect.prototype.endDragSelection_ = function (col, row, color, frame, overlay) {};
|
||||
})();
|
||||
@@ -4,7 +4,7 @@
|
||||
* @require pskl.utils
|
||||
*/
|
||||
(function() {
|
||||
var ns = $.namespace('pskl.tools.drawing');
|
||||
var ns = $.namespace('pskl.tools.drawing.selection');
|
||||
|
||||
ns.BaseSelect = function() {
|
||||
this.secondaryToolId = pskl.tools.drawing.Move.TOOL_ID;
|
||||
@@ -23,7 +23,7 @@
|
||||
];
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.BaseSelect, ns.BaseTool);
|
||||
pskl.utils.inherit(ns.BaseSelect, pskl.tools.drawing.BaseTool);
|
||||
|
||||
/**
|
||||
* @override
|
||||
|
||||
@@ -4,179 +4,59 @@
|
||||
* @require pskl.utils
|
||||
*/
|
||||
(function() {
|
||||
var ns = $.namespace('pskl.tools.drawing');
|
||||
var ns = $.namespace('pskl.tools.drawing.selection');
|
||||
|
||||
ns.LassoSelect = function() {
|
||||
this.toolId = 'tool-lasso-select';
|
||||
|
||||
this.helpText = 'Lasso selection';
|
||||
|
||||
ns.BaseSelect.call(this);
|
||||
this.hasSelection = false;
|
||||
|
||||
this.selectionOrigin_ = null;
|
||||
ns.AbstractDragSelect.call(this);
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.LassoSelect, ns.BaseSelect);
|
||||
pskl.utils.inherit(ns.LassoSelect, ns.AbstractDragSelect);
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
ns.LassoSelect.prototype.onSelectStart_ = function (col, row, color, frame, overlay) {
|
||||
this.selectionOrigin_ = {
|
||||
col : col,
|
||||
row : row
|
||||
};
|
||||
ns.LassoSelect.prototype.startDragSelection_ = function (col, row) {
|
||||
this.pixels = [{col : col, row : row}];
|
||||
this.previousCol = col;
|
||||
this.previousRow = row;
|
||||
if (this.hasSelection) {
|
||||
this.hasSelection = false;
|
||||
overlay.clear();
|
||||
$.publish(Events.SELECTION_DISMISSED);
|
||||
} else {
|
||||
this.startSelection_(col, row);
|
||||
overlay.setPixel(col, row, color);
|
||||
}
|
||||
};
|
||||
|
||||
ns.LassoSelect.prototype.startSelection_ = function (col, row) {
|
||||
this.hasSelection = true;
|
||||
this.pixels = [{col : col, row : row}];
|
||||
$.publish(Events.DRAG_START, [col, row]);
|
||||
// Drawing the first point of the rectangle in the fake overlay canvas:
|
||||
};
|
||||
|
||||
/**
|
||||
* When creating the rectangle selection, we clear the current overlayFrame and
|
||||
* redraw the current rectangle based on the orgin coordinate and
|
||||
* the current mouse coordiinate in sprite.
|
||||
* @override
|
||||
*/
|
||||
ns.LassoSelect.prototype.onSelect_ = function (col, row, color, frame, overlay) {
|
||||
if (!this.hasSelection && (this.selectionOrigin_.col !== col || this.selectionOrigin_.row !== row)) {
|
||||
this.startSelection_(col, row);
|
||||
}
|
||||
ns.LassoSelect.prototype.updateDragSelection_ = function (col, row, color, frame, overlay) {
|
||||
col = pskl.utils.Math.minmax(col, 0, frame.getWidth() - 1);
|
||||
row = pskl.utils.Math.minmax(row, 0, frame.getHeight() - 1);
|
||||
this.addPixelToSelection_(col, row, frame);
|
||||
var additionnalPixels = this.getLinePixels_(col, this.startCol, row, this.startRow);
|
||||
|
||||
if (this.hasSelection) {
|
||||
if ((Math.abs(col - this.previousCol) > 1) || (Math.abs(row - this.previousRow) > 1)) {
|
||||
// The pen movement is too fast for the mousemove frequency, there is a gap between the
|
||||
// current point and the previously drawn one.
|
||||
// We fill the gap by calculating missing dots (simple linear interpolation) and draw them.
|
||||
var interpolatedPixels = this.getLinePixels_(col, this.previousCol, row, this.previousRow);
|
||||
this.pixels = this.pixels.concat(interpolatedPixels);
|
||||
} else {
|
||||
this.pixels.push({col : col, row : row});
|
||||
}
|
||||
// during the selection, create simple ShapeSelection, containing only the pixels hovered by the user
|
||||
this.selection = new pskl.selection.ShapeSelection(this.pixels.concat(additionnalPixels));
|
||||
$.publish(Events.SELECTION_CREATED, [this.selection]);
|
||||
|
||||
this.previousCol = col;
|
||||
this.previousRow = row;
|
||||
|
||||
// join lasso tail with origin
|
||||
var additionnalPixels = this.getLinePixels_(col, this.selectionOrigin_.col, row, this.selectionOrigin_.row);
|
||||
|
||||
overlay.clear();
|
||||
this.selection = new pskl.selection.ShapeSelection(this.pixels.concat(additionnalPixels));
|
||||
$.publish(Events.SELECTION_CREATED, [this.selection]);
|
||||
this.drawSelectionOnOverlay_(overlay);
|
||||
}
|
||||
overlay.clear();
|
||||
this.drawSelectionOnOverlay_(overlay);
|
||||
};
|
||||
|
||||
ns.LassoSelect.prototype.onSelectEnd_ = function (col, row, color, frame, overlay) {
|
||||
if (this.hasSelection) {
|
||||
if ((Math.abs(col - this.previousCol) > 1) || (Math.abs(row - this.previousRow) > 1)) {
|
||||
// The pen movement is too fast for the mousemove frequency, there is a gap between the
|
||||
// current point and the previously drawn one.
|
||||
// We fill the gap by calculating missing dots (simple linear interpolation) and draw them.
|
||||
var interpolatedPixels = this.getLinePixels_(col, this.previousCol, row, this.previousRow);
|
||||
this.pixels = this.pixels.concat(interpolatedPixels);
|
||||
} else {
|
||||
this.pixels.push({col : col, row : row});
|
||||
}
|
||||
ns.LassoSelect.prototype.endDragSelection_ = function (col, row, color, frame, overlay) {
|
||||
col = pskl.utils.Math.minmax(col, 0, frame.getWidth() - 1);
|
||||
row = pskl.utils.Math.minmax(row, 0, frame.getHeight() - 1);
|
||||
this.addPixelToSelection_(col, row, frame);
|
||||
var additionnalPixels = this.getLinePixels_(col, this.startCol, row, this.startRow);
|
||||
|
||||
// finalize the selection, add all pixels contained inside the shape drawn by the user to the selection
|
||||
this.selection = new pskl.selection.LassoSelection(this.pixels.concat(additionnalPixels), frame);
|
||||
$.publish(Events.SELECTION_CREATED, [this.selection]);
|
||||
|
||||
var additionnalPixels = this.getLinePixels_(col, this.selectionOrigin_.col, row, this.selectionOrigin_.row);
|
||||
this.pixels = this.pixels.concat(additionnalPixels);
|
||||
overlay.clear();
|
||||
this.drawSelectionOnOverlay_(overlay);
|
||||
|
||||
var shapePixels = [];
|
||||
var pixelsMap = {};
|
||||
this.pixels.forEach(function (p) {
|
||||
pixelsMap[p.col] = pixelsMap[p.col] || {};
|
||||
pixelsMap[p.col][p.row] = 1;
|
||||
});
|
||||
frame.forEachPixel(function (color, c, r) {
|
||||
if(this.isInPoly_(c, r, pixelsMap, frame)) {
|
||||
shapePixels.push({col : c, row : r});
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.pixels = this.pixels.concat(shapePixels);
|
||||
|
||||
this.selection = new pskl.selection.ShapeSelection(this.pixels);
|
||||
$.publish(Events.SELECTION_CREATED, [this.selection]);
|
||||
this.onSelect_(col, row, color, frame, overlay);
|
||||
$.publish(Events.DRAG_END, [col, row]);
|
||||
}
|
||||
$.publish(Events.DRAG_END, [col, row]);
|
||||
};
|
||||
|
||||
ns.LassoSelect.prototype.isInPoly_ = function (col, row, pixelsMap, frame) {
|
||||
ns.LassoSelect.prototype.addPixelToSelection_ = function (col, row, frame) {
|
||||
var interpolatedPixels = this.getLinePixels_(col, this.previousCol, row, this.previousRow);
|
||||
this.pixels = this.pixels.concat(interpolatedPixels);
|
||||
|
||||
if (pixelsMap[col] && pixelsMap[col][row]) {
|
||||
// already marked
|
||||
return pixelsMap[col][row] == 1;
|
||||
}
|
||||
|
||||
var paintedPixels = [];
|
||||
var queue = [];
|
||||
var dy = [-1, 0, 1, 0];
|
||||
var dx = [0, 1, 0, -1];
|
||||
|
||||
queue.push({'col': col, 'row': row});
|
||||
var isOut = false;
|
||||
var loopCount = 0;
|
||||
var cellCount = frame.getWidth() * frame.getHeight();
|
||||
while (queue.length > 0) {
|
||||
loopCount ++;
|
||||
|
||||
var currentItem = queue.pop();
|
||||
paintedPixels.push({'col': currentItem.col, 'row': currentItem.row});
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var nextCol = currentItem.col + dx[i];
|
||||
var nextRow = currentItem.row + dy[i];
|
||||
try {
|
||||
var isMarked = pixelsMap[nextCol] && pixelsMap[nextCol][nextRow];
|
||||
if (frame.containsPixel(nextCol, nextRow) && !isMarked && !this.isInPixels_(nextCol, nextRow, pixelsMap)) {
|
||||
queue.push({'col': nextCol, 'row': nextRow});
|
||||
|
||||
pixelsMap[nextCol] = pixelsMap[nextCol] || {};
|
||||
pixelsMap[nextCol][nextRow] = 2;
|
||||
|
||||
if ((nextCol === 0 || nextCol == frame.getWidth() - 1) || (nextRow === 0 || nextRow == frame.getHeight() - 1)) {
|
||||
isOut= true;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Frame out of bound exception.
|
||||
}
|
||||
}
|
||||
|
||||
// Security loop breaker:
|
||||
if (loopCount > 10 * cellCount) {
|
||||
console.log('loop breaker called');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
paintedPixels.forEach(function (p) {
|
||||
pixelsMap[p.col] = pixelsMap[p.col] || {};
|
||||
pixelsMap[p.col][p.row] = isOut ? -1 : 1;
|
||||
});
|
||||
|
||||
return !isOut;
|
||||
};
|
||||
|
||||
|
||||
ns.LassoSelect.prototype.isInPixels_ = function (col, row, pixelsMap) {
|
||||
return pixelsMap[col] && pixelsMap[col][row] === 1;
|
||||
this.previousCol = col;
|
||||
this.previousRow = row;
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -4,43 +4,19 @@
|
||||
* @require pskl.utils
|
||||
*/
|
||||
(function() {
|
||||
var ns = $.namespace('pskl.tools.drawing');
|
||||
var ns = $.namespace('pskl.tools.drawing.selection');
|
||||
|
||||
ns.RectangleSelect = function() {
|
||||
this.toolId = 'tool-rectangle-select';
|
||||
|
||||
this.helpText = 'Rectangle selection';
|
||||
|
||||
ns.BaseSelect.call(this);
|
||||
this.hasSelection = false;
|
||||
|
||||
this.selectionOrigin_ = null;
|
||||
ns.AbstractDragSelect.call(this);
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.RectangleSelect, ns.BaseSelect);
|
||||
pskl.utils.inherit(ns.RectangleSelect, ns.AbstractDragSelect);
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
ns.RectangleSelect.prototype.onSelectStart_ = function (col, row, frame, overlay) {
|
||||
this.selectionOrigin_ = {
|
||||
col : col,
|
||||
row : row
|
||||
};
|
||||
if (this.hasSelection) {
|
||||
this.hasSelection = false;
|
||||
overlay.clear();
|
||||
$.publish(Events.SELECTION_DISMISSED);
|
||||
} else {
|
||||
this.startSelection_(col, row);
|
||||
overlay.setPixel(col, row, Constants.SELECTION_TRANSPARENT_COLOR);
|
||||
}
|
||||
};
|
||||
|
||||
ns.RectangleSelect.prototype.startSelection_ = function (col, row) {
|
||||
this.hasSelection = true;
|
||||
ns.RectangleSelect.prototype.startDragSelection_ = function (col, row) {
|
||||
$.publish(Events.DRAG_START, [col, row]);
|
||||
// Drawing the first point of the rectangle in the fake overlay canvas:
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -49,25 +25,16 @@
|
||||
* the current mouse coordiinate in sprite.
|
||||
* @override
|
||||
*/
|
||||
ns.RectangleSelect.prototype.onSelect_ = function (col, row, frame, overlay) {
|
||||
if (!this.hasSelection && (this.selectionOrigin_.col !== col || this.selectionOrigin_.row !== row)) {
|
||||
this.startSelection_(col, row);
|
||||
}
|
||||
|
||||
if (this.hasSelection) {
|
||||
overlay.clear();
|
||||
this.selection = new pskl.selection.RectangularSelection(
|
||||
this.startCol, this.startRow, col, row);
|
||||
$.publish(Events.SELECTION_CREATED, [this.selection]);
|
||||
this.drawSelectionOnOverlay_(overlay);
|
||||
}
|
||||
ns.RectangleSelect.prototype.updateDragSelection_ = function (col, row, color, frame, overlay) {
|
||||
overlay.clear();
|
||||
this.selection = new pskl.selection.RectangularSelection(this.startCol, this.startRow, col, row);
|
||||
$.publish(Events.SELECTION_CREATED, [this.selection]);
|
||||
this.drawSelectionOnOverlay_(overlay);
|
||||
};
|
||||
|
||||
ns.RectangleSelect.prototype.onSelectEnd_ = function (col, row, frame, overlay) {
|
||||
if (this.hasSelection) {
|
||||
this.onSelect_(col, row, frame, overlay);
|
||||
$.publish(Events.DRAG_END, [col, row]);
|
||||
}
|
||||
ns.RectangleSelect.prototype.onSelectEnd_ = function (col, row, color, frame, overlay) {
|
||||
this.onSelect_(col, row, color, frame, overlay);
|
||||
$.publish(Events.DRAG_END, [col, row]);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @require pskl.utils
|
||||
*/
|
||||
(function() {
|
||||
var ns = $.namespace('pskl.tools.drawing');
|
||||
var ns = $.namespace('pskl.tools.drawing.selection');
|
||||
|
||||
ns.ShapeSelect = function() {
|
||||
this.toolId = 'tool-shape-select';
|
||||
|
||||
@@ -99,10 +99,6 @@
|
||||
* 13. Continue looping until Q is exhausted.
|
||||
* 14. Return.
|
||||
*/
|
||||
var paintedPixels = [];
|
||||
var queue = [];
|
||||
var dy = [-1, 0, 1, 0];
|
||||
var dx = [0, 1, 0, -1];
|
||||
var targetColor;
|
||||
try {
|
||||
targetColor = frame.getPixel(col, row);
|
||||
@@ -114,22 +110,45 @@
|
||||
return;
|
||||
}
|
||||
|
||||
queue.push({'col': col, 'row': row});
|
||||
var paintedPixels = pskl.PixelUtils.visitConnectedPixels({col:col, row:row}, frame, function (pixel) {
|
||||
if (frame.containsPixel(pixel.col, pixel.row) && frame.getPixel(pixel.col, pixel.row) == targetColor) {
|
||||
frame.setPixel(pixel.col, pixel.row, replacementColor);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return paintedPixels;
|
||||
},
|
||||
|
||||
visitConnectedPixels : function (pixel, frame, pixelVisitor) {
|
||||
var col = pixel.col;
|
||||
var row = pixel.row;
|
||||
|
||||
var queue = [];
|
||||
var visitedPixels = [];
|
||||
var dy = [-1, 0, 1, 0];
|
||||
var dx = [0, 1, 0, -1];
|
||||
|
||||
queue.push(pixel);
|
||||
visitedPixels.push(pixel);
|
||||
pixelVisitor(pixel);
|
||||
|
||||
var loopCount = 0;
|
||||
var cellCount = frame.getWidth() * frame.getHeight();
|
||||
while (queue.length > 0) {
|
||||
loopCount ++;
|
||||
|
||||
var currentItem = queue.pop();
|
||||
frame.setPixel(currentItem.col, currentItem.row, replacementColor);
|
||||
paintedPixels.push({'col': currentItem.col, 'row': currentItem.row});
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var nextCol = currentItem.col + dx[i];
|
||||
var nextRow = currentItem.row + dy[i];
|
||||
try {
|
||||
if (frame.containsPixel(nextCol, nextRow) && frame.getPixel(nextCol, nextRow) == targetColor) {
|
||||
queue.push({'col': nextCol, 'row': nextRow});
|
||||
var connectedPixel = {'col': nextCol, 'row': nextRow};
|
||||
var isValid = pixelVisitor(connectedPixel);
|
||||
if (isValid) {
|
||||
queue.push(connectedPixel);
|
||||
visitedPixels.push(connectedPixel);
|
||||
}
|
||||
} catch (e) {
|
||||
// Frame out of bound exception.
|
||||
@@ -142,7 +161,8 @@
|
||||
break;
|
||||
}
|
||||
}
|
||||
return paintedPixels;
|
||||
|
||||
return visitedPixels;
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
// Selection
|
||||
"js/selection/SelectionManager.js",
|
||||
"js/selection/BaseSelection.js",
|
||||
"js/selection/LassoSelection.js",
|
||||
"js/selection/RectangularSelection.js",
|
||||
"js/selection/ShapeSelection.js",
|
||||
|
||||
@@ -184,6 +185,7 @@
|
||||
"js/tools/drawing/Circle.js",
|
||||
"js/tools/drawing/Move.js",
|
||||
"js/tools/drawing/selection/BaseSelect.js",
|
||||
"js/tools/drawing/selection/AbstractDragSelect.js",
|
||||
"js/tools/drawing/selection/LassoSelect.js",
|
||||
"js/tools/drawing/selection/RectangleSelect.js",
|
||||
"js/tools/drawing/selection/ShapeSelect.js",
|
||||
|
||||
Reference in New Issue
Block a user