Browse files

Add basic crop history support (crop/uncrop)

  • Loading branch information...
1 parent 9eb65c9 commit b97189fb4266c71e0721db4804955773d887b3c6 @caleb committed May 30, 2014
Showing with 129 additions and 2 deletions.
  1. +8 −0 lib/crop-box.coffee
  2. +72 −2 lib/drawing.coffee
  3. +26 −0 lib/rodeo-crop.coffee
  4. +23 −0 public/index.html
View
8 lib/crop-box.coffee
@@ -29,6 +29,14 @@ class CropBox extends drawing.Drawable
# reposition the frame when the image is loaded
@setCropFrameAndUpdateFrame @cropFrame()
+ @image.on 'crop', (image, previousCrop, crop) =>
+ # reposition the frame when the image is loaded
+ @cropX = if previousCrop.w >= crop.w then 0 else previousCrop.x - crop.x
+ @cropY = if previousCrop.h >= crop.h then 0 else previousCrop.y - crop.y
+ @cropWidth = if previousCrop.w >= crop.w then crop.w else previousCrop.w
+ @cropHeight = if previousCrop.h >= crop.h then crop.h else previousCrop.h
+ @setCropFrameAndUpdateFrame @cropFrame()
+
frame: () ->
{
x: if @w < 0 then @x + @w else @x
View
74 lib/drawing.coffee
@@ -16,6 +16,7 @@ class Drawable extends Events
@canvas = options.canvas
@children = options.children || []
@dragable = options.dragable || false
+ @enabled = options.enabled || true
set: (options) ->
for own key, value of options
@@ -114,7 +115,7 @@ class Drawable extends Events
drawChildren: (ctx) ->
for child in @children
- child.draw ctx
+ child.draw ctx if child.enabled
draw: (ctx) ->
# noop
@@ -128,16 +129,27 @@ class CanvasImage extends Drawable
@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()
setSource: (source) ->
@clearImage()
@@ -152,6 +164,53 @@ class CanvasImage extends Drawable
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()
+
+ undoCrop: () ->
+ @cropped = true
+
+ 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()
+
+ @trigger 'crop', @, previousCropFrame, @cropFrame()
+
resizeToParent: () ->
cw = @parent.frame().w
ch = @parent.frame().h
@@ -176,7 +235,10 @@ class CanvasImage extends Drawable
draw: (ctx) ->
@isolateAndMoveToParent ctx, (ctx) ->
- ctx.drawImage @img, 0, 0, @w, @h
+ if @cropped
+ ctx.drawImage @img, @cropX, @cropY, @cropWidth, @cropHeight, 0, 0, @w, @h
+ else
+ ctx.drawImage @img, 0, 0, @w, @h
@drawChildren ctx
@@ -186,6 +248,14 @@ class CanvasImage extends Drawable
@loaded = true
@naturalWidth = @img.naturalWidth
@naturalHeight = @img.naturalHeight
+
+ @cropX = 0
+ @cropY = 0
+ @cropWidth = @img.naturalWidth
+ @cropHeight = @img.naturalHeight
+
+ @cropStack.push @cropFrame()
+
@trigger 'load', @
@img.src = @source
View
26 lib/rodeo-crop.coffee
@@ -9,6 +9,15 @@ class Stage extends drawing.Drawable
initialize: (options) ->
@canvas = options.canvas
+ windowToCanvas: (e) ->
+ rect = @canvas.getBoundingClientRect()
+ x = e.clientX - rect.left
+ y = e.clientY - rect.top
+
+ {
+ x: x
+ y: y
+ }
frame: ->
{
x: 0
@@ -88,6 +97,7 @@ class Cropper extends Events
createCropBox: () ->
@cropBox = new CropBox
+ enabled: @cropEnabled
canvas: @canvas
image: @image
cropX: @options.cropX
@@ -132,6 +142,8 @@ class Cropper extends Events
window.addEventListener 'mousedown', (e) =>
pos = globalToCanvas e
+ return unless @cropBox.enabled
+
if @cropBox.containsCanvasPoint pos
@mouseDown = @cropBox
@cropBox.onMouseDown pos
@@ -147,6 +159,8 @@ class Cropper extends Events
@dragging.onDragMove pos
@valid = false
else
+ return unless @cropBox.enabled
+
pos = globalToCanvas e
cropboxContainsPoint = @cropBox.containsCanvasPoint pos
@@ -170,6 +184,18 @@ class Cropper extends Events
@cropBox.cropFrame()
+ enableCrop: (enabled) ->
+ @cropBox.enabled = enabled
+ @valid = false
+
+ unCropImage: () ->
+ @image.undoCrop()
+ @valid = false
+
+ cropImage: () ->
+ @image.crop @cropBox.cropFrame()
+ @valid = false
+
updateCanvasSize: () ->
w = window.getComputedStyle(@canvas.parentNode).getPropertyValue 'width'
h = window.getComputedStyle(@canvas.parentNode).getPropertyValue 'height'
View
23 public/index.html
@@ -20,6 +20,11 @@
<button id="update-crop">update!</button>
<button id="change-image">change image</button>
+
+ <button id="do-crop">do crop</button>
+ <button id="reset">reset</button>
+
+ <input type="checkbox" checked> Enabled
</form>
<div id="container">
@@ -92,6 +97,19 @@
hbox.value = cropFrame.height;
})
+ cropbutton = document.querySelector('#do-crop')
+ cropbutton.addEventListener('click', function(e) {
+ e.preventDefault();
+ cropper.cropImage()
+ })
+
+
+ resetbutton = document.querySelector("#reset")
+ resetbutton.addEventListener('click', function(e) {
+ e.preventDefault();
+ cropper.unCropImage()
+ })
+
button = document.querySelector('#update-crop')
button.addEventListener('click', function(e) {
e.preventDefault();
@@ -108,6 +126,11 @@
wbox.value = cropFrame.width;
hbox.value = cropFrame.height;
});
+
+ checkbox = document.querySelector('[type=checkbox]')
+ checkbox.addEventListener('change', function(e) {
+ cropper.enableCrop(checkbox.checked);
+ });
</script>
</body>
</html>

0 comments on commit b97189f

Please sign in to comment.