mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Issue #311 : Add lasso tool initial commit
This commit is contained in:
parent
66fa71affd
commit
f7592f864b
@ -17,6 +17,7 @@
|
|||||||
toDescriptor('circle', 'C', new pskl.tools.drawing.Circle()),
|
toDescriptor('circle', 'C', new pskl.tools.drawing.Circle()),
|
||||||
toDescriptor('move', 'M', new pskl.tools.drawing.Move()),
|
toDescriptor('move', 'M', new pskl.tools.drawing.Move()),
|
||||||
toDescriptor('rectangleSelect', 'S', new pskl.tools.drawing.RectangleSelect()),
|
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('shapeSelect', 'Z', new pskl.tools.drawing.ShapeSelect()),
|
||||||
toDescriptor('lighten', 'U', new pskl.tools.drawing.Lighten()),
|
toDescriptor('lighten', 'U', new pskl.tools.drawing.Lighten()),
|
||||||
toDescriptor('dithering', 'T', new pskl.tools.drawing.DitheringTool()),
|
toDescriptor('dithering', 'T', new pskl.tools.drawing.DitheringTool()),
|
||||||
@ -96,12 +97,22 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) {
|
ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) {
|
||||||
|
|
||||||
|
var tools = [];
|
||||||
for (var i = 0 ; i < this.tools.length ; i++) {
|
for (var i = 0 ; i < this.tools.length ; i++) {
|
||||||
var tool = this.tools[i];
|
var tool = this.tools[i];
|
||||||
if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) {
|
if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) {
|
||||||
this.selectTool_(tool);
|
tools.push(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) {
|
ns.ToolController.prototype.getToolById_ = function (toolId) {
|
||||||
|
182
src/js/tools/drawing/selection/LassoSelect.js
Normal file
182
src/js/tools/drawing/selection/LassoSelect.js
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/**
|
||||||
|
* @provide pskl.tools.drawing.ShapeSelect
|
||||||
|
*
|
||||||
|
* @require pskl.utils
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
var ns = $.namespace('pskl.tools.drawing');
|
||||||
|
|
||||||
|
ns.LassoSelect = function() {
|
||||||
|
this.toolId = 'tool-lasso-select';
|
||||||
|
|
||||||
|
this.helpText = 'Lasso selection';
|
||||||
|
|
||||||
|
ns.BaseSelect.call(this);
|
||||||
|
this.hasSelection = false;
|
||||||
|
|
||||||
|
this.selectionOrigin_ = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
pskl.utils.inherit(ns.LassoSelect, ns.BaseSelect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
ns.LassoSelect.prototype.onSelectStart_ = function (col, row, color, frame, overlay) {
|
||||||
|
this.selectionOrigin_ = {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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});
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var additionnalPixels = this.getLinePixels_(col, this.selectionOrigin_.col, row, this.selectionOrigin_.row);
|
||||||
|
this.pixels = this.pixels.concat(additionnalPixels);
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.LassoSelect.prototype.isInPoly_ = function (col, row, pixelsMap, frame) {
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
})();
|
@ -184,6 +184,7 @@
|
|||||||
"js/tools/drawing/Circle.js",
|
"js/tools/drawing/Circle.js",
|
||||||
"js/tools/drawing/Move.js",
|
"js/tools/drawing/Move.js",
|
||||||
"js/tools/drawing/selection/BaseSelect.js",
|
"js/tools/drawing/selection/BaseSelect.js",
|
||||||
|
"js/tools/drawing/selection/LassoSelect.js",
|
||||||
"js/tools/drawing/selection/RectangleSelect.js",
|
"js/tools/drawing/selection/RectangleSelect.js",
|
||||||
"js/tools/drawing/selection/ShapeSelect.js",
|
"js/tools/drawing/selection/ShapeSelect.js",
|
||||||
"js/tools/drawing/ColorPicker.js",
|
"js/tools/drawing/ColorPicker.js",
|
||||||
|
Loading…
Reference in New Issue
Block a user