Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

reorganize image cropping/uncropping

split the CanvasImage class into its own file
  • Loading branch information...
commit 956046a90e105c3603525385e9e4679cf3ba1152 1 parent a0212d3
@caleb authored
View
189 lib/canvas-image.coffee
@@ -0,0 +1,189 @@
+`import drawing from "drawing"`
+
+class CanvasImage extends drawing.Drawable
+ constructor: (options) ->
+ super options
+
+ @source = options.source
+ @naturalWidth = options.naturalWidth
+ @naturalHeight = options.naturalHeight
+ @originalNaturalBounds = @naturalBounds()
+ @cropped = false
+ @history = []
+ @loaded = false
+
+ @cropX = 0
+ @cropY = 0
+ @cropWidth = @naturalWidth
+ @cropHeight = @naturalHeight
+
+ @loadImage()
+
+ clearImage: () ->
+ @loaded = false
+ @cropped = false
+ @w = null
+ @h = null
+ @naturalWidth = null
+ @naturalHeight = null
+ @history = []
+ @originalNaturalBounds = @naturalBounds()
+
+ @markDirty()
+
+ setSource: (source) ->
+ @clearImage()
+ @source = source
+ @loadImage()
+
+ naturalBounds: () ->
+ {
+ x: 0
+ y: 0
+ w: @naturalWidth
+ h: @naturalHeight
+ }
+
+ cropFrame: () ->
+ {
+ x: @cropX
+ y: @cropY
+ w: @cropWidth
+ h: @cropHeight
+ }
+
+ crop: (frame) ->
+ unless @cropped
+ @cropped = true
+ @cropX = @cropY = 0
+
+ previousCrop = @cropFrame()
+
+ @cropX = frame.x + @cropX
+ @cropY = frame.y + @cropY
+ @cropWidth = frame.width
+ @cropHeight = frame.height
+
+ @naturalWidth = @cropWidth
+ @naturalHeight = @cropHeight
+
+ @resizeToParent()
+ @centerOnParent()
+
+ @history.push
+ action: 'crop'
+ fromCropFrame: previousCrop
+ toCropFrame: @cropFrame()
+
+ @trigger 'crop', @, previousCrop, @cropFrame()
+
+ @markDirty()
+
+ undoCrop: () ->
+ if @history.length > 0
+ cropHistory = @history.pop()
+ newCropFrame = cropHistory.fromCropFrame
+
+ @cropX = newCropFrame.x
+ @cropY = newCropFrame.y
+ @cropWidth = newCropFrame.w
+ @cropHeight = newCropFrame.h
+ @naturalWidth = newCropFrame.w
+ @naturalHeight = newCropFrame.h
+
+ @resizeToParent()
+ @centerOnParent()
+
+ @cropped = false if @history.length == 0
+
+ @trigger 'crop', @, cropHistory.toCropFrame, @cropFrame()
+
+ @markDirty()
+
+ revertImage: () ->
+ @cropped = false
+
+ if @history.length > 0
+ cropHistory = @history.pop()
+
+ @cropX = 0
+ @cropY = 0
+ @cropWidth = @originalNaturalBounds.w
+ @cropHeight = @originalNaturalBounds.h
+ @naturalWidth = @originalNaturalBounds.w
+ @naturalHeight = @originalNaturalBounds.h
+
+ @resizeToParent()
+ @centerOnParent()
+
+ @trigger 'crop', @, cropHistory.toCropFrame, @cropFrame()
+
+ @history = []
+
+ @markDirty()
+
+ resizeToParent: () ->
+ cw = @parent.frame().w
+ ch = @parent.frame().h
+
+ scaleX = 1
+ scaleY = 1
+
+ scaleX = cw / @naturalWidth if @naturalWidth > cw
+ scaleY = ch / @naturalHeight if @naturalHeight > ch
+
+ @scale = Math.min scaleX, scaleY
+ @w = (@naturalWidth * @scale)|0
+ @h = (@naturalHeight * @scale)|0
+
+ @trigger 'resize', @frame()
+
+ centerOnParent: () ->
+ @x = ((@parent.frame().w / 2) - (@w / 2))|0
+ @y = ((@parent.frame().h / 2) - (@h / 2))|0
+
+ @trigger 'reposition', @frame()
+
+ toDataURL: (format = 'image/png') ->
+ canvas = document.createElement 'canvas'
+ canvas.width = @cropWidth
+ canvas.height = @cropHeight
+ ctx = canvas.getContext '2d'
+
+ if @cropped
+ ctx.drawImage @img, @cropX, @cropY, @cropWidth, @cropHeight, 0, 0, @cropWidth, @cropHeight
+ else
+ ctx.drawImage @img, 0, 0, @cropWidth, @cropHeight
+
+ canvas.toDataURL format
+
+ draw: (ctx) ->
+ @positionContext ctx, (ctx) ->
+ if @cropped
+ ctx.drawImage @img, @cropX, @cropY, @cropWidth, @cropHeight, 0, 0, @w, @h
+ else
+ ctx.drawImage @img, 0, 0, @w, @h
+
+ loadImage: ->
+ @img = document.createElement 'img'
+ @img.onload = =>
+ @loaded = true
+ @naturalWidth = @img.naturalWidth
+ @naturalHeight = @img.naturalHeight
+
+ @cropped = false
+ @history = []
+
+ @cropX = 0
+ @cropY = 0
+ @cropWidth = @img.naturalWidth
+ @cropHeight = @img.naturalHeight
+
+ @originalNaturalBounds = @naturalBounds()
+
+ @markDirty()
+
+ @trigger 'load', @
+ @img.src = @source
+
+`export default CanvasImage`
View
184 lib/drawing.coffee
@@ -214,190 +214,6 @@ class PaddedContainer extends Drawable
drawing.PaddedContainer = PaddedContainer
-class CanvasImage extends Drawable
- constructor: (options) ->
- super options
-
- @source = options.source
- @naturalWidth = options.naturalWidth
- @naturalHeight = options.naturalHeight
- @originalNaturalBounds = @naturalBounds()
- @cropped = false
- @cropStack = []
- @loaded = false
-
- @cropX = 0
- @cropY = 0
- @cropWidth = @naturalWidth
- @cropHeight = @naturalHeight
-
- @loadImage()
-
- clearImage: () ->
- @loaded = false
- @cropped = false
- @w = null
- @h = null
- @naturalWidth = null
- @naturalHeight = null
- @cropStack = []
- @originalNaturalBounds = @naturalBounds()
-
- @markDirty()
-
- setSource: (source) ->
- @clearImage()
- @source = source
- @loadImage()
-
- naturalBounds: () ->
- {
- x: 0
- y: 0
- w: @naturalWidth
- h: @naturalHeight
- }
-
- cropFrame: () ->
- {
- x: @cropX
- y: @cropY
- w: @cropWidth
- h: @cropHeight
- }
-
- crop: (frame) ->
- unless @cropped
- @cropped = true
- @cropX = @cropY = 0
-
- @cropX = frame.x + @cropX
- @cropY = frame.y + @cropY
- @cropWidth = frame.width
- @cropHeight = frame.height
-
- @naturalWidth = @cropWidth
- @naturalHeight = @cropHeight
-
- @resizeToParent()
- @centerOnParent()
-
- @cropStack.push @cropFrame()
-
- @trigger 'crop', @, @cropStack[@cropStack.length - 2], @cropFrame()
-
- @markDirty()
-
- undoCrop: () ->
- if @cropStack.length > 1
- previousCropFrame = @cropStack.pop()
- newCropFrame = @cropStack[@cropStack.length - 1]
-
- @cropX = newCropFrame.x
- @cropY = newCropFrame.y
- @cropWidth = newCropFrame.w
- @cropHeight = newCropFrame.h
- @naturalWidth = newCropFrame.w
- @naturalHeight = newCropFrame.h
-
- @resizeToParent()
- @centerOnParent()
-
- @cropped = false if @cropStack.length == 1
-
- @trigger 'crop', @, previousCropFrame, @cropFrame()
-
- @markDirty()
-
- revertImage: () ->
- @cropped = false
-
- if @cropStack.length > 1
- originalCropFrame = @cropStack[@cropStack.length - 1]
- newCropFrame = @cropStack[0]
-
- @cropX = newCropFrame.x
- @cropY = newCropFrame.y
- @cropWidth = newCropFrame.w
- @cropHeight = newCropFrame.h
- @naturalWidth = newCropFrame.w
- @naturalHeight = newCropFrame.h
-
- @resizeToParent()
- @centerOnParent()
-
- @cropStack = [newCropFrame]
-
- @trigger 'crop', @, originalCropFrame, newCropFrame
-
- @markDirty()
-
- resizeToParent: () ->
- cw = @parent.frame().w
- ch = @parent.frame().h
-
- scaleX = 1
- scaleY = 1
-
- scaleX = cw / @naturalWidth if @naturalWidth > cw
- scaleY = ch / @naturalHeight if @naturalHeight > ch
-
- @scale = Math.min scaleX, scaleY
- @w = (@naturalWidth * @scale)|0
- @h = (@naturalHeight * @scale)|0
-
- @trigger 'resize', @frame()
-
- centerOnParent: () ->
- @x = ((@parent.frame().w / 2) - (@w / 2))|0
- @y = ((@parent.frame().h / 2) - (@h / 2))|0
-
- @trigger 'reposition', @frame()
-
- toDataURL: (format = 'image/png') ->
- canvas = document.createElement 'canvas'
- canvas.width = @cropWidth
- canvas.height = @cropHeight
- ctx = canvas.getContext '2d'
-
- if @cropped
- ctx.drawImage @img, @cropX, @cropY, @cropWidth, @cropHeight, 0, 0, @cropWidth, @cropHeight
- else
- ctx.drawImage @img, 0, 0, @cropWidth, @cropHeight
-
- canvas.toDataURL format
-
- draw: (ctx) ->
- @positionContext ctx, (ctx) ->
- if @cropped
- ctx.drawImage @img, @cropX, @cropY, @cropWidth, @cropHeight, 0, 0, @w, @h
- else
- ctx.drawImage @img, 0, 0, @w, @h
-
- loadImage: ->
- @img = document.createElement 'img'
- @img.onload = =>
- @loaded = true
- @naturalWidth = @img.naturalWidth
- @naturalHeight = @img.naturalHeight
-
- @cropped = false
- @cropStack = []
-
- @cropX = 0
- @cropY = 0
- @cropWidth = @img.naturalWidth
- @cropHeight = @img.naturalHeight
-
- @cropStack.push @cropFrame()
-
- @markDirty()
-
- @trigger 'load', @
- @img.src = @source
-
-drawing.CanvasImage = CanvasImage
-
class Rectangle extends Drawable
constructor: (options) ->
super options
View
3  lib/rodeo-crop.coffee
@@ -1,6 +1,7 @@
`import _ from "funderscore"`
`import drawing from "drawing"`
`import Events from "events"`
+`import CanvasImage from "canvas-image"`
`import CropBox from "crop-box"`
`import Stage from "stage"`
@@ -54,7 +55,7 @@ class Cropper extends Events
@paddedContainer = new drawing.PaddedContainer
padding: (@options.handleSize / 2) + 1
- @image = new drawing.CanvasImage
+ @image = new CanvasImage
canvas: @canvas
source: @imageSource
View
1,894 rodeo-crop.js
@@ -51,521 +51,557 @@ var define, requireModule, require, requirejs;
}
};
})();
-define("crop-box",
- ["funderscore","drawing","exports"],
- function(__dependency1__, __dependency2__, __exports__) {
+define("canvas-image",
+ ["drawing","exports"],
+ function(__dependency1__, __exports__) {
"use strict";
- var _ = __dependency1__["default"];
- var drawing = __dependency2__["default"];
- var CropBox,
+ var drawing = __dependency1__["default"];
+ var CanvasImage,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
- CropBox = (function(_super) {
- __extends(CropBox, _super);
+ CanvasImage = (function(_super) {
+ __extends(CanvasImage, _super);
- function CropBox(options) {
- CropBox.__super__.constructor.call(this, _.extend({
- dragable: true
- }, options));
- this.image = options.image;
- this.handleSize = options.handleSize || 10;
- this.screenStyle = options.screenStyle || 'rgba(0, 0, 0, .75)';
- this.topScreen = new drawing.Rectangle({
- fillStyle: this.screenStyle
- });
- this.leftScreen = new drawing.Rectangle({
- fillStyle: this.screenStyle
- });
- this.rightScreen = new drawing.Rectangle({
- fillStyle: this.screenStyle
- });
- this.bottomScreen = new drawing.Rectangle({
- fillStyle: this.screenStyle
- });
- this.cropX = options.cropX || 0;
- this.cropY = options.cropY || 0;
- this.cropWidth = options.cropWidth || this.handleSize * 4;
- this.cropHeight = options.cropHeight || this.handleSize * 4;
- this.marchingAnts = options.marchingAnts || true;
- this.dashOffset = 0;
- this.dragging = null;
- this.mouseDown = false;
- this.handles = {};
- this.image.on('load', (function(_this) {
- return function() {
- return _this.setCropFrameAndUpdateFrame(_this.cropFrame());
- };
- })(this));
- this.image.on('crop', (function(_this) {
- return function(image, previousCrop, crop) {
- _this.cropX = previousCrop.w >= crop.w ? 0 : previousCrop.x - crop.x;
- _this.cropY = previousCrop.h >= crop.h ? 0 : previousCrop.y - crop.y;
- _this.cropWidth = previousCrop.w >= crop.w ? crop.w : previousCrop.w;
- _this.cropHeight = previousCrop.h >= crop.h ? crop.h : previousCrop.h;
- return _this.setCropFrameAndUpdateFrame(_this.cropFrame());
- };
- })(this));
- this.on('mouseout', this.onMouseOut);
- this.on('mousemove', this.onMouseMove);
- this.on('mousedown', this.onMouseDown);
- this.on('mouseup', this.onMouseUp);
- this.on('dragstart', this.onDragStart);
- this.on('dragend', this.onDragEnd);
- this.on('dragmove', this.onDragMove);
- this.setLooseTheAnts();
+ function CanvasImage(options) {
+ CanvasImage.__super__.constructor.call(this, options);
+ this.source = options.source;
+ this.naturalWidth = options.naturalWidth;
+ this.naturalHeight = options.naturalHeight;
+ this.originalNaturalBounds = this.naturalBounds();
+ this.cropped = false;
+ this.history = [];
+ this.loaded = false;
+ this.cropX = 0;
+ this.cropY = 0;
+ this.cropWidth = this.naturalWidth;
+ this.cropHeight = this.naturalHeight;
+ this.loadImage();
}
- CropBox.prototype.frame = function() {
+ CanvasImage.prototype.clearImage = function() {
+ this.loaded = false;
+ this.cropped = false;
+ this.w = null;
+ this.h = null;
+ this.naturalWidth = null;
+ this.naturalHeight = null;
+ this.history = [];
+ this.originalNaturalBounds = this.naturalBounds();
+ return this.markDirty();
+ };
+
+ CanvasImage.prototype.setSource = function(source) {
+ this.clearImage();
+ this.source = source;
+ return this.loadImage();
+ };
+
+ CanvasImage.prototype.naturalBounds = function() {
return {
- x: this.w < 0 ? this.x + this.w : this.x,
- y: this.h < 0 ? this.y + this.h : this.y,
- w: Math.abs(this.w),
- h: Math.abs(this.h)
+ x: 0,
+ y: 0,
+ w: this.naturalWidth,
+ h: this.naturalHeight
};
};
- CropBox.prototype.cropFrame = function() {
+ CanvasImage.prototype.cropFrame = function() {
return {
x: this.cropX,
y: this.cropY,
- width: this.cropWidth,
- height: this.cropHeight
+ w: this.cropWidth,
+ h: this.cropHeight
};
};
- CropBox.prototype.updateCropFrameFromFrame = function() {
- var frame, imageBounds, naturalBounds;
- frame = this.frame();
- naturalBounds = this.image.naturalBounds();
- imageBounds = this.image.bounds();
- if (this.image.loaded) {
- this.cropX = naturalBounds.w * (frame.x / imageBounds.w);
- this.cropY = naturalBounds.h * (frame.y / imageBounds.h);
- this.cropWidth = naturalBounds.w * (frame.w / imageBounds.w);
- this.cropHeight = naturalBounds.h * (frame.h / imageBounds.h);
+ CanvasImage.prototype.crop = function(frame) {
+ var previousCrop;
+ if (!this.cropped) {
+ this.cropped = true;
+ this.cropX = this.cropY = 0;
}
- return this.trigger('change:cropFrame', this.cropFrame());
+ previousCrop = this.cropFrame();
+ this.cropX = frame.x + this.cropX;
+ this.cropY = frame.y + this.cropY;
+ this.cropWidth = frame.width;
+ this.cropHeight = frame.height;
+ this.naturalWidth = this.cropWidth;
+ this.naturalHeight = this.cropHeight;
+ this.resizeToParent();
+ this.centerOnParent();
+ this.history.push({
+ action: 'crop',
+ fromCropFrame: previousCrop,
+ toCropFrame: this.cropFrame()
+ });
+ this.trigger('crop', this, previousCrop, this.cropFrame());
+ return this.markDirty();
};
- CropBox.prototype.setFrameAndUpdateCropArea = function(frame) {
- this.x = frame.x;
- this.y = frame.y;
- this.w = frame.w;
- this.h = frame.h;
- this.updateCropFrameFromFrame();
- return this.markDirty();
+ CanvasImage.prototype.undoCrop = function() {
+ var cropHistory, newCropFrame;
+ if (this.history.length > 0) {
+ cropHistory = this.history.pop();
+ newCropFrame = cropHistory.fromCropFrame;
+ this.cropX = newCropFrame.x;
+ this.cropY = newCropFrame.y;
+ this.cropWidth = newCropFrame.w;
+ this.cropHeight = newCropFrame.h;
+ this.naturalWidth = newCropFrame.w;
+ this.naturalHeight = newCropFrame.h;
+ this.resizeToParent();
+ this.centerOnParent();
+ if (this.history.length === 0) {
+ this.cropped = false;
+ }
+ this.trigger('crop', this, cropHistory.toCropFrame, this.cropFrame());
+ return this.markDirty();
+ }
};
- CropBox.prototype.updateFrameFromCropFrame = function() {
- var imageBounds, naturalBounds;
- if (this.image.loaded) {
- naturalBounds = this.image.naturalBounds();
- imageBounds = this.image.bounds();
- this.x = imageBounds.w * (this.cropX / naturalBounds.w);
- this.y = imageBounds.h * (this.cropY / naturalBounds.h);
- this.w = imageBounds.w * (this.cropWidth / naturalBounds.w);
- this.h = imageBounds.h * (this.cropHeight / naturalBounds.h);
+ CanvasImage.prototype.revertImage = function() {
+ var cropHistory;
+ this.cropped = false;
+ if (this.history.length > 0) {
+ cropHistory = this.history.pop();
+ this.cropX = 0;
+ this.cropY = 0;
+ this.cropWidth = this.originalNaturalBounds.w;
+ this.cropHeight = this.originalNaturalBounds.h;
+ this.naturalWidth = this.originalNaturalBounds.w;
+ this.naturalHeight = this.originalNaturalBounds.h;
+ this.resizeToParent();
+ this.centerOnParent();
+ this.trigger('crop', this, cropHistory.toCropFrame, this.cropFrame());
+ this.history = [];
return this.markDirty();
}
};
- CropBox.prototype.setCropFrameAndUpdateFrame = function(cropArea) {
- var naturalBounds, newCropHeight, newCropWidth, newCropX, newCropY;
- if (this.image.loaded) {
- naturalBounds = this.image.naturalBounds();
- newCropX = (cropArea != null ? cropArea.x : void 0) || naturalBounds.w * .125;
- newCropY = (cropArea != null ? cropArea.y : void 0) || naturalBounds.h * .125;
- newCropWidth = (cropArea != null ? cropArea.width : void 0) || naturalBounds.w * .75;
- newCropHeight = (cropArea != null ? cropArea.height : void 0) || naturalBounds.h * .75;
- this.cropX = Math.min(Math.max(newCropX, 0), naturalBounds.w);
- this.cropY = Math.min(Math.max(newCropY, 0), naturalBounds.h);
- this.cropWidth = Math.min(Math.max(newCropWidth, 0), naturalBounds.w - this.cropX);
- this.cropHeight = Math.min(Math.max(newCropHeight, 0), naturalBounds.h - this.cropY);
- return this.updateFrameFromCropFrame();
- } else {
- this.cropX = cropArea != null ? cropArea.x : void 0;
- this.cropY = cropArea != null ? cropArea.y : void 0;
- this.cropWidth = cropArea != null ? cropArea.width : void 0;
- return this.cropHeight = cropArea != null ? cropArea.height : void 0;
+ CanvasImage.prototype.resizeToParent = function() {
+ var ch, cw, scaleX, scaleY;
+ cw = this.parent.frame().w;
+ ch = this.parent.frame().h;
+ scaleX = 1;
+ scaleY = 1;
+ if (this.naturalWidth > cw) {
+ scaleX = cw / this.naturalWidth;
+ }
+ if (this.naturalHeight > ch) {
+ scaleY = ch / this.naturalHeight;
}
+ this.scale = Math.min(scaleX, scaleY);
+ this.w = (this.naturalWidth * this.scale) | 0;
+ this.h = (this.naturalHeight * this.scale) | 0;
+ return this.trigger('resize', this.frame());
};
- CropBox.prototype.bounds = function() {
- return {
- x: 0,
- y: 0,
- w: Math.abs(this.w),
- h: Math.abs(this.h)
- };
+ CanvasImage.prototype.centerOnParent = function() {
+ this.x = ((this.parent.frame().w / 2) - (this.w / 2)) | 0;
+ this.y = ((this.parent.frame().h / 2) - (this.h / 2)) | 0;
+ return this.trigger('reposition', this.frame());
};
- CropBox.prototype.containsCanvasPoint = function(point) {
- var containsPoint, direction, handle, local, _ref;
- local = this.convertFromCanvas(point);
- containsPoint = this.containsPoint(local);
- if (containsPoint) {
- return containsPoint;
+ CanvasImage.prototype.toDataURL = function(format) {
+ var canvas, ctx;
+ if (format == null) {
+ format = 'image/png';
}
- _ref = this.handles;
- for (direction in _ref) {
- handle = _ref[direction];
- if (handle.containsCanvasPoint(point)) {
- return true;
- }
+ canvas = document.createElement('canvas');
+ canvas.width = this.cropWidth;
+ canvas.height = this.cropHeight;
+ ctx = canvas.getContext('2d');
+ if (this.cropped) {
+ ctx.drawImage(this.img, this.cropX, this.cropY, this.cropWidth, this.cropHeight, 0, 0, this.cropWidth, this.cropHeight);
+ } else {
+ ctx.drawImage(this.img, 0, 0, this.cropWidth, this.cropHeight);
}
- return false;
+ return canvas.toDataURL(format);
};
- CropBox.prototype.onMouseOut = function(e) {
- return this.canvas.style.cursor = 'default';
+ CanvasImage.prototype.draw = function(ctx) {
+ return this.positionContext(ctx, function(ctx) {
+ if (this.cropped) {
+ return ctx.drawImage(this.img, this.cropX, this.cropY, this.cropWidth, this.cropHeight, 0, 0, this.w, this.h);
+ } else {
+ return ctx.drawImage(this.img, 0, 0, this.w, this.h);
+ }
+ });
};
- CropBox.prototype.onMouseMove = function(e) {
- var direction, handle, point, _ref;
- if (!this.enabled) {
- return;
- }
- point = e.canvasPoint;
- _ref = this.handles;
- for (direction in _ref) {
- handle = _ref[direction];
- if (handle.containsCanvasPoint(point)) {
- switch (direction) {
- case 'tl':
- this.canvas.style.cursor = 'nw-resize';
- break;
- case 'tm':
- this.canvas.style.cursor = 'n-resize';
- break;
- case 'tr':
- this.canvas.style.cursor = 'ne-resize';
- break;
- case 'ml':
- this.canvas.style.cursor = 'w-resize';
- break;
- case 'mr':
- this.canvas.style.cursor = 'e-resize';
- break;
- case 'bl':
- this.canvas.style.cursor = 'sw-resize';
- break;
- case 'bm':
- this.canvas.style.cursor = 's-resize';
- break;
- case 'br':
- this.canvas.style.cursor = 'se-resize';
+ CanvasImage.prototype.loadImage = function() {
+ this.img = document.createElement('img');
+ this.img.onload = (function(_this) {
+ return function() {
+ _this.loaded = true;
+ _this.naturalWidth = _this.img.naturalWidth;
+ _this.naturalHeight = _this.img.naturalHeight;
+ _this.cropped = false;
+ _this.history = [];
+ _this.cropX = 0;
+ _this.cropY = 0;
+ _this.cropWidth = _this.img.naturalWidth;
+ _this.cropHeight = _this.img.naturalHeight;
+ _this.originalNaturalBounds = _this.naturalBounds();
+ _this.markDirty();
+ return _this.trigger('load', _this);
+ };
+ })(this);
+ return this.img.src = this.source;
+ };
+
+ return CanvasImage;
+
+ })(drawing.Drawable);
+
+ __exports__["default"] = CanvasImage;
+ });define("drawing",
+ ["funderscore","events","exports"],
+ function(__dependency1__, __dependency2__, __exports__) {
+ "use strict";
+ var _ = __dependency1__["default"];
+ var Events = __dependency2__["default"];
+ var Drawable, PaddedContainer, Rectangle, drawing,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ __slice = [].slice;
+
+ drawing = {};
+
+ Drawable = (function(_super) {
+ __extends(Drawable, _super);
+
+ function Drawable(options) {
+ this.options = options;
+ this.x = options.x;
+ this.y = options.y;
+ this.w = options.w;
+ this.h = options.h;
+ this.dirty = true;
+ this.scale = options.scale;
+ this.parent = options.parent;
+ this.canvas = options.canvas;
+ this.children = options.children || [];
+ this.dragable = options.dragable || false;
+ this.enabled = options.enabled !== void 0 ? !!options.enabled : true;
+ }
+
+ Drawable.prototype.set = function(options) {
+ var key, value, _results;
+ _results = [];
+ for (key in options) {
+ if (!__hasProp.call(options, key)) continue;
+ value = options[key];
+ _results.push(this[key] = value);
+ }
+ return _results;
+ };
+
+ Drawable.prototype.enable = function(enabled) {
+ var previous;
+ previous = this.enabled;
+ this.enabled = !!enabled;
+ this.markDirty();
+ if (previous !== this.enabled) {
+ if (this.enabled) {
+ return this.trigger('enabled', this);
+ } else {
+ return this.trigger('disabled', this);
+ }
+ }
+ };
+
+ Drawable.prototype.markDirty = function() {
+ this.dirty = true;
+ if (this.parent) {
+ return this.parent.markDirty();
+ }
+ };
+
+ Drawable.prototype.bubble = function() {
+ var args, event, eventName, parent, _results;
+ eventName = arguments[0], event = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
+ event.currentTarget = this;
+ this.trigger.apply(this, arguments);
+ parent = this.parent;
+ _results = [];
+ while (parent) {
+ event = _.clone(event);
+ event.currentTarget = parent;
+ parent.trigger.apply(parent, [eventName, event].concat(args));
+ _results.push(parent = parent.parent);
+ }
+ return _results;
+ };
+
+ Drawable.prototype.findChildAtPoint = function(point) {
+ var child, grandChild, i;
+ i = this.children.length - 1;
+ while (i >= 0) {
+ child = this.children[i];
+ grandChild = child.findChildAtPoint(point);
+ if (grandChild) {
+ return grandChild;
+ } else {
+ if (child.containsCanvasPoint(point)) {
+ return child;
}
- return;
}
+ i--;
}
- return this.canvas.style.cursor = 'move';
};
- CropBox.prototype.constrainPointInParent = function(point) {
+ Drawable.prototype.bounds = function() {
return {
- x: Math.min(Math.max(point.x, 0), this.parent.frame().w),
- y: Math.min(Math.max(point.y, 0), this.parent.frame().h)
+ x: 0,
+ y: 0,
+ w: this.w,
+ h: this.h
};
};
- CropBox.prototype.onMouseUp = function(point) {
- return this.dragging = this.mouseDown = null;
+ Drawable.prototype.frame = function() {
+ return {
+ x: this.x,
+ y: this.y,
+ w: this.w,
+ h: this.h
+ };
};
- CropBox.prototype.onDragStart = function(e) {
- var direction, handle, localPoint, point, _ref;
- point = e.canvasPoint;
- _ref = this.handles;
- for (direction in _ref) {
- handle = _ref[direction];
- if (handle.containsCanvasPoint(point)) {
- localPoint = handle.convertFromCanvas(point);
- this.dragging = {
- resizeDirection: direction,
- object: handle,
- offsetX: localPoint.x,
- offsetY: localPoint.y
- };
- return;
- }
+ Drawable.prototype.convertToParent = function(point) {
+ var frame;
+ frame = this.frame();
+ return {
+ x: point.x + frame.x,
+ y: point.y + frame.y
+ };
+ };
+
+ Drawable.prototype.convertFromParent = function(point) {
+ var frame;
+ frame = this.frame();
+ return {
+ x: point.x - frame.x,
+ y: point.y - frame.y
+ };
+ };
+
+ Drawable.prototype.convertToCanvas = function(point) {
+ var parent, x, y;
+ parent = this;
+ x = point.x;
+ y = point.y;
+ while (parent) {
+ x += parent.frame().x;
+ y += parent.frame().y;
+ parent = parent.parent;
}
- localPoint = this.convertFromCanvas(point);
- return this.dragging = {
- object: this,
- offsetX: localPoint.x,
- offsetY: localPoint.y
+ return {
+ x: x,
+ y: y
};
};
- CropBox.prototype.onDragMove = function(e) {
- var localPoint, parentPoint, point, _ref, _ref1;
- point = e.canvasPoint;
- if (((_ref = this.dragging) != null ? _ref.object : void 0) === this) {
- localPoint = this.convertFromCanvas(point);
- this.moveTo({
- x: localPoint.x - this.dragging.offsetX,
- y: localPoint.y - this.dragging.offsetY
- });
- this.updateCropFrameFromFrame();
- return this.markDirty();
- } else if ((_ref1 = this.dragging) != null ? _ref1.resizeDirection : void 0) {
- parentPoint = this.parent.convertFromCanvas(point);
- switch (this.dragging.resizeDirection) {
- case 'tl':
- point = this.constrainPointInParent(parentPoint);
- this.w = this.w + (this.x - point.x);
- this.h = this.h + (this.y - point.y);
- this.x = point.x;
- this.y = point.y;
- break;
- case 'tm':
- point = this.constrainPointInParent(parentPoint);
- this.w = this.w;
- this.h = this.h + (this.y - point.y);
- this.x = this.x;
- this.y = point.y;
- break;
- case 'tr':
- point = this.constrainPointInParent(parentPoint);
- this.w = point.x - this.x;
- this.h = this.h + (this.y - point.y);
- this.x = this.x;
- this.y = point.y;
- break;
- case 'ml':
- point = this.constrainPointInParent(parentPoint);
- this.w = this.w + (this.x - point.x);
- this.h = this.h;
- this.x = point.x;
- this.y = this.y;
- break;
- case 'mr':
- point = this.constrainPointInParent(parentPoint);
- this.w = point.x - this.x;
- this.h = this.h;
- this.x = this.x;
- this.y = this.y;
- break;
- case 'bl':
- point = this.constrainPointInParent(parentPoint);
- this.w = this.w + (this.x - point.x);
- this.h = point.y - this.y;
- this.x = point.x;
- this.y = this.y;
- break;
- case 'bm':
- point = this.constrainPointInParent(parentPoint);
- this.w = this.w;
- this.h = point.y - this.y;
- this.x = this.x;
- this.y = this.y;
- break;
- case 'br':
- point = this.constrainPointInParent(parentPoint);
- this.w = point.x - this.x;
- this.h = point.y - this.y;
- this.x = this.x;
- this.y = this.y;
- }
- this.updateCropFrameFromFrame();
- return this.markDirty();
+ Drawable.prototype.convertFromCanvas = function(point) {
+ var parent, x, y;
+ parent = this;
+ x = point.x;
+ y = point.y;
+ while (parent) {
+ x -= parent.frame().x;
+ y -= parent.frame().y;
+ parent = parent.parent;
+ }
+ return {
+ x: x,
+ y: y
+ };
+ };
+
+ Drawable.prototype.positionContext = function(ctx, fn) {
+ var pos;
+ if (this.parent) {
+ pos = this.convertToCanvas(this.parent.bounds());
+ ctx.translate(pos.x, pos.y);
}
+ return fn.call(this, ctx);
};
- CropBox.prototype.onDragEnd = function(e) {
- var frame, point;
- point = e.canvasPoint;
+ Drawable.prototype.containsCanvasPoint = function(point) {
+ var localPoint;
+ localPoint = this.convertFromCanvas(point);
+ return this.containsPoint(localPoint);
+ };
+
+ Drawable.prototype.containsPoint = function(point) {
+ var frame, _ref, _ref1;
frame = this.frame();
- this.x = frame.x;
- this.y = frame.y;
- this.w = frame.w;
- this.h = frame.h;
- return this.trigger('change', this.cropFrame());
+ return (0 <= (_ref = point.x) && _ref <= frame.w) && (0 <= (_ref1 = point.y) && _ref1 <= frame.h);
};
- CropBox.prototype.onClick = function(e) {};
+ Drawable.prototype.addChild = function(child) {
+ child.parent = this;
+ this.children.push(child);
+ return this.markDirty();
+ };
- CropBox.prototype.moveTo = function(point) {
- var pos, x, y;
- pos = this.convertToParent(point);
- x = Math.max(0, pos.x);
- y = Math.max(0, pos.y);
- x = Math.min(this.parent.bounds().w - this.w, x);
- y = Math.min(this.parent.bounds().h - this.h, y);
- this.x = x;
- return this.y = y;
+ Drawable.prototype.removeChild = function(child) {
+ var i;
+ i = this.children.indexOf(child);
+ if (i >= 0) {
+ child.parent = null;
+ this.children.splice(i, 1);
+ return this.markDirty();
+ }
};
- CropBox.prototype.setLooseTheAnts = function() {
- var animationFn;
- animationFn = (function(_this) {
- return function() {
- if (_this.marchingAnts) {
- _this.dashOffset += 0.15;
- _this.markDirty();
- }
- return window.requestAnimationFrame(animationFn);
- };
- })(this);
- return window.requestAnimationFrame(animationFn);
+ Drawable.prototype.renderChildren = function(ctx) {
+ var child, _i, _len, _ref, _results;
+ _ref = this.children;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ child = _ref[_i];
+ if (child.enabled) {
+ _results.push(child.render(ctx));
+ } else {
+ _results.push(void 0);
+ }
+ }
+ return _results;
};
- CropBox.prototype.drawScreen = function(ctx) {
+ Drawable.prototype.clear = function(ctx) {
var frame;
frame = this.frame();
- frame.x = Math.round(frame.x);
- frame.y = Math.round(frame.y);
- frame.w = Math.round(frame.w);
- frame.h = Math.round(frame.h);
- this.topScreen.set({
- parent: this.parent,
- x: 0,
- y: 0,
- w: this.parent.w,
- h: frame.y
- });
- this.bottomScreen.set({
- parent: this.parent,
- x: 0,
- y: frame.y + frame.h,
- w: this.parent.w,
- h: this.parent.h - (frame.y + frame.h)
- });
- this.leftScreen.set({
- parent: this.parent,
- x: 0,
- y: frame.y,
- w: frame.x,
- h: frame.h
- });
- this.rightScreen.set({
- parent: this.parent,
- x: frame.x + frame.w,
- y: frame.y,
- w: this.parent.w - (frame.x + frame.w),
- h: frame.h
- });
- this.topScreen.render(ctx);
- this.leftScreen.render(ctx);
- this.rightScreen.render(ctx);
- return this.bottomScreen.render(ctx);
+ if (this.parent) {
+ return positionContext(ctx, (function(_this) {
+ return function(ctx) {
+ return ctx.clearRect(frame.x, frame.y, frame.w, frame.h);
+ };
+ })(this));
+ } else {
+ return ctx.clearRect(frame.x, frame.y, frame.w, frame.h);
+ }
};
- CropBox.prototype.drawHandles = function(ctx) {
- var direction, frame, handle, newRect, _ref, _results;
- frame = this.frame();
- frame.x = Math.round(frame.x);
- frame.y = Math.round(frame.y);
- frame.w = Math.round(frame.w);
- frame.h = Math.round(frame.h);
- newRect = (function(_this) {
- return function(x, y) {
- return new drawing.Rectangle({
- parent: _this,
- x: x - (_this.handleSize / 2) - 0.5,
- y: y - (_this.handleSize / 2) - 0.5,
- w: _this.handleSize,
- h: _this.handleSize,
- lineWidth: 1,
- strokeStyle: 'rgba(192, 192, 192, 1)',
- fillStyle: 'rgba(64, 64, 64, 1)'
- });
+ Drawable.prototype.render = function(ctx) {
+ ctx.save();
+ this.draw(ctx);
+ ctx.restore();
+ this.renderChildren(ctx);
+ return this.dirty = false;
+ };
+
+ Drawable.prototype.draw = function(ctx) {};
+
+ return Drawable;
+
+ })(Events);
+
+ drawing.Drawable = Drawable;
+
+ PaddedContainer = (function(_super) {
+ __extends(PaddedContainer, _super);
+
+ function PaddedContainer(options) {
+ if (options == null) {
+ options = {};
+ }
+ PaddedContainer.__super__.constructor.call(this, options);
+ this.padding = options.padding || 10;
+ this.fillParent = options.fillParent || true;
+ }
+
+ PaddedContainer.prototype.frame = function() {
+ var parentFrame;
+ if (this.fillParent) {
+ parentFrame = this.parent.frame();
+ return {
+ x: this.padding,
+ y: this.padding,
+ w: parentFrame.w - 2 * this.padding,
+ h: parentFrame.h - 2 * this.padding
+ };
+ } else {
+ return {
+ x: this.x + this.padding,
+ y: this.y + this.padding,
+ w: this.w - 2 * this.padding,
+ h: this.h - 2 * this.padding
};
- })(this);
- this.handles["tl"] = newRect(0, 0);
- this.handles["tm"] = newRect(frame.w / 2, 0);
- this.handles["tr"] = newRect(frame.w, 0);
- this.handles["ml"] = newRect(0, frame.h / 2);
- this.handles["mr"] = newRect(frame.w, frame.h / 2);
- this.handles["bl"] = newRect(0, frame.h);
- this.handles["bm"] = newRect(frame.w / 2, frame.h);
- this.handles["br"] = newRect(frame.w, frame.h);
- _ref = this.handles;
- _results = [];
- for (direction in _ref) {
- handle = _ref[direction];
- _results.push(handle.render(ctx));
}
- return _results;
};
- CropBox.prototype.drawCropLines = function(ctx) {
- var frame, lineDash, opacity;
- frame = this.frame();
- frame.x = Math.round(frame.x);
- frame.y = Math.round(frame.y);
- frame.w = Math.round(frame.w);
- frame.h = Math.round(frame.h);
- opacity = "0.5";
- lineDash = 4;
- ctx.save();
- this.positionContext(ctx, (function(_this) {
+ PaddedContainer.prototype.bounds = function() {
+ var parentFrame;
+ if (this.fillParent) {
+ parentFrame = this.parent.frame();
+ return {
+ x: 0,
+ y: 0,
+ w: parentFrame.w - 2 * this.padding,
+ h: parentFrame.h - 2 * this.padding
+ };
+ } else {
+ return {
+ x: 0,
+ y: 0,
+ w: this.w - 2 * this.padding,
+ h: this.h - 2 * this.padding
+ };
+ }
+ };
+
+ return PaddedContainer;
+
+ })(Drawable);
+
+ drawing.PaddedContainer = PaddedContainer;
+
+ Rectangle = (function(_super) {
+ __extends(Rectangle, _super);
+
+ function Rectangle(options) {
+ Rectangle.__super__.constructor.call(this, options);
+ this.fillStyle = options.fillStyle || 'rgba(0, 0, 0, 0)';
+ this.strokeStyle = options.strokeStyle;
+ this.lineWidth = options.lineWidth;
+ }
+
+ Rectangle.prototype.draw = function(ctx) {
+ return this.positionContext(ctx, (function(_this) {
return function(ctx) {
- var x, y, _i, _j, _len, _len1, _ref, _ref1, _results;
- ctx.lineDashOffset = _this.dashOffset;
- ctx.beginPath();
- ctx.strokeStyle = "rgba(255,255,255," + (1 || opacity) + ")";
- ctx.rect(0.5, 0.5, frame.w, frame.h);
- ctx.closePath();
- ctx.stroke();
+ if (_this.fillStyle) {
+ ctx.fillStyle = _this.fillStyle;
+ }
+ if (_this.strokeStyle) {
+ ctx.strokeStyle = _this.strokeStyle;
+ }
+ if (_this.lineWidth) {
+ ctx.lineWidth = _this.lineWidth;
+ }
ctx.beginPath();
- ctx.strokeStyle = "rgba(0,0,0," + (1 || opacity) + ")";
- ctx.setLineDash([lineDash]);
- ctx.rect(0.5, 0.5, frame.w, frame.h);
+ ctx.rect(0, 0, _this.w, _this.h);
ctx.closePath();
- ctx.stroke();
- ctx.lineDashOffset = 0;
- _ref = [frame.w / 3 + 0.5, (frame.w / 3) * 2 + 0.5];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- x = _ref[_i];
- ctx.beginPath();
- ctx.moveTo(x, 0);
- ctx.strokeStyle = "rgba(255,255,255," + opacity + ")";
- ctx.setLineDash([]);
- ctx.lineTo(x, frame.h);
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(x, 0);
- ctx.strokeStyle = "rgba(0,0,0," + opacity + ")";
- ctx.setLineDash([lineDash]);
- ctx.lineTo(x, frame.h);
- ctx.stroke();
+ if (_this.fillStyle) {
+ ctx.fill();
}
- _ref1 = [frame.h / 3 + 0.5, (frame.h / 3) * 2 + 0.5];
- _results = [];
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- y = _ref1[_j];
- ctx.beginPath();
- ctx.moveTo(0, y);
- ctx.strokeStyle = "rgba(255,255,255," + opacity + ")";
- ctx.setLineDash([]);
- ctx.lineTo(frame.w, y);
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(0, y);
- ctx.strokeStyle = "rgba(0,0,0," + opacity + ")";
- ctx.setLineDash([lineDash]);
- ctx.lineTo(frame.w, y);
- _results.push(ctx.stroke());
+ if (_this.lineWidth && _this.strokeStyle) {
+ return ctx.stroke();
}
- return _results;
};
})(this));
- return ctx.restore();
};
- CropBox.prototype.draw = function(ctx) {
- this.drawScreen(ctx);
- this.drawCropLines(ctx);
- return this.drawHandles(ctx);
- };
+ return Rectangle;
- return CropBox;
+ })(Drawable);
- })(drawing.Drawable);
+ drawing.Rectangle = Rectangle;
- __exports__["default"] = CropBox;
+ __exports__["default"] = drawing;
});define("funderscore",
["exports"],
function(__exports__) {
@@ -600,606 +636,584 @@ define("crop-box",
}
__exports__["default"] = _;
- });define("drawing",
- ["funderscore","events","exports"],
- function(__dependency1__, __dependency2__, __exports__) {
+ });define("events",
+ ["funderscore","exports"],
+ function(__dependency1__, __exports__) {
"use strict";
var _ = __dependency1__["default"];
- var Events = __dependency2__["default"];
- var CanvasImage, Drawable, PaddedContainer, Rectangle, drawing,
- __hasProp = {}.hasOwnProperty,
- __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
- __slice = [].slice;
-
- drawing = {};
+ var Event, Events;
- Drawable = (function(_super) {
- __extends(Drawable, _super);
+ Events = (function() {
+ function Events() {}
- function Drawable(options) {
- this.options = options;
- this.x = options.x;
- this.y = options.y;
- this.w = options.w;
- this.h = options.h;
- this.dirty = true;
- this.scale = options.scale;
- this.parent = options.parent;
- this.canvas = options.canvas;
- this.children = options.children || [];
- this.dragable = options.dragable || false;
- this.enabled = options.enabled !== void 0 ? !!options.enabled : true;
- }
+ Events.prototype.on = function(event, callback, context) {
+ var _base;
+ this.events || (this.events = {});
+ (_base = this.events)[event] || (_base[event] = []);
+ if (_.isFunction(callback)) {
+ return this.events[event].push([callback, context]);
+ }
+ };
- Drawable.prototype.set = function(options) {
- var key, value, _results;
+ Events.prototype.trigger = function(event) {
+ var callback, callbackStruct, callbacks, context, tail, _i, _len, _results;
+ tail = Array.prototype.slice.call(arguments, 1);
+ callbacks = this.events && this.events[event] ? this.events[event] : [];
_results = [];
- for (key in options) {
- if (!__hasProp.call(options, key)) continue;
- value = options[key];
- _results.push(this[key] = value);
+ for (_i = 0, _len = callbacks.length; _i < _len; _i++) {
+ callbackStruct = callbacks[_i];
+ callback = callbackStruct[0];
+ context = callbackStruct[1] || this;
+ _results.push(callback.apply(context, tail));
}
return _results;
};
- Drawable.prototype.enable = function(enabled) {
- var previous;
- previous = this.enabled;
- this.enabled = !!enabled;
- this.markDirty();
- if (previous !== this.enabled) {
- if (this.enabled) {
- return this.trigger('enabled', this);
- } else {
- return this.trigger('disabled', this);
- }
- }
- };
+ return Events;
- Drawable.prototype.markDirty = function() {
- this.dirty = true;
- if (this.parent) {
- return this.parent.markDirty();
- }
- };
+ })();
- Drawable.prototype.bubble = function() {
- var args, event, eventName, parent, _results;
- eventName = arguments[0], event = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
- event.currentTarget = this;
- this.trigger.apply(this, arguments);
- parent = this.parent;
- _results = [];
- while (parent) {
- event = _.clone(event);
- event.currentTarget = parent;
- parent.trigger.apply(parent, [eventName, event].concat(args));
- _results.push(parent = parent.parent);
+ Event = (function() {
+ function Event(options) {
+ var k, v;
+ for (k in options) {
+ v = options[k];
+ this[k] = v;
}
- return _results;
- };
+ }
- Drawable.prototype.findChildAtPoint = function(point) {
- var child, grandChild, i;
- i = this.children.length - 1;
- while (i >= 0) {
- child = this.children[i];
- grandChild = child.findChildAtPoint(point);
- if (grandChild) {
- return grandChild;
- } else {
- if (child.containsCanvasPoint(point)) {
- return child;
- }
- }
- i--;
- }
- };
+ return Event;
- Drawable.prototype.bounds = function() {
- return {
- x: 0,
- y: 0,
- w: this.w,
- h: this.h
- };
- };
+ })();
- Drawable.prototype.frame = function() {
- return {
- x: this.x,
- y: this.y,
- w: this.w,
- h: this.h
- };
- };
+ __exports__["default"] = Events;
- Drawable.prototype.convertToParent = function(point) {
- var frame;
- frame = this.frame();
- return {
- x: point.x + frame.x,
- y: point.y + frame.y
- };
- };
+ __exports__.Event = Event;
+ });define("crop-box",
+ ["funderscore","drawing","exports"],
+ function(__dependency1__, __dependency2__, __exports__) {
+ "use strict";
+ var _ = __dependency1__["default"];
+ var drawing = __dependency2__["default"];
+ var CropBox,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
- Drawable.prototype.convertFromParent = function(point) {
- var frame;
- frame = this.frame();
- return {
- x: point.x - frame.x,
- y: point.y - frame.y
- };
- };
+ CropBox = (function(_super) {
+ __extends(CropBox, _super);
+
+ function CropBox(options) {
+ CropBox.__super__.constructor.call(this, _.extend({
+ dragable: true
+ }, options));
+ this.image = options.image;
+ this.handleSize = options.handleSize || 10;
+ this.screenStyle = options.screenStyle || 'rgba(0, 0, 0, .75)';
+ this.topScreen = new drawing.Rectangle({
+ fillStyle: this.screenStyle
+ });
+ this.leftScreen = new drawing.Rectangle({
+ fillStyle: this.screenStyle
+ });
+ this.rightScreen = new drawing.Rectangle({
+ fillStyle: this.screenStyle
+ });
+ this.bottomScreen = new drawing.Rectangle({
+ fillStyle: this.screenStyle
+ });
+ this.cropX = options.cropX || 0;
+ this.cropY = options.cropY || 0;
+ this.cropWidth = options.cropWidth || this.handleSize * 4;
+ this.cropHeight = options.cropHeight || this.handleSize * 4;
+ this.marchingAnts = options.marchingAnts || true;
+ this.dashOffset = 0;
+ this.dragging = null;
+ this.mouseDown = false;
+ this.handles = {};
+ this.image.on('load', (function(_this) {
+ return function() {
+ return _this.setCropFrameAndUpdateFrame(_this.cropFrame());
+ };
+ })(this));
+ this.image.on('crop', (function(_this) {
+ return function(image, previousCrop, crop) {
+ _this.cropX = previousCrop.w >= crop.w ? 0 : previousCrop.x - crop.x;
+ _this.cropY = previousCrop.h >= crop.h ? 0 : previousCrop.y - crop.y;
+ _this.cropWidth = previousCrop.w >= crop.w ? crop.w : previousCrop.w;
+ _this.cropHeight = previousCrop.h >= crop.h ? crop.h : previousCrop.h;
+ return _this.setCropFrameAndUpdateFrame(_this.cropFrame());
+ };
+ })(this));
+ this.on('mouseout', this.onMouseOut);
+ this.on('mousemove', this.onMouseMove);
+ this.on('mousedown', this.onMouseDown);
+ this.on('mouseup', this.onMouseUp);
+ this.on('dragstart', this.onDragStart);
+ this.on('dragend', this.onDragEnd);
+ this.on('dragmove', this.onDragMove);
+ this.setLooseTheAnts();
+ }
- Drawable.prototype.convertToCanvas = function(point) {
- var parent, x, y;
- parent = this;
- x = point.x;
- y = point.y;
- while (parent) {
- x += parent.frame().x;
- y += parent.frame().y;
- parent = parent.parent;
- }
+ CropBox.prototype.frame = function() {
return {
- x: x,
- y: y
+ x: this.w < 0 ? this.x + this.w : this.x,
+ y: this.h < 0 ? this.y + this.h : this.y,
+ w: Math.abs(this.w),
+ h: Math.abs(this.h)
};
};
- Drawable.prototype.convertFromCanvas = function(point) {
- var parent, x, y;
- parent = this;
- x = point.x;
- y = point.y;
- while (parent) {
- x -= parent.frame().x;
- y -= parent.frame().y;
- parent = parent.parent;
- }
+ CropBox.prototype.cropFrame = function() {
return {
- x: x,
- y: y
+ x: this.cropX,
+ y: this.cropY,
+ width: this.cropWidth,
+ height: this.cropHeight
};
};
- Drawable.prototype.positionContext = function(ctx, fn) {
- var pos;
- if (this.parent) {
- pos = this.convertToCanvas(this.parent.bounds());
- ctx.translate(pos.x, pos.y);
- }
- return fn.call(this, ctx);
- };
-
- Drawable.prototype.containsCanvasPoint = function(point) {
- var localPoint;
- localPoint = this.convertFromCanvas(point);
- return this.containsPoint(localPoint);
- };
-
- Drawable.prototype.containsPoint = function(point) {
- var frame, _ref, _ref1;
+ CropBox.prototype.updateCropFrameFromFrame = function() {
+ var frame, imageBounds, naturalBounds;
frame = this.frame();
- return (0 <= (_ref = point.x) && _ref <= frame.w) && (0 <= (_ref1 = point.y) && _ref1 <= frame.h);
+ naturalBounds = this.image.naturalBounds();
+ imageBounds = this.image.bounds();
+ if (this.image.loaded) {
+ this.cropX = naturalBounds.w * (frame.x / imageBounds.w);
+ this.cropY = naturalBounds.h * (frame.y / imageBounds.h);
+ this.cropWidth = naturalBounds.w * (frame.w / imageBounds.w);
+ this.cropHeight = naturalBounds.h * (frame.h / imageBounds.h);
+ }
+ return this.trigger('change:cropFrame', this.cropFrame());
};
- Drawable.prototype.addChild = function(child) {
- child.parent = this;
- this.children.push(child);
+ CropBox.prototype.setFrameAndUpdateCropArea = function(frame) {
+ this.x = frame.x;
+ this.y = frame.y;
+ this.w = frame.w;
+ this.h = frame.h;
+ this.updateCropFrameFromFrame();
return this.markDirty();
};
- Drawable.prototype.removeChild = function(child) {
- var i;
- i = this.children.indexOf(child);
- if (i >= 0) {
- child.parent = null;
- this.children.splice(i, 1);
+ CropBox.prototype.updateFrameFromCropFrame = function() {
+ var imageBounds, naturalBounds;
+ if (this.image.loaded) {
+ naturalBounds = this.image.naturalBounds();
+ imageBounds = this.image.bounds();
+ this.x = imageBounds.w * (this.cropX / naturalBounds.w);
+ this.y = imageBounds.h * (this.cropY / naturalBounds.h);
+ this.w = imageBounds.w * (this.cropWidth / naturalBounds.w);
+ this.h = imageBounds.h * (this.cropHeight / naturalBounds.h);
return this.markDirty();
}
};
- Drawable.prototype.renderChildren = function(ctx) {
- var child, _i, _len, _ref, _results;
- _ref = this.children;
- _results = [];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- child = _ref[_i];
- if (child.enabled) {
- _results.push(child.render(ctx));
- } else {
- _results.push(void 0);
- }
- }
- return _results;
- };
-
- Drawable.prototype.clear = function(ctx) {
- var frame;
- frame = this.frame();
- if (this.parent) {
- return positionContext(ctx, (function(_this) {
- return function(ctx) {
- return ctx.clearRect(frame.x, frame.y, frame.w, frame.h);
- };
- })(this));
- } else {
- return ctx.clearRect(frame.x, frame.y, frame.w, frame.h);
- }
- };
-
- Drawable.prototype.render = function(ctx) {
- ctx.save();
- this.draw(ctx);
- ctx.restore();
- this.renderChildren(ctx);
- return this.dirty = false;
- };
-
- Drawable.prototype.draw = function(ctx) {};
-
- return Drawable;
-
- })(Events);
-
- drawing.Drawable = Drawable;
-
- PaddedContainer = (function(_super) {
- __extends(PaddedContainer, _super);
-
- function PaddedContainer(options) {
- if (options == null) {
- options = {};
- }
- PaddedContainer.__super__.constructor.call(this, options);
- this.padding = options.padding || 10;
- this.fillParent = options.fillParent || true;
- }
-
- PaddedContainer.prototype.frame = function() {
- var parentFrame;
- if (this.fillParent) {
- parentFrame = this.parent.frame();
- return {
- x: this.padding,
- y: this.padding,
- w: parentFrame.w - 2 * this.padding,
- h: parentFrame.h - 2 * this.padding
- };
+ CropBox.prototype.setCropFrameAndUpdateFrame = function(cropArea) {
+ var naturalBounds, newCropHeight, newCropWidth, newCropX, newCropY;
+ if (this.image.loaded) {
+ naturalBounds = this.image.naturalBounds();
+ newCropX = (cropArea != null ? cropArea.x : void 0) || naturalBounds.w * .125;
+ newCropY = (cropArea != null ? cropArea.y : void 0) || naturalBounds.h * .125;
+ newCropWidth = (cropArea != null ? cropArea.width : void 0) || naturalBounds.w * .75;
+ newCropHeight = (cropArea != null ? cropArea.height : void 0) || naturalBounds.h * .75;
+ this.cropX = Math.min(Math.max(newCropX, 0), naturalBounds.w);
+ this.cropY = Math.min(Math.max(newCropY, 0), naturalBounds.h);
+ this.cropWidth = Math.min(Math.max(newCropWidth, 0), naturalBounds.w - this.cropX);
+ this.cropHeight = Math.min(Math.max(newCropHeight, 0), naturalBounds.h - this.cropY);
+ return this.updateFrameFromCropFrame();
} else {
- return {
- x: this.x + this.padding,
- y: this.y + this.padding,
- w: this.w - 2 * this.padding,
- h: this.h - 2 * this.padding
- };
+ this.cropX = cropArea != null ? cropArea.x : void 0;
+ this.cropY = cropArea != null ? cropArea.y : void 0;
+ this.cropWidth = cropArea != null ? cropArea.width : void 0;
+ return this.cropHeight = cropArea != null ? cropArea.height : void 0;
}
};
- PaddedContainer.prototype.bounds = function() {
- var parentFrame;
- if (this.fillParent) {
- parentFrame = this.parent.frame();
- return {
- x: 0,
- y: 0,
- w: parentFrame.w - 2 * this.padding,
- h: parentFrame.h - 2 * this.padding
- };
- } else {
- return {
- x: 0,
- y: 0,
- w: this.w - 2 * this.padding,
- h: this.h - 2 * this.padding
- };
- }
+ CropBox.prototype.bounds = function() {
+ return {
+ x: 0,
+ y: 0,
+ w: Math.abs(this.w),
+ h: Math.abs(this.h)
+ };
};
- return PaddedContainer;
-
- })(Drawable);
-
- drawing.PaddedContainer = PaddedContainer;
-
- CanvasImage = (function(_super) {
- __extends(CanvasImage, _super);
-
- function CanvasImage(options) {
- CanvasImage.__super__.constructor.call(this, options);
- this.source = options.source;
- this.naturalWidth = options.naturalWidth;
- this.naturalHeight = options.naturalHeight;
- this.originalNaturalBounds = this.naturalBounds();
- this.cropped = false;
- this.cropStack = [];
- this.loaded = false;
- this.cropX = 0;
- this.cropY = 0;
- this.cropWidth = this.naturalWidth;
- this.cropHeight = this.naturalHeight;
- this.loadImage();
- }
-
- CanvasImage.prototype.clearImage = function() {
- this.loaded = false;
- this.cropped = false;
- this.w = null;
- this.h = null;
- this.naturalWidth = null;
- this.naturalHeight = null;
- this.cropStack = [];
- this.originalNaturalBounds = this.naturalBounds();
- return this.markDirty();
+ CropBox.prototype.containsCanvasPoint = function(point) {
+ var containsPoint, direction, handle, local, _ref;
+ local = this.convertFromCanvas(point);
+ containsPoint = this.containsPoint(local);
+ if (containsPoint) {
+ return containsPoint;
+ }
+ _ref = this.handles;
+ for (direction in _ref) {
+ handle = _ref[direction];
+ if (handle.containsCanvasPoint(point)) {
+ return true;
+ }
+ }
+ return false;
};
- CanvasImage.prototype.setSource = function(source) {
- this.clearImage();
- this.source = source;
- return this.loadImage();
+ CropBox.prototype.onMouseOut = function(e) {
+ return this.canvas.style.cursor = 'default';
};
- CanvasImage.prototype.naturalBounds = function() {
- return {
- x: 0,
- y: 0,
- w: this.naturalWidth,
- h: this.naturalHeight
- };
+ CropBox.prototype.onMouseMove = function(e) {
+ var direction, handle, point, _ref;
+ if (!this.enabled) {
+ return;
+ }
+ point = e.canvasPoint;
+ _ref = this.handles;
+ for (direction in _ref) {
+ handle = _ref[direction];
+ if (handle.containsCanvasPoint(point)) {
+ switch (direction) {
+ case 'tl':
+ this.canvas.style.cursor = 'nw-resize';
+ break;
+ case 'tm':
+ this.canvas.style.cursor = 'n-resize';
+ break;
+ case 'tr':
+ this.canvas.style.cursor = 'ne-resize';
+ break;
+ case 'ml':
+ this.canvas.style.cursor = 'w-resize';
+ break;
+ case 'mr':
+ this.canvas.style.cursor = 'e-resize';
+ break;
+ case 'bl':
+ this.canvas.style.cursor = 'sw-resize';
+ break;
+ case 'bm':
+ this.canvas.style.cursor = 's-resize';
+ break;
+ case 'br':
+ this.canvas.style.cursor = 'se-resize';
+ }
+ return;
+ }
+ }
+ return this.canvas.style.cursor = 'move';
};
- CanvasImage.prototype.cropFrame = function() {
+ CropBox.prototype.constrainPointInParent = function(point) {
return {
- x: this.cropX,
- y: this.cropY,
- w: this.cropWidth,
- h: this.cropHeight
+ x: Math.min(Math.max(point.x, 0), this.parent.frame().w),
+ y: Math.min(Math.max(point.y, 0), this.parent.frame().h)
};
};
- CanvasImage.prototype.crop = function(frame) {
- if (!this.cropped) {
- this.cropped = true;
- this.cropX = this.cropY = 0;
- }
- this.cropX = frame.x + this.cropX;
- this.cropY = frame.y + this.cropY;
- this.cropWidth = frame.width;
- this.cropHeight = frame.height;
- this.naturalWidth = this.cropWidth;
- this.naturalHeight = this.cropHeight;
- this.resizeToParent();
- this.centerOnParent();
- this.cropStack.push(this.cropFrame());
- this.trigger('crop', this, this.cropStack[this.cropStack.length - 2], this.cropFrame());
- return this.markDirty();
+ CropBox.prototype.onMouseUp = function(point) {
+ return this.dragging = this.mouseDown = null;
};
- CanvasImage.prototype.undoCrop = function() {
- var newCropFrame, previousCropFrame;
- if (this.cropStack.length > 1) {
- previousCropFrame = this.cropStack.pop();
- newCropFrame = this.cropStack[this.cropStack.length - 1];
- this.cropX = newCropFrame.x;
- this.cropY = newCropFrame.y;
- this.cropWidth = newCropFrame.w;
- this.cropHeight = newCropFrame.h;
- this.naturalWidth = newCropFrame.w;
- this.naturalHeight = newCropFrame.h;
- this.resizeToParent();
- this.centerOnParent();
- if (this.cropStack.length === 1) {
- this.cropped = false;
+ CropBox.prototype.onDragStart = function(e) {
+ var direction, handle, localPoint, point, _ref;
+ point = e.canvasPoint;
+ _ref = this.handles;
+ for (direction in _ref) {
+ handle = _ref[direction];
+ if (handle.containsCanvasPoint(point)) {
+ localPoint = handle.convertFromCanvas(point);
+ this.dragging = {
+ resizeDirection: direction,
+ object: handle,
+ offsetX: localPoint.x,
+ offsetY: localPoint.y
+ };
+ return;
}
- this.trigger('crop', this, previousCropFrame, this.cropFrame());
- return this.markDirty();
}
+ localPoint = this.convertFromCanvas(point);
+ return this.dragging = {
+ object: this,
+ offsetX: localPoint.x,
+ offsetY: localPoint.y
+ };
};
- CanvasImage.prototype.revertImage = function() {
- var newCropFrame, originalCropFrame;
- this.cropped = false;
- if (this.cropStack.length > 1) {
- originalCropFrame = this.cropStack[this.cropStack.length - 1];
- newCropFrame = this.cropStack[0];
- this.cropX = newCropFrame.x;
- this.cropY = newCropFrame.y;
- this.cropWidth = newCropFrame.w;
- this.cropHeight = newCropFrame.h;
- this.naturalWidth = newCropFrame.w;
- this.naturalHeight = newCropFrame.h;
- this.resizeToParent();
- this.centerOnParent();
- this.cropStack = [newCropFrame];
- this.trigger('crop', this, originalCropFrame, newCropFrame);
+ CropBox.prototype.onDragMove = function(e) {
+ var localPoint, parentPoint, point, _ref, _ref1;
+ point = e.canvasPoint;
+ if (((_ref = this.dragging) != null ? _ref.object : void 0) === this) {
+ localPoint = this.convertFromCanvas(point);
+ this.moveTo({
+ x: localPoint.x - this.dragging.offsetX,
+ y: localPoint.y - this.dragging.offsetY
+ });
+ this.updateCropFrameFromFrame();
+ return this.markDirty();
+ } else if ((_ref1 = this.dragging) != null ? _ref1.resizeDirection : void 0) {
+ parentPoint = this.parent.convertFromCanvas(point);
+ switch (this.dragging.resizeDirection) {
+ case 'tl':
+ point = this.constrainPointInParent(parentPoint);
+ this.w = this.w + (this.x - point.x);
+ this.h = this.h + (this.y - point.y);
+ this.x = point.x;
+ this.y = point.y;
+ break;
+ case 'tm':
+ point = this.constrainPointInParent(parentPoint);
+ this.w = this.w;
+ this.h = this.h + (this.y - point.y);
+ this.x = this.x;
+ this.y = point.y;
+ break;
+ case 'tr':
+ point = this.constrainPointInParent(parentPoint);
+ this.w = point.x - this.x;
+ this.h = this.h + (this.y - point.y);
+ this.x = this.x;
+ this.y = point.y;
+ break;
+ case 'ml':
+ point = this.constrainPointInParent(parentPoint);
+ this.w = this.w + (this.x - point.x);
+ this.h = this.h;
+ this.x = point.x;
+ this.y = this.y;
+ break;
+ case 'mr':
+ point = this.constrainPointInParent(parentPoint);
+ this.w = point.x - this.x;
+ this.h = this.h;
+ this.x = this.x;
+ this.y = this.y;
+ break;
+ case 'bl':
+ point = this.constrainPointInParent(parentPoint);
+ this.w = this.w + (this.x - point.x);
+ this.h = point.y - this.y;
+ this.x = point.x;
+ this.y = this.y;
+ break;
+ case 'bm':
+ point = this.constrainPointInParent(parentPoint);
+ this.w = this.w;
+ this.h = point.y - this.y;
+ this.x = this.x;
+ this.y = this.y;
+ break;
+ case 'br':
+ point = this.constrainPointInParent(parentPoint);
+ this.w = point.x - this.x;
+ this.h = point.y - this.y;
+ this.x = this.x;
+ this.y = this.y;
+ }
+ this.updateCropFrameFromFrame();
return this.markDirty();
}
};
- CanvasImage.prototype.resizeToParent = function() {
- var ch, cw, scaleX, scaleY;
- cw = this.parent.frame().w;
- ch = this.parent.frame().h;
- scaleX = 1;
- scaleY = 1;
- if (this.naturalWidth > cw) {
- scaleX = cw / this.naturalWidth;
- }
- if (this.naturalHeight > ch) {
- scaleY = ch / this.naturalHeight;
- }
- this.scale = Math.min(scaleX, scaleY);
- this.w = (this.naturalWidth * this.scale) | 0;
- this.h = (this.naturalHeight * this.scale) | 0;
- return this.trigger('resize', this.frame());
- };
-
- CanvasImage.prototype.centerOnParent = function() {
- this.x = ((this.parent.frame().w / 2) - (this.w / 2)) | 0;
- this.y = ((this.parent.frame().h / 2) - (this.h / 2)) | 0;
- return this.trigger('reposition', this.frame());
+ CropBox.prototype.onDragEnd = function(e) {
+ var frame, point;
+ point = e.canvasPoint;
+ frame = this.frame();
+ this.x = frame.x;
+ this.y = frame.y;
+ this.w = frame.w;
+ this.h = frame.h;
+ return this.trigger('change', this.cropFrame());
};
- CanvasImage.prototype.toDataURL = function(format) {
- var canvas, ctx;
- if (format == null) {
- format = 'image/png';
- }
- canvas = document.createElement('canvas');
- canvas.width = this.cropWidth;
- canvas.height = this.cropHeight;
- ctx = canvas.getContext('2d');
- if (this.cropped) {
- ctx.drawImage(this.img, this.cropX, this.cropY, this.cropWidth, this.cropHeight, 0, 0, this.cropWidth, this.cropHeight);
- } else {
- ctx.drawImage(this.img, 0, 0, this.cropWidth, this.cropHeight);
- }
- return canvas.toDataURL(format);
- };
+ CropBox.prototype.onClick = function(e) {};
- CanvasImage.prototype.draw = function(ctx) {
- return this.positionContext(ctx, function(ctx) {
- if (this.cropped) {
- return ctx.drawImage(this.img, this.cropX, this.cropY, this.cropWidth, this.cropHeight, 0, 0, this.w, this.h);
- } else {
- return ctx.drawImage(this.img, 0, 0, this.w, this.h);
- }
- });
+ CropBox.prototype.moveTo = function(point) {
+ var pos, x, y;
+ pos = this.convertToParent(point);
+ x = Math.max(0, pos.x);
+ y = Math.max(0, pos.y);
+ x = Math.min(this.parent.bounds().w - this.w, x);
+ y = Math.min(this.parent.bounds().h - this.h, y);
+ this.x = x;
+ return this.y = y;
};
- CanvasImage.prototype.loadImage = function() {
- this.img = document.createElement('img');
- this.img.onload = (function(_this) {
+ CropBox.prototype.setLooseTheAnts = function() {
+ var animationFn;
+ animationFn = (function(_this) {
return function() {
- _this.loaded = true;
- _this.naturalWidth = _this.img.naturalWidth;
- _this.naturalHeight = _this.img.naturalHeight;
- _this.cropped = false;
- _this.cropStack = [];
- _this.cropX = 0;
- _this.cropY = 0;
- _this.cropWidth = _this.img.naturalWidth;
- _this.cropHeight = _this.img.naturalHeight;
- _this.cropStack.push(_this.cropFrame());
- _this.markDirty();
- return _this.trigger('load', _this);
+ if (_this.marchingAnts) {
+ _this.dashOffset += 0.15;
+ _this.markDirty();
+ }
+ return window.requestAnimationFrame(animationFn);
};
})(this);
- return this.img.src = this.source;
+ return window.requestAnimationFrame(animationFn);
};
- return CanvasImage;
-
- })(Drawable);
-
- drawing.CanvasImage = CanvasImage;
-
- Rectangle = (function(_super) {
- __extends(Rectangle, _super);
+ CropBox.prototype.drawScreen = function(ctx) {
+ var frame;
+ frame = this.frame();
+ frame.x = Math.round(frame.x);
+ frame.y = Math.round(frame.y);
+ frame.w = Math.round(frame.w);
+ frame.h = Math.round(frame.h);
+ this.topScreen.set({
+ parent: this.parent,
+ x: 0,
+ y: 0,
+ w: this.parent.w,
+ h: frame.y
+ });
+ this.bottomScreen.set({
+ parent: this.parent,
+ x: 0,
+ y: frame.y + frame.h,
+ w: this.parent.w,
+ h: this.parent.h - (frame.y + frame.h)
+ });
+ this.leftScreen.set({
+ parent: this.parent,
+ x: 0,
+ y: frame.y,
+ w: frame.x,
+ h: frame.h
+ });
+ this.rightScreen.set({
+ parent: this.parent,
+ x: frame.x + frame.w,
+ y: frame.y,
+ w: this.parent.w - (frame.x + frame.w),
+ h: frame.h
+ });
+ this.topScreen.render(ctx);
+ this.leftScreen.render(ctx);
+ this.rightScreen.render(ctx);
+ return this.bottomScreen.render(ctx);
+ };
- function Rectangle(options) {
- Rectangle.__super__.constructor.call(this, options);
- this.fillStyle