Merge pull request #78 from juliandescottes/add-circletool

Add circletool
This commit is contained in:
Julian Descottes 2012-09-14 14:51:33 -07:00
commit 76838e64b9
10 changed files with 179 additions and 130 deletions

View File

@ -45,6 +45,10 @@
background-image: url(../img/tools/icons/rectangle.png); background-image: url(../img/tools/icons/rectangle.png);
} }
.tool-icon.tool-circle {
background-image: url(../img/tools/cursors/circle.png);
}
.tool-icon.tool-move { .tool-icon.tool-move {
background-image: url(../img/tools/icons/hand.png); background-image: url(../img/tools/icons/hand.png);
} }
@ -77,6 +81,10 @@
cursor: url(../img/tools/cursors/rectangle.png) 4 21, pointer; cursor: url(../img/tools/cursors/rectangle.png) 4 21, pointer;
} }
.tool-circle .drawing-canvas-container:hover {
cursor: url(../img/tools/cursors/circle.png) 4 21, pointer;
}
.tool-move .drawing-canvas-container:hover { .tool-move .drawing-canvas-container:hover {
cursor: url(../img/tools/cursors/hand.png) 14 12, pointer; cursor: url(../img/tools/cursors/hand.png) 14 12, pointer;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 761 B

View File

@ -31,6 +31,7 @@
<li class="tool-icon tool-paint-bucket" data-tool-id="tool-paint-bucket" title="Bucket tool"></li> <li class="tool-icon tool-paint-bucket" data-tool-id="tool-paint-bucket" title="Bucket tool"></li>
<li class="tool-icon tool-stroke" data-tool-id="tool-stroke" title="Stroke tool"></li> <li class="tool-icon tool-stroke" data-tool-id="tool-stroke" title="Stroke tool"></li>
<li class="tool-icon tool-rectangle" data-tool-id="tool-rectangle" title="Rectangle tool"></li> <li class="tool-icon tool-rectangle" data-tool-id="tool-rectangle" title="Rectangle tool"></li>
<li class="tool-icon tool-circle" data-tool-id="tool-circle" title="Circle tool"></li>
<li class="tool-icon tool-move" data-tool-id="tool-move" title="Move tool"></li> <li class="tool-icon tool-move" data-tool-id="tool-move" title="Move tool"></li>
<li class="tool-icon tool-select" data-tool-id="tool-select" title="Move tool"></li> <li class="tool-icon tool-select" data-tool-id="tool-select" title="Move tool"></li>
</ul> </ul>
@ -113,12 +114,16 @@
<script src="js/selection/RectangularSelection.js"></script> <script src="js/selection/RectangularSelection.js"></script>
<script src="js/Palette.js"></script> <script src="js/Palette.js"></script>
<script src="js/Notification.js"></script> <script src="js/Notification.js"></script>
<!-- Tools-->
<script src="js/drawingtools/BaseTool.js"></script> <script src="js/drawingtools/BaseTool.js"></script>
<script src="js/drawingtools/SimplePen.js"></script> <script src="js/drawingtools/SimplePen.js"></script>
<script src="js/drawingtools/Eraser.js"></script> <script src="js/drawingtools/Eraser.js"></script>
<script src="js/drawingtools/Stroke.js"></script> <script src="js/drawingtools/Stroke.js"></script>
<script src="js/drawingtools/PaintBucket.js"></script> <script src="js/drawingtools/PaintBucket.js"></script>
<script src="js/drawingtools/Rectangle.js"></script> <script src="js/drawingtools/Rectangle.js"></script>
<script src="js/drawingtools/Circle.js"></script>
<script src="js/drawingtools/Move.js"></script> <script src="js/drawingtools/Move.js"></script>
<script src="js/drawingtools/RectangularSelect.js"></script> <script src="js/drawingtools/RectangularSelect.js"></script>
<script src="js/ToolSelector.js"></script> <script src="js/ToolSelector.js"></script>

View File

@ -1,50 +1,48 @@
(function () { (function () {
var ns = $.namespace("pskl"); var ns = $.namespace("pskl");
ns.KeyManager = function () { ns.KeyManager = function () {
$(document.body).keydown($.proxy(this.onKeyUp_, this)); $(document.body).keydown($.proxy(this.onKeyUp_, this));
}; };
// Kind of object that make you want to stop front-end _engineering_: // Kind of object that make you want to stop front-end _engineering_:
ns.KeyManager.prototype.CharCodeToKeyCodeMap = { ns.KeyManager.prototype.CharCodeToKeyCodeMap = {
90 : "z", 90 : "z",
89 : "y", 89 : "y",
88 : "x", 88 : "x",
67 : "c", 67 : "c",
86 : "v" 86 : "v"
}; };
ns.KeyManager.prototype.KeyboardActions = { ns.KeyManager.prototype.KeyboardActions = {
"ctrl" : { "ctrl" : {
"z" : Events.UNDO, "z" : Events.UNDO,
"y" : Events.REDO, "y" : Events.REDO,
"x" : Events.CUT, "x" : Events.CUT,
"c" : Events.COPY, "c" : Events.COPY,
"v" : Events.PASTE "v" : Events.PASTE
} }
}; };
ns.KeyManager.prototype.onKeyUp_ = function(evt) {
var isMac = false;
ns.KeyManager.prototype.onKeyUp_ = function(evt) { if (navigator.appVersion.indexOf("Mac")!=-1) {
var isMac = false; // Welcome in mac world where vowels are consons and meta used instead of ctrl:
if (navigator.appVersion.indexOf("Mac")!=-1) { isMac = true;
// Welcome in mac world where vowels are consons and meta used instead of ctrl: }
isMac = true;
} if (isMac ? evt.metaKey : evt.ctrlKey) {
// Get key pressed:
if (isMac ? evt.metaKey : evt.ctrlKey) { var letter = this.CharCodeToKeyCodeMap[evt.which];
// Get key pressed: if(letter) {
var letter = this.CharCodeToKeyCodeMap[evt.which]; var eventToTrigger = this.KeyboardActions.ctrl[letter];
if(letter) { if(eventToTrigger) {
var eventToTrigger = this.KeyboardActions["ctrl"][letter]; $.publish(eventToTrigger);
if(eventToTrigger) { }
$.publish(eventToTrigger); }
} }
}; };
}
};
})(); })();

View File

@ -15,6 +15,7 @@ pskl.ToolSelector = (function() {
"paintBucket" : new pskl.drawingtools.PaintBucket(), "paintBucket" : new pskl.drawingtools.PaintBucket(),
"stroke" : new pskl.drawingtools.Stroke(), "stroke" : new pskl.drawingtools.Stroke(),
"rectangle" : new pskl.drawingtools.Rectangle(), "rectangle" : new pskl.drawingtools.Rectangle(),
"circle" : new pskl.drawingtools.Circle(),
"move" : new pskl.drawingtools.Move(), "move" : new pskl.drawingtools.Move(),
"select" : new pskl.drawingtools.Select() "select" : new pskl.drawingtools.Select()
}; };

View File

@ -208,7 +208,6 @@
ns.PreviewFilmController.prototype.onDeleteButtonClick_ = function (index, evt) { ns.PreviewFilmController.prototype.onDeleteButtonClick_ = function (index, evt) {
this.framesheet.removeFrameByIndex(index); this.framesheet.removeFrameByIndex(index);
$.publish(Events.FRAMESHEET_RESET);
$.publish(Events.LOCALSTORAGE_REQUEST); // Should come from model $.publish(Events.LOCALSTORAGE_REQUEST); // Should come from model
}; };

84
js/drawingtools/Circle.js Normal file
View File

@ -0,0 +1,84 @@
/*
* @provide pskl.drawingtools.Circle
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
ns.Circle = function() {
this.toolId = "tool-circle"
// Circle's first point coordinates (set in applyToolAt)
this.startCol = null;
this.startRow = null;
};
pskl.utils.inherit(ns.Circle, ns.BaseTool);
/**
* @override
*/
ns.Circle.prototype.applyToolAt = function(col, row, color, frame, overlay) {
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) {
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) {
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) {
var circlePoints = this.getCirclePixels_(this.startCol, this.startRow, col, row);
for(var i = 0; i< circlePoints.length; i++) {
// Change model:
targetFrame.setPixel(circlePoints[i].col, circlePoints[i].row, color);
}
};
ns.Circle.prototype.getCirclePixels_ = function (x0, y0, x1, y1) {
var coords = pskl.PixelUtils.getOrderedRectangleCoordinates(x0, y0, x1, y1);
var xC = (coords.x0 + coords.x1)/2;
var yC = (coords.y0 + coords.y1)/2;
var rX = coords.x1 - xC;
var rY = coords.y1 - yC;
var pixels = [];
var x, y, angle;
for (x = coords.x0 ; x < coords.x1 ; x++) {
angle = Math.acos((x - xC)/rX);
y = Math.round(rY * Math.sin(angle) + yC);
pixels.push({"col": x, "row": y});
pixels.push({"col": 2*xC - x, "row": 2*yC - y});
}
for (y = coords.y0 ; y < coords.y1 ; y++) {
angle = Math.asin((y - yC)/rY);
x = Math.round(rX * Math.cos(angle) + xC);
pixels.push({"col": x, "row": y});
pixels.push({"col": 2*xC - x, "row": 2*yC - y});
}
return pixels;
};
})();

View File

@ -29,20 +29,12 @@
ns.Rectangle.prototype.moveToolAt = function(col, row, color, frame, overlay) { ns.Rectangle.prototype.moveToolAt = function(col, row, color, frame, overlay) {
overlay.clear(); overlay.clear();
// When the user moussemove (before releasing), we dynamically compute the
// pixel to draw the line and draw this line in the overlay :
var strokePoints = pskl.PixelUtils.getBoundRectanglePixels(this.startCol, this.startRow, col, row);
if(color == Constants.TRANSPARENT_COLOR) { if(color == Constants.TRANSPARENT_COLOR) {
color = Constants.SELECTION_TRANSPARENT_COLOR; color = Constants.SELECTION_TRANSPARENT_COLOR;
} }
// Drawing current stroke: // draw in overlay
for(var i = 0; i< strokePoints.length; i++) { this.drawRectangle_(col, row, color, overlay);
overlay.setPixel(strokePoints[i].col, strokePoints[i].row, color);
}
}; };
/** /**
@ -50,52 +42,17 @@
*/ */
ns.Rectangle.prototype.releaseToolAt = function(col, row, color, frame, overlay) { ns.Rectangle.prototype.releaseToolAt = function(col, row, color, frame, overlay) {
overlay.clear(); overlay.clear();
// If the stroke tool is released outside of the canvas, we cancel the stroke: if(frame.containsPixel(col, row)) { // cancel if outside of canvas
if(frame.containsPixel(col, row)) { // draw in frame to finalize
var strokePoints = pskl.PixelUtils.getBoundRectanglePixels(this.startCol, this.startRow, col, row); this.drawRectangle_(col, row, color, frame);
for(var i = 0; i< strokePoints.length; i++) {
// Change model:
frame.setPixel(strokePoints[i].col, strokePoints[i].row, color);
}
// The user released the tool to draw a line. We will compute the pixel coordinate, impact
// the model and draw them in the drawing canvas (not the fake overlay anymore)
} }
}; };
/** ns.Rectangle.prototype.drawRectangle_ = function (col, row, color, targetFrame) {
* Get an array of pixels representing the rectangle. var strokePoints = pskl.PixelUtils.getBoundRectanglePixels(this.startCol, this.startRow, col, row);
* for(var i = 0; i< strokePoints.length; i++) {
* @private // Change model:
*/ targetFrame.setPixel(strokePoints[i].col, strokePoints[i].row, color);
ns.Rectangle.prototype.getRectanglePixels_ = function(x0, x1, y0, y1) {
var pixels = [];
var swap;
if(x0 > x1) {
swap = x0;
x0 = x1;
x1 = swap;
} }
if(y0 > y1) { };
swap = y0;
y0 = y1;
y1 = swap;
}
// Creating horizontal sides of the rectangle:
for(var x = x0; x <= x1; x++) {
pixels.push({"col": x, "row": y0});
pixels.push({"col": x, "row": y1});
}
// Creating vertical sides of the rectangle:
for(var y = y0; y <= y1; y++) {
pixels.push({"col": x0, "row": y});
pixels.push({"col": x1, "row": y});
}
return pixels;
};
})(); })();

View File

@ -96,6 +96,14 @@
throw "Out of bound index for frameSheet object."; throw "Out of bound index for frameSheet object.";
} }
this.frames.splice(index, 1); this.frames.splice(index, 1);
// Current frame index might not be valid anymore
if (!this.hasFrameAtIndex(this.currentFrameIndex)) {
// if not select last frame available
this.setCurrentFrameIndex(this.getFrameCount() - 1);
}
$.publish(Events.FRAMESHEET_RESET);
}; };
ns.FrameSheet.prototype.duplicateFrameByIndex = function(index) { ns.FrameSheet.prototype.duplicateFrameByIndex = function(index) {

View File

@ -4,22 +4,11 @@
ns.PixelUtils = { ns.PixelUtils = {
getRectanglePixels : function (x0, y0, x1, y1) { getRectanglePixels : function (x0, y0, x1, y1) {
var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1);
var pixels = []; var pixels = [];
var swap;
if(x0 > x1) {
swap = x0;
x0 = x1;
x1 = swap;
}
if(y0 > y1) {
swap = y0;
y0 = y1;
y1 = swap;
}
for(var x = x0; x <= x1; x++) { for(var x = rectangle.x0; x <= rectangle.x1; x++) {
for(var y = y0; y <= y1; y++) { for(var y = rectangle.y0; y <= rectangle.y1; y++) {
pixels.push({"col": x, "row": y}); pixels.push({"col": x, "row": y});
} }
} }
@ -28,33 +17,33 @@
}, },
getBoundRectanglePixels : function (x0, y0, x1, y1) { getBoundRectanglePixels : function (x0, y0, x1, y1) {
var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1);
var pixels = []; var pixels = [];
var swap;
if(x0 > x1) {
swap = x0;
x0 = x1;
x1 = swap;
}
if(y0 > y1) {
swap = y0;
y0 = y1;
y1 = swap;
}
// Creating horizontal sides of the rectangle: // Creating horizontal sides of the rectangle:
for(var x = x0; x <= x1; x++) { for(var x = rectangle.x0; x <= rectangle.x1; x++) {
pixels.push({"col": x, "row": y0}); pixels.push({"col": x, "row": rectangle.y0});
pixels.push({"col": x, "row": y1}); pixels.push({"col": x, "row": rectangle.y1});
} }
// Creating vertical sides of the rectangle: // Creating vertical sides of the rectangle:
for(var y = y0; y <= y1; y++) { for(var y = rectangle.y0; y <= rectangle.y1; y++) {
pixels.push({"col": x0, "row": y}); pixels.push({"col": rectangle.x0, "row": y});
pixels.push({"col": x1, "row": y}); pixels.push({"col": rectangle.x1, "row": y});
} }
return pixels; return pixels;
} },
/**
* Return an object of ordered rectangle coordinate.
* In returned object {x0, y0} => top left corner - {x1, y1} => bottom right corner
* @private
*/
getOrderedRectangleCoordinates : function (x0, y0, x1, y1) {
return {
x0 : Math.min(x0, x1), y0 : Math.min(y0, y1),
x1 : Math.max(x0, x1), y1 : Math.max(y0, y1),
};
}
}; };
})(); })();