Add outliner tool.

This commit is contained in:
Jeff Wofford 2020-05-05 18:09:35 -05:00
parent cb41a72b5b
commit 0f5501bc3b
10 changed files with 120 additions and 5 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -46,6 +46,7 @@ body {
.tool.bucket { background-image: url(img/paintbucket-icon.png); } .tool.bucket { background-image: url(img/paintbucket-icon.png); }
.tool.pen { background-image: url(img/pen-icon.png); } .tool.pen { background-image: url(img/pen-icon.png); }
.tool.eyedropper { background-image: url(img/eyedropper-icon.png);} .tool.eyedropper { background-image: url(img/eyedropper-icon.png);}
.tool.outliner { background-image: url(img/outliner-icon.png);} /* TODO!!! replace */
.tool:hover { .tool:hover {
cursor: pointer; cursor: pointer;

View File

@ -202,6 +202,10 @@
background-image: url(../img/icons/tools/tool-paint-bucket.png); background-image: url(../img/icons/tools/tool-paint-bucket.png);
} }
.cheatsheet-icon-tool-outliner {
background-image: url(../img/icons/tools/tool-outliner.png);
}
.cheatsheet-icon-tool-pen { .cheatsheet-icon-tool-pen {
background-image: url(../img/icons/tools/tool-pen.png); background-image: url(../img/icons/tools/tool-pen.png);
} }

View File

@ -30,6 +30,7 @@
*/ */
.tool-paint-bucket .drawing-canvas-container:hover, .tool-paint-bucket .drawing-canvas-container:hover,
.tool-outliner .drawing-canvas-container:hover,
.tool-colorswap .drawing-canvas-container:hover { .tool-colorswap .drawing-canvas-container:hover {
cursor: url(../img/cursors/paint-bucket.png) 14 14, pointer; cursor: url(../img/cursors/paint-bucket.png) 14 14, pointer;
} }

View File

@ -18,7 +18,8 @@
new pskl.tools.drawing.selection.LassoSelect(), new pskl.tools.drawing.selection.LassoSelect(),
new pskl.tools.drawing.Lighten(), new pskl.tools.drawing.Lighten(),
new pskl.tools.drawing.DitheringTool(), new pskl.tools.drawing.DitheringTool(),
new pskl.tools.drawing.ColorPicker() new pskl.tools.drawing.ColorPicker(),
new pskl.tools.drawing.Outliner()
]; ];
this.toolIconBuilder = new pskl.tools.ToolIconBuilder(); this.toolIconBuilder = new pskl.tools.ToolIconBuilder();

View File

@ -31,7 +31,8 @@
LASSO_SELECT : createShortcut('tool-lasso-select', 'Lasso selection', 'H'), LASSO_SELECT : createShortcut('tool-lasso-select', 'Lasso selection', 'H'),
LIGHTEN : createShortcut('tool-lighten', 'Lighten tool', 'U'), LIGHTEN : createShortcut('tool-lighten', 'Lighten tool', 'U'),
DITHERING : createShortcut('tool-dithering', 'Dithering tool', 'T'), DITHERING : createShortcut('tool-dithering', 'Dithering tool', 'T'),
COLORPICKER : createShortcut('tool-colorpicker', 'Color picker', 'O') COLORPICKER : createShortcut('tool-colorpicker', 'Color picker', 'O'),
OUTLINER : createShortcut('tool-outliner', 'Outliner', 'Q')
}, },
SELECTION : { SELECTION : {

View File

@ -0,0 +1,39 @@
/**
* @provide pskl.tools.drawing.Outliner
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace('pskl.tools.drawing');
ns.Outliner = function() {
this.toolId = 'tool-outliner';
this.helpText = 'Outliner tool';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.OUTLINER;
this.tooltipDescriptors = [
{key : 'ctrl', description : 'Fill corners'}
];
};
pskl.utils.inherit(ns.Outliner, ns.BaseTool);
/**
* @override
*/
ns.Outliner.prototype.applyToolAt = function(col, row, frame, overlay, event) {
var fillCorners = pskl.utils.UserAgent.isMac ? event.metaKey : event.ctrlKey;
var color = this.getToolColor();
pskl.PixelUtils.outlineSimilarConnectedPixelsFromFrame(frame, col, row, color, fillCorners);
this.raiseSaveStateEvent({
col : col,
row : row,
color : color,
fillCorners: fillCorners
});
};
ns.Outliner.prototype.replay = function (frame, replayData) {
pskl.PixelUtils.outlineSimilarConnectedPixelsFromFrame(frame, replayData.col, replayData.row, replayData.color, replayData.fillCorners);
};
})();

View File

@ -154,6 +154,76 @@
return paintedPixels; return paintedPixels;
}, },
/**
* Apply the outliner tool in a frame at the (col, row) initial position
* with the replacement color.
*
* @param frame pskl.model.Frame The frame target in which we want to paintbucket
* @param col number Column coordinate in the frame
* @param row number Row coordinate in the frame
* @param replacementColor string Hexadecimal color used to fill the area
* @param fillCorners boolean If true, also paint corner pixels
*
* @return an array of the pixel coordinates paint with the replacement color
*/
outlineSimilarConnectedPixelsFromFrame: function(frame, col, row, replacementColor, fillCorners) {
/**
* Acts like floodfill, except that a given pixel is only painted if it has at
* least one non-filled-color neighbor.
*
*/
if (typeof replacementColor == 'string') {
replacementColor = pskl.utils.colorToInt(replacementColor);
}
if (fillCorners===undefined) {
fillCorners = false;
}
var targetColor;
try {
targetColor = frame.getPixel(col, row);
} catch (e) {
// Frame out of bound exception.
}
if (targetColor === null || targetColor == replacementColor) {
return;
}
var atLeastOneNeighborHasNonTargetColor = function(pixel) {
for (var y = -1; y <= 1; y++ ) {
for (var x = -1; x <= 1; x++ ) {
if (x != 0 || y != 0) {
if (fillCorners || (x == 0 || y == 0)) {
try {
var pixelColor = frame.getPixel(pixel.col + x, pixel.row + y);
if ( pixelColor !== null && pixelColor !== targetColor) {
return true;
}
} catch (e) {
// Frame out of bound exception.
}
}
}
}
}
return false;
};
var pixels = pskl.PixelUtils.getSimilarConnectedPixelsFromFrame(frame, col, row);
pixels = pixels.filter(pixel => atLeastOneNeighborHasNonTargetColor(pixel));
var paintedPixels = [];
for (var pixel of pixels) {
frame.setPixel(pixel.col, pixel.row, replacementColor);
paintedPixels.push(pixel);
}
return paintedPixels;
},
/** /**
* Starting from a provided origin, visit connected pixels using a visitor function. * Starting from a provided origin, visit connected pixels using a visitor function.
* After visiting a pixel, select the 4 connected pixels (up, right, down, left). * After visiting a pixel, select the 4 connected pixels (up, right, down, left).
@ -167,9 +237,6 @@
* @return {Array} the array of visited pixels {col, row} * @return {Array} the array of visited pixels {col, row}
*/ */
visitConnectedPixels : function (pixel, frame, pixelVisitor) { visitConnectedPixels : function (pixel, frame, pixelVisitor) {
var col = pixel.col;
var row = pixel.row;
var queue = []; var queue = [];
var visitedPixels = []; var visitedPixels = [];
var dy = [-1, 0, 1, 0]; var dy = [-1, 0, 1, 0];

View File

@ -225,6 +225,7 @@
"js/tools/drawing/Eraser.js", "js/tools/drawing/Eraser.js",
"js/tools/drawing/Stroke.js", "js/tools/drawing/Stroke.js",
"js/tools/drawing/PaintBucket.js", "js/tools/drawing/PaintBucket.js",
"js/tools/drawing/Outliner.js",
"js/tools/drawing/Rectangle.js", "js/tools/drawing/Rectangle.js",
"js/tools/drawing/Circle.js", "js/tools/drawing/Circle.js",
"js/tools/drawing/Move.js", "js/tools/drawing/Move.js",