Feature : Hold shift to preserve shape ratio

- mutualized shape tools common code in a ShapeTool class
- when holding shift and drawing a frame, the ratio is preserved
- selection and shape tools now support the mouse to leave the drawing
  area
- shape tools can go 'outside' the drawing canvas
- Frame set/getPixel now check the pixel is in range instead of crashing
This commit is contained in:
jdescottes 2014-04-02 22:21:32 +02:00
parent 7357614d9a
commit c9251229fc
8 changed files with 119 additions and 90 deletions

View File

@ -40,7 +40,7 @@
-moz-box-sizing : border-box;
border-radius: 3px;
background: rgba(0,0,0,0.9);
background: rgba(0,0,0,1);
overflow: auto;
}

View File

@ -120,7 +120,7 @@
* @private
*/
ns.DrawingController.prototype.onMouseenter_ = function (event) {
this.container.bind('mousemove', $.proxy(this.onMousemove_, this));
$('body').bind('mousemove', $.proxy(this.onMousemove_, this));
};
/**

View File

@ -7,49 +7,15 @@
var ns = $.namespace("pskl.drawingtools");
ns.Circle = function() {
ns.ShapeTool.call(this);
this.toolId = "tool-circle";
this.helpText = "Circle tool";
// Circle's first point coordinates (set in applyToolAt)
this.startCol = null;
this.startRow = null;
};
pskl.utils.inherit(ns.Circle, ns.BaseTool);
pskl.utils.inherit(ns.Circle, ns.ShapeTool);
/**
* @override
*/
ns.Circle.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {
this.startCol = col;
this.startRow = row;
// Drawing the first point of the rectangle in the fake overlay canvas:
overlay.setPixel(col, row, color);
};
ns.Circle.prototype.moveToolAt = function(col, row, color, frame, overlay, event) {
overlay.clear();
if(color == Constants.TRANSPARENT_COLOR) {
color = Constants.SELECTION_TRANSPARENT_COLOR;
}
// draw in overlay
this.drawCircle_(col, row, color, overlay);
};
/**
* @override
*/
ns.Circle.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) {
overlay.clear();
if(frame.containsPixel(col, row)) { // cancel if outside of canvas
// draw in frame to finalize
this.drawCircle_(col, row, color, frame);
}
};
ns.Circle.prototype.drawCircle_ = function (col, row, color, targetFrame) {
ns.Circle.prototype.draw_ = function (col, row, color, targetFrame) {
var circlePoints = this.getCirclePixels_(this.startCol, this.startRow, col, row);
for(var i = 0; i< circlePoints.length; i++) {
// Change model:

View File

@ -7,49 +7,15 @@
var ns = $.namespace("pskl.drawingtools");
ns.Rectangle = function() {
ns.ShapeTool.call(this);
this.toolId = "tool-rectangle";
this.helpText = "Rectangle tool";
// Rectangle's first point coordinates (set in applyToolAt)
this.startCol = null;
this.startRow = null;
};
pskl.utils.inherit(ns.Rectangle, ns.BaseTool);
pskl.utils.inherit(ns.Rectangle, ns.ShapeTool);
/**
* @override
*/
ns.Rectangle.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {
this.startCol = col;
this.startRow = row;
// Drawing the first point of the rectangle in the fake overlay canvas:
overlay.setPixel(col, row, color);
};
ns.Rectangle.prototype.moveToolAt = function(col, row, color, frame, overlay, event) {
overlay.clear();
if(color == Constants.TRANSPARENT_COLOR) {
color = Constants.SELECTION_TRANSPARENT_COLOR;
}
// draw in overlay
this.drawRectangle_(col, row, color, overlay);
};
/**
* @override
*/
ns.Rectangle.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) {
overlay.clear();
if(frame.containsPixel(col, row)) { // cancel if outside of canvas
// draw in frame to finalize
this.drawRectangle_(col, row, color, frame);
}
};
ns.Rectangle.prototype.drawRectangle_ = function (col, row, color, targetFrame) {
ns.Rectangle.prototype.draw_ = function (col, row, color, targetFrame) {
var strokePoints = pskl.PixelUtils.getBoundRectanglePixels(this.startCol, this.startRow, col, row);
for(var i = 0; i< strokePoints.length; i++) {
// Change model:

View File

@ -0,0 +1,89 @@
(function () {
var ns = $.namespace('pskl.drawingtools');
/**
* Abstract shape tool class, parent to all shape tools (rectangle, circle).
* Shape tools should override only the draw_ method
*/
ns.ShapeTool = function() {
// Shapes's first point coordinates (set in applyToolAt)
this.startCol = null;
this.startRow = null;
};
pskl.utils.inherit(ns.ShapeTool, ns.BaseTool);
/**
* @override
*/
ns.ShapeTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {
this.startCol = col;
this.startRow = row;
// Drawing the first point of the rectangle in the fake overlay canvas:
overlay.setPixel(col, row, color);
};
ns.ShapeTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) {
overlay.clear();
if(color == Constants.TRANSPARENT_COLOR) {
color = Constants.SELECTION_TRANSPARENT_COLOR;
}
var coords = this.getCoordinates_(col, row, event);
// draw in overlay
this.draw_(coords.col, coords.row, color, overlay);
};
/**
* @override
*/
ns.ShapeTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) {
overlay.clear();
if (event.shiftKey) {
var scaled = this.getScaledCoordinates_(col, row);
col = scaled.col;
row = scaled.row;
}
var coords = this.getCoordinates_(col, row, event);
this.draw_(coords.col, coords.row, color, frame);
};
/**
* Transform the current coordinates based on the original event
* @param {Number} col current col/x coordinate in the frame
* @param {Number} row current row/y coordinate in the frame
* @param {Event} event current event (can be mousemove, mouseup ...)
* @return {Object} {row : Number, col : Number}
*/
ns.ShapeTool.prototype.getCoordinates_ = function(col, row, event) {
if (event.shiftKey) {
return this.getScaledCoordinates_(col, row);
} else {
return {col : col, row : row};
}
};
/**
* Transform the coordinates to preserve a square 1:1 ratio from the origin of the shape
* @param {Number} col current col/x coordinate in the frame
* @param {Number} row current row/y coordinate in the frame
* @return {Object} {row : Number, col : Number}
*/
ns.ShapeTool.prototype.getScaledCoordinates_ = function(col, row) {
var sign;
if (Math.abs(this.startCol - col) > Math.abs(this.startRow - row)) {
sign = row > this.startRow ? 1 : -1;
row = this.startRow + (sign * Math.abs(this.startCol - col));
} else {
sign = col > this.startCol ? 1 : -1;
col = this.startCol + (sign * Math.abs(this.startRow - row));
}
return {
col : col,
row : row
};
};
ns.ShapeTool.prototype.draw_ = Constants.ABSTRACT_FUNCTION;
})();

View File

@ -80,15 +80,16 @@
* @override
*/
ns.BaseSelect.prototype.moveUnactiveToolAt = function(col, row, color, frame, overlay, event) {
if(overlay.getPixel(col, row) != Constants.SELECTION_TRANSPARENT_COLOR) {
// We're hovering the selection, show the move tool:
this.BodyRoot.addClass(this.toolId);
this.BodyRoot.removeClass(this.secondaryToolId);
} else {
// We're not hovering the selection, show create selection tool:
this.BodyRoot.addClass(this.secondaryToolId);
this.BodyRoot.removeClass(this.toolId);
if (overlay.containsPixel(col, row)) {
if(overlay.getPixel(col, row) != Constants.SELECTION_TRANSPARENT_COLOR) {
// We're hovering the selection, show the move tool:
this.BodyRoot.addClass(this.toolId);
this.BodyRoot.removeClass(this.secondaryToolId);
} else {
// We're not hovering the selection, show create selection tool:
this.BodyRoot.addClass(this.secondaryToolId);
this.BodyRoot.removeClass(this.toolId);
}
}
};

View File

@ -83,11 +83,17 @@
};
ns.Frame.prototype.setPixel = function (col, row, color) {
this.pixels[col][row] = color;
if (this.containsPixel(col, row)) {
this.pixels[col][row] = color;
}
};
ns.Frame.prototype.getPixel = function (col, row) {
return this.pixels[col][row];
if (this.containsPixel(col, row)) {
return this.pixels[col][row];
} else {
return null;
}
};
ns.Frame.prototype.forEachPixel = function (callback) {
@ -107,7 +113,7 @@
};
ns.Frame.prototype.containsPixel = function (col, row) {
return col >= 0 && row >= 0 && col < this.pixels.length && row < this.pixels[0].length;
return col >= 0 && row >= 0 && col < this.width && row < this.height;
};
ns.Frame.prototype.saveState = function () {

View File

@ -100,6 +100,7 @@ exports.scripts = [
// Tools
"js/drawingtools/BaseTool.js",
"js/drawingtools/ShapeTool.js",
"js/drawingtools/SimplePen.js",
"js/drawingtools/VerticalMirrorPen.js",
"js/drawingtools/Eraser.js",