|
$( function () |
|
{ |
|
|
|
// this should be handled different, but works for the demo |
|
var template = '<div class="image well clearfix">' + |
|
'<div class="crop-container col-xs-12 col-sm-6 pull-right">' + |
|
'<h3>Select Desired Orientation</h3>' + |
|
'<span class="crop btn btn-default" data-orientation="landscape" data-ratio="1.7778">Landscape</span>' + |
|
'<span class="crop btn btn-default" data-orientation="portrait" data-ratio="0.5625">Portrait</span>' + |
|
'<span class="crop btn btn-default" data-orientation="square" data-ratio="1.0000">Square</span>' + |
|
'<h3>Select Desired Crop</h3>' + |
|
'<img class="img-responsive" />' + |
|
'</div>' + |
|
'<div class="form-container col-xs-12 col-sm-6">' + |
|
'<h3>Image Details</h3>' + |
|
'' + |
|
'<div class="form-group col-xs-12">' + |
|
'<input class="form-control" type="text" name="name" placeholder="Name" required>' + |
|
'</div>' + |
|
'<div class="form-group col-xs-12">' + |
|
'<input class="form-control" type="text" name="credit" placeholder="Credit">' + |
|
'</div>' + |
|
'<div class="form-group col-xs-12">' + |
|
'<textarea class="form-control" name="caption" placeholder="Caption"></textarea>' + |
|
'</div>' + |
|
'<div class="form-group col-xs-6">' + |
|
'<input class="form-control" type="text" name="origWidth" placeholder="Original Width" readonly>' + |
|
'</div>' + |
|
'<div class="form-group col-xs-6">' + |
|
'<input class="form-control" type="text" name="origHeight" placeholder="Original Height" readonly>' + |
|
'</div>' + |
|
'<div class="form-group col-xs-6">' + |
|
'<input class="form-control" type="text" name="width" placeholder="Width" readonly>' + |
|
'</div>' + |
|
'<div class="form-group col-xs-6">' + |
|
'<input class="form-control" type="text" name="height" placeholder="Height" readonly>' + |
|
'</div>' + |
|
'<div class="form-group col-xs-3">' + |
|
'<input class="form-control" type="text" name="x1" placeholder="x1" readonly>' + |
|
'</div>' + |
|
'<div class="form-group col-xs-3">' + |
|
'<input class="form-control" type="text" name="y1" placeholder="y1" readonly>' + |
|
'</div>' + |
|
'<div class="form-group col-xs-3">' + |
|
'<input class="form-control" type="text" name="x2" placeholder="x2" readonly>' + |
|
'</div>' + |
|
'<div class="form-group col-xs-3">' + |
|
'<input class="form-control" type="text" name="y2" placeholder="y2" readonly>' + |
|
'</div>' + |
|
'<div class="form-group">' + |
|
'<div class="col-xs-12">' + |
|
'<button type="submit" class="btn btn-default">Save & Continue</button>' + |
|
'</div>' + |
|
'</div>' + |
|
'' + |
|
'</div>' + |
|
'</div>'; |
|
|
|
var fileInput = $( '#filesToUpload' ); |
|
var fileDisplayArea = $( '.img-wrapper' ); |
|
|
|
function initCrop( el ) |
|
{ |
|
|
|
var target = el.nextAll( 'img' ); |
|
var form = el.parents( '.crop-container' ).nextAll( '.form-container' ); |
|
var cropContainer = $( '.crop-container' ); |
|
|
|
var imageData = new Image(); |
|
imageData.src = target.attr( "src" ); |
|
|
|
target.Jcrop( |
|
{ |
|
onSelect: showCoords, |
|
bgColor: 'black', |
|
bgOpacity: .4, |
|
setSelect: [ 100, 100, 50, 50 ], |
|
trueSize: [ imageData.width, imageData.height ], |
|
aspectRatio: el.data( 'ratio' ), |
|
minSize: [ 320, 320 ], |
|
} ); |
|
|
|
function showCoords( c ) |
|
{ |
|
form.find( 'input[name="origWidth"]' ).val( imageData.width ); |
|
form.find( 'input[name="origHeight"]' ).val( imageData.height ); |
|
form.find( 'input[name="x1"]' ).val( c.x ); |
|
form.find( 'input[name="y1"]' ).val( c.y ); |
|
form.find( 'input[name="x2"]' ).val( c.x2 ); |
|
form.find( 'input[name="y2"]' ).val( c.y2 ); |
|
form.find( 'input[name="width"]' ).val( c.w ); |
|
form.find( 'input[name="height"]' ).val( c.h ); |
|
}; |
|
|
|
} |
|
|
|
function createImage( file ) |
|
{ |
|
var preview = $( template ), |
|
image = $( 'img', preview ); |
|
var form = image.parents( '.crop-container' ).nextAll( '.form-container' ); |
|
|
|
var reader = new FileReader(); |
|
|
|
|
|
// var imageData = new Image(); |
|
// imageData.src = image.attr( "src" ); |
|
// var imageType = /image.*/; |
|
// console.log( imageData, imageData.type, 'type' ); |
|
// if ( !imageData.type.match( imageType ) ) |
|
// { |
|
// alert( 'unsupported format supplied' ); |
|
// return; |
|
// } |
|
|
|
reader.onload = function ( e ) |
|
{ |
|
image.attr( 'src', e.target.result ); |
|
image.attr( 'id', 'crop-' + file.name ); |
|
form.attr( 'id', 'form-' + file.name ); |
|
}; |
|
|
|
reader.readAsDataURL( file ); |
|
|
|
preview.prependTo( fileDisplayArea ); |
|
|
|
} |
|
|
|
fileInput.on( 'change', function ( e ) |
|
{ |
|
var files = fileInput[ 0 ].files; |
|
|
|
for ( var i = 0; i < files.length; i++ ) |
|
{ |
|
var file = files[ i ]; |
|
createImage( file ); |
|
} |
|
} ); |
|
|
|
$( document ).on( 'click', 'span.crop', function () |
|
{ |
|
initCrop( $( this ) ) |
|
|
|
} ) |
|
|
|
$( document ).on( 'submit', '.image-form', function ( ev ) |
|
{ |
|
// Just for fun |
|
var values = {}; |
|
$.each( $( this ).serializeArray(), function ( i, field ) |
|
{ |
|
|
|
values[ field.name ] = field.value; |
|
|
|
} ); |
|
console.log( values ); |
|
|
|
ev.preventDefault(); |
|
} ); |
|
|
|
} ) |
|
|
|
/** |
|
* jquery.Jcrop.js v0.9.12 |
|
* jQuery Image Cropping Plugin - released under MIT License |
|
* Author: Kelly Hallman <khallman@gmail.com> |
|
* http://github.com/tapmodo/Jcrop |
|
* Copyright (c) 2008-2013 Tapmodo Interactive LLC {{{ |
|
* |
|
* Permission is hereby granted, free of charge, to any person |
|
* obtaining a copy of this software and associated documentation |
|
* files (the "Software"), to deal in the Software without |
|
* restriction, including without limitation the rights to use, |
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
* copies of the Software, and to permit persons to whom the |
|
* Software is furnished to do so, subject to the following |
|
* conditions: |
|
* |
|
* The above copyright notice and this permission notice shall be |
|
* included in all copies or substantial portions of the Software. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|
* OTHER DEALINGS IN THE SOFTWARE. |
|
* |
|
* }}} |
|
*/ |
|
|
|
; |
|
( function ( $ ) |
|
{ |
|
|
|
$.Jcrop = function ( obj, opt ) |
|
{ |
|
var options = $.extend( |
|
{}, $.Jcrop.defaults ), |
|
docOffset, |
|
_ua = navigator.userAgent.toLowerCase(), |
|
is_msie = /msie/.test( _ua ), |
|
ie6mode = /msie [1-6]\./.test( _ua ); |
|
|
|
// Internal Methods {{{ |
|
function px( n ) |
|
{ |
|
return Math.round( n ) + 'px'; |
|
} |
|
|
|
function cssClass( cl ) |
|
{ |
|
return options.baseClass + '-' + cl; |
|
} |
|
|
|
function supportsColorFade() |
|
{ |
|
return $.fx.step.hasOwnProperty( 'backgroundColor' ); |
|
} |
|
|
|
function getPos( obj ) //{{{ |
|
{ |
|
var pos = $( obj ).offset(); |
|
return [ pos.left, pos.top ]; |
|
} |
|
//}}} |
|
function mouseAbs( e ) //{{{ |
|
{ |
|
return [ ( e.pageX - docOffset[ 0 ] ), ( e.pageY - docOffset[ 1 ] ) ]; |
|
} |
|
//}}} |
|
function setOptions( opt ) //{{{ |
|
{ |
|
if ( typeof ( opt ) !== 'object' ) opt = {}; |
|
options = $.extend( options, opt ); |
|
|
|
$.each( [ 'onChange', 'onSelect', 'onRelease', 'onDblClick' ], function ( i, e ) |
|
{ |
|
if ( typeof ( options[ e ] ) !== 'function' ) options[ e ] = function () {}; |
|
} ); |
|
} |
|
//}}} |
|
function startDragMode( mode, pos, touch ) //{{{ |
|
{ |
|
docOffset = getPos( $img ); |
|
Tracker.setCursor( mode === 'move' ? mode : mode + '-resize' ); |
|
|
|
if ( mode === 'move' ) |
|
{ |
|
return Tracker.activateHandlers( createMover( pos ), doneSelect, touch ); |
|
} |
|
|
|
var fc = Coords.getFixed(); |
|
var opp = oppLockCorner( mode ); |
|
var opc = Coords.getCorner( oppLockCorner( opp ) ); |
|
|
|
Coords.setPressed( Coords.getCorner( opp ) ); |
|
Coords.setCurrent( opc ); |
|
|
|
Tracker.activateHandlers( dragmodeHandler( mode, fc ), doneSelect, touch ); |
|
} |
|
//}}} |
|
function dragmodeHandler( mode, f ) //{{{ |
|
{ |
|
return function ( pos ) |
|
{ |
|
if ( !options.aspectRatio ) |
|
{ |
|
switch ( mode ) |
|
{ |
|
case 'e': |
|
pos[ 1 ] = f.y2; |
|
break; |
|
case 'w': |
|
pos[ 1 ] = f.y2; |
|
break; |
|
case 'n': |
|
pos[ 0 ] = f.x2; |
|
break; |
|
case 's': |
|
pos[ 0 ] = f.x2; |
|
break; |
|
} |
|
} |
|
else |
|
{ |
|
switch ( mode ) |
|
{ |
|
case 'e': |
|
pos[ 1 ] = f.y + 1; |
|
break; |
|
case 'w': |
|
pos[ 1 ] = f.y + 1; |
|
break; |
|
case 'n': |
|
pos[ 0 ] = f.x + 1; |
|
break; |
|
case 's': |
|
pos[ 0 ] = f.x + 1; |
|
break; |
|
} |
|
} |
|
Coords.setCurrent( pos ); |
|
Selection.update(); |
|
}; |
|
} |
|
//}}} |
|
function createMover( pos ) //{{{ |
|
{ |
|
var lloc = pos; |
|
KeyManager.watchKeys(); |
|
|
|
return function ( pos ) |
|
{ |
|
Coords.moveOffset( [ pos[ 0 ] - lloc[ 0 ], pos[ 1 ] - lloc[ 1 ] ] ); |
|
lloc = pos; |
|
|
|
Selection.update(); |
|
}; |
|
} |
|
//}}} |
|
function oppLockCorner( ord ) //{{{ |
|
{ |
|
switch ( ord ) |
|
{ |
|
case 'n': |
|
return 'sw'; |
|
case 's': |
|
return 'nw'; |
|
case 'e': |
|
return 'nw'; |
|
case 'w': |
|
return 'ne'; |
|
case 'ne': |
|
return 'sw'; |
|
case 'nw': |
|
return 'se'; |
|
case 'se': |
|
return 'nw'; |
|
case 'sw': |
|
return 'ne'; |
|
} |
|
} |
|
//}}} |
|
function createDragger( ord ) //{{{ |
|
{ |
|
return function ( e ) |
|
{ |
|
if ( options.disabled ) |
|
{ |
|
return false; |
|
} |
|
if ( ( ord === 'move' ) && !options.allowMove ) |
|
{ |
|
return false; |
|
} |
|
|
|
// Fix position of crop area when dragged the very first time. |
|
// Necessary when crop image is in a hidden element when page is loaded. |
|
docOffset = getPos( $img ); |
|
|
|
btndown = true; |
|
startDragMode( ord, mouseAbs( e ) ); |
|
e.stopPropagation(); |
|
e.preventDefault(); |
|
return false; |
|
}; |
|
} |
|
//}}} |
|
function presize( $obj, w, h ) //{{{ |
|
{ |
|
var nw = $obj.width(), |
|
nh = $obj.height(); |
|
if ( ( nw > w ) && w > 0 ) |
|
{ |
|
nw = w; |
|
nh = ( w / $obj.width() ) * $obj.height(); |
|
} |
|
if ( ( nh > h ) && h > 0 ) |
|
{ |
|
nh = h; |
|
nw = ( h / $obj.height() ) * $obj.width(); |
|
} |
|
xscale = $obj.width() / nw; |
|
yscale = $obj.height() / nh; |
|
$obj.width( nw ).height( nh ); |
|
} |
|
//}}} |
|
function unscale( c ) //{{{ |
|
{ |
|
return { |
|
x: c.x * xscale, |
|
y: c.y * yscale, |
|
x2: c.x2 * xscale, |
|
y2: c.y2 * yscale, |
|
w: c.w * xscale, |
|
h: c.h * yscale |
|
}; |
|
} |
|
//}}} |
|
function doneSelect( pos ) //{{{ |
|
{ |
|
var c = Coords.getFixed(); |
|
if ( ( c.w > options.minSelect[ 0 ] ) && ( c.h > options.minSelect[ 1 ] ) ) |
|
{ |
|
Selection.enableHandles(); |
|
Selection.done(); |
|
} |
|
else |
|
{ |
|
Selection.release(); |
|
} |
|
Tracker.setCursor( options.allowSelect ? 'crosshair' : 'default' ); |
|
} |
|
//}}} |
|
function newSelection( e ) //{{{ |
|
{ |
|
if ( options.disabled ) |
|
{ |
|
return false; |
|
} |
|
if ( !options.allowSelect ) |
|
{ |
|
return false; |
|
} |
|
btndown = true; |
|
docOffset = getPos( $img ); |
|
Selection.disableHandles(); |
|
Tracker.setCursor( 'crosshair' ); |
|
var pos = mouseAbs( e ); |
|
Coords.setPressed( pos ); |
|
Selection.update(); |
|
Tracker.activateHandlers( selectDrag, doneSelect, e.type.substring( 0, 5 ) === 'touch' ); |
|
KeyManager.watchKeys(); |
|
|
|
e.stopPropagation(); |
|
e.preventDefault(); |
|
return false; |
|
} |
|
//}}} |
|
function selectDrag( pos ) //{{{ |
|
{ |
|
Coords.setCurrent( pos ); |
|
Selection.update(); |
|
} |
|
//}}} |
|
function newTracker() //{{{ |
|
{ |
|
var trk = $( '<div></div>' ).addClass( cssClass( 'tracker' ) ); |
|
if ( is_msie ) |
|
{ |
|
trk.css( |
|
{ |
|
opacity: 0, |
|
backgroundColor: 'white' |
|
} ); |
|
} |
|
return trk; |
|
} |
|
//}}} |
|
|
|
// }}} |
|
// Initialization {{{ |
|
// Sanitize some options {{{ |
|
if ( typeof ( obj ) !== 'object' ) |
|
{ |
|
obj = $( obj )[ 0 ]; |
|
} |
|
if ( typeof ( opt ) !== 'object' ) |
|
{ |
|
opt = {}; |
|
} |
|
// }}} |
|
setOptions( opt ); |
|
// Initialize some jQuery objects {{{ |
|
// The values are SET on the image(s) for the interface |
|
// If the original image has any of these set, they will be reset |
|
// However, if you destroy() the Jcrop instance the original image's |
|
// character in the DOM will be as you left it. |
|
var img_css = { |
|
border: 'none', |
|
visibility: 'visible', |
|
margin: 0, |
|
padding: 0, |
|
position: 'absolute', |
|
top: 0, |
|
left: 0 |
|
}; |
|
|
|
var $origimg = $( obj ), |
|
img_mode = true; |
|
|
|
if ( obj.tagName == 'IMG' ) |
|
{ |
|
// Fix size of crop image. |
|
// Necessary when crop image is within a hidden element when page is loaded. |
|
if ( $origimg[ 0 ].width != 0 && $origimg[ 0 ].height != 0 ) |
|
{ |
|
// Obtain dimensions from contained img element. |
|
$origimg.width( $origimg[ 0 ].width ); |
|
$origimg.height( $origimg[ 0 ].height ); |
|
} |
|
else |
|
{ |
|
// Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0). |
|
var tempImage = new Image(); |
|
tempImage.src = $origimg[ 0 ].src; |
|
$origimg.width( tempImage.width ); |
|
$origimg.height( tempImage.height ); |
|
} |
|
|
|
var $img = $origimg.clone().removeAttr( 'id' ).css( img_css ).show(); |
|
|
|
$img.width( $origimg.width() ); |
|
$img.height( $origimg.height() ); |
|
$origimg.after( $img ).hide(); |
|
|
|
} |
|
else |
|
{ |
|
$img = $origimg.css( img_css ).show(); |
|
img_mode = false; |
|
if ( options.shade === null ) |
|
{ |
|
options.shade = true; |
|
} |
|
} |
|
|
|
presize( $img, options.boxWidth, options.boxHeight ); |
|
|
|
var boundx = $img.width(), |
|
boundy = $img.height(), |
|
|
|
|
|
$div = $( '<div />' ).width( boundx ).height( boundy ).addClass( cssClass( 'holder' ) ).css( |
|
{ |
|
position: 'relative', |
|
backgroundColor: options.bgColor |
|
} ).insertAfter( $origimg ).append( $img ); |
|
|
|
if ( options.addClass ) |
|
{ |
|
$div.addClass( options.addClass ); |
|
} |
|
|
|
var $img2 = $( '<div />' ), |
|
|
|
$img_holder = $( '<div />' ) |
|
.width( '100%' ).height( '100%' ).css( |
|
{ |
|
zIndex: 310, |
|
position: 'absolute', |
|
overflow: 'hidden' |
|
} ), |
|
|
|
$hdl_holder = $( '<div />' ) |
|
.width( '100%' ).height( '100%' ).css( 'zIndex', 320 ), |
|
|
|
$sel = $( '<div />' ) |
|
.css( |
|
{ |
|
position: 'absolute', |
|
zIndex: 600 |
|
} ).dblclick( function () |
|
{ |
|
var c = Coords.getFixed(); |
|
options.onDblClick.call( api, c ); |
|
} ).insertBefore( $img ).append( $img_holder, $hdl_holder ); |
|
|
|
if ( img_mode ) |
|
{ |
|
|
|
$img2 = $( '<img />' ) |
|
.attr( 'src', $img.attr( 'src' ) ).css( img_css ).width( boundx ).height( boundy ), |
|
|
|
$img_holder.append( $img2 ); |
|
|
|
} |
|
|
|
if ( ie6mode ) |
|
{ |
|
$sel.css( |
|
{ |
|
overflowY: 'hidden' |
|
} ); |
|
} |
|
|
|
var bound = options.boundary; |
|
var $trk = newTracker().width( boundx + ( bound * 2 ) ).height( boundy + ( bound * 2 ) ).css( |
|
{ |
|
position: 'absolute', |
|
top: px( -bound ), |
|
left: px( -bound ), |
|
zIndex: 290 |
|
} ).mousedown( newSelection ); |
|
|
|
/* }}} */ |
|
// Set more variables {{{ |
|
var bgcolor = options.bgColor, |
|
bgopacity = options.bgOpacity, |
|
xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true, |
|
btndown, animating, shift_down; |
|
|
|
docOffset = getPos( $img ); |
|
// }}} |
|
// }}} |
|
// Internal Modules {{{ |
|
// Touch Module {{{ |
|
var Touch = ( function () |
|
{ |
|
// Touch support detection function adapted (under MIT License) |
|
// from code by Jeffrey Sambells - http://github.com/iamamused/ |
|
function hasTouchSupport() |
|
{ |
|
var support = {}, events = [ 'touchstart', 'touchmove', 'touchend' ], |
|
el = document.createElement( 'div' ), |
|
i; |
|
|
|
try |
|
{ |
|
for ( i = 0; i < events.length; i++ ) |
|
{ |
|
var eventName = events[ i ]; |
|
eventName = 'on' + eventName; |
|
var isSupported = ( eventName in el ); |
|
if ( !isSupported ) |
|
{ |
|
el.setAttribute( eventName, 'return;' ); |
|
isSupported = typeof el[ eventName ] == 'function'; |
|
} |
|
support[ events[ i ] ] = isSupported; |
|
} |
|
return support.touchstart && support.touchend && support.touchmove; |
|
} |
|
catch ( err ) |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
function detectSupport() |
|
{ |
|
if ( ( options.touchSupport === true ) || ( options.touchSupport === false ) ) return options.touchSupport; |
|
else return hasTouchSupport(); |
|
} |
|
return { |
|
createDragger: function ( ord ) |
|
{ |
|
return function ( e ) |
|
{ |
|
if ( options.disabled ) |
|
{ |
|
return false; |
|
} |
|
if ( ( ord === 'move' ) && !options.allowMove ) |
|
{ |
|
return false; |
|
} |
|
docOffset = getPos( $img ); |
|
btndown = true; |
|
startDragMode( ord, mouseAbs( Touch.cfilter( e ) ), true ); |
|
e.stopPropagation(); |
|
e.preventDefault(); |
|
return false; |
|
}; |
|
}, |
|
newSelection: function ( e ) |
|
{ |
|
return newSelection( Touch.cfilter( e ) ); |
|
}, |
|
cfilter: function ( e ) |
|
{ |
|
e.pageX = e.originalEvent.changedTouches[ 0 ].pageX; |
|
e.pageY = e.originalEvent.changedTouches[ 0 ].pageY; |
|
return e; |
|
}, |
|
isSupported: hasTouchSupport, |
|
support: detectSupport() |
|
}; |
|
}() ); |
|
// }}} |
|
// Coords Module {{{ |
|
var Coords = ( function () |
|
{ |
|
var x1 = 0, |
|
y1 = 0, |
|
x2 = 0, |
|
y2 = 0, |
|
ox, oy; |
|
|
|
function setPressed( pos ) //{{{ |
|
{ |
|
pos = rebound( pos ); |
|
x2 = x1 = pos[ 0 ]; |
|
y2 = y1 = pos[ 1 ]; |
|
} |
|
//}}} |
|
function setCurrent( pos ) //{{{ |
|
{ |
|
pos = rebound( pos ); |
|
ox = pos[ 0 ] - x2; |
|
oy = pos[ 1 ] - y2; |
|
x2 = pos[ 0 ]; |
|
y2 = pos[ 1 ]; |
|
} |
|
//}}} |
|
function getOffset() //{{{ |
|
{ |
|
return [ ox, oy ]; |
|
} |
|
//}}} |
|
function moveOffset( offset ) //{{{ |
|
{ |
|
var ox = offset[ 0 ], |
|
oy = offset[ 1 ]; |
|
|
|
if ( 0 > x1 + ox ) |
|
{ |
|
ox -= ox + x1; |
|
} |
|
if ( 0 > y1 + oy ) |
|
{ |
|
oy -= oy + y1; |
|
} |
|
|
|
if ( boundy < y2 + oy ) |
|
{ |
|
oy += boundy - ( y2 + oy ); |
|
} |
|
if ( boundx < x2 + ox ) |
|
{ |
|
ox += boundx - ( x2 + ox ); |
|
} |
|
|
|
x1 += ox; |
|
x2 += ox; |
|
y1 += oy; |
|
y2 += oy; |
|
} |
|
//}}} |
|
function getCorner( ord ) //{{{ |
|
{ |
|
var c = getFixed(); |
|
switch ( ord ) |
|
{ |
|
case 'ne': |
|
return [ c.x2, c.y ]; |
|
case 'nw': |
|
return [ c.x, c.y ]; |
|
case 'se': |
|
return [ c.x2, c.y2 ]; |
|
case 'sw': |
|
return [ c.x, c.y2 ]; |
|
} |
|
} |
|
//}}} |
|
function getFixed() //{{{ |
|
{ |
|
if ( !options.aspectRatio ) |
|
{ |
|
return getRect(); |
|
} |
|
// This function could use some optimization I think... |
|
var aspect = options.aspectRatio, |
|
min_x = options.minSize[ 0 ] / xscale, |
|
|
|
|
|
//min_y = options.minSize[1]/yscale, |
|
max_x = options.maxSize[ 0 ] / xscale, |
|
max_y = options.maxSize[ 1 ] / yscale, |
|
rw = x2 - x1, |
|
rh = y2 - y1, |
|
rwa = Math.abs( rw ), |
|
rha = Math.abs( rh ), |
|
real_ratio = rwa / rha, |
|
xx, yy, w, h; |
|
|
|
if ( max_x === 0 ) |
|
{ |
|
max_x = boundx * 10; |
|
} |
|
if ( max_y === 0 ) |
|
{ |
|
max_y = boundy * 10; |
|
} |
|
if ( real_ratio < aspect ) |
|
{ |
|
yy = y2; |
|
w = rha * aspect; |
|
xx = rw < 0 ? x1 - w : w + x1; |
|
|
|
if ( xx < 0 ) |
|
{ |
|
xx = 0; |
|
h = Math.abs( ( xx - x1 ) / aspect ); |
|
yy = rh < 0 ? y1 - h : h + y1; |
|
} |
|
else if ( xx > boundx ) |
|
{ |
|
xx = boundx; |
|
h = Math.abs( ( xx - x1 ) / aspect ); |
|
yy = rh < 0 ? y1 - h : h + y1; |
|
} |
|
} |
|
else |
|
{ |
|
xx = x2; |
|
h = rwa / aspect; |
|
yy = rh < 0 ? y1 - h : y1 + h; |
|
if ( yy < 0 ) |
|
{ |
|
yy = 0; |
|
w = Math.abs( ( yy - y1 ) * aspect ); |
|
xx = rw < 0 ? x1 - w : w + x1; |
|
} |
|
else if ( yy > boundy ) |
|
{ |
|
yy = boundy; |
|
w = Math.abs( yy - y1 ) * aspect; |
|
xx = rw < 0 ? x1 - w : w + x1; |
|
} |
|
} |
|
|
|
// Magic %-) |
|
if ( xx > x1 ) |
|
{ // right side |
|
if ( xx - x1 < min_x ) |
|
{ |
|
xx = x1 + min_x; |
|
} |
|
else if ( xx - x1 > max_x ) |
|
{ |
|
xx = x1 + max_x; |
|
} |
|
if ( yy > y1 ) |
|
{ |
|
yy = y1 + ( xx - x1 ) / aspect; |
|
} |
|
else |
|
{ |
|
yy = y1 - ( xx - x1 ) / aspect; |
|
} |
|
} |
|
else if ( xx < x1 ) |
|
{ // left side |
|
if ( x1 - xx < min_x ) |
|
{ |
|
xx = x1 - min_x; |
|
} |
|
else if ( x1 - xx > max_x ) |
|
{ |
|
xx = x1 - max_x; |
|
} |
|
if ( yy > y1 ) |
|
{ |
|
yy = y1 + ( x1 - xx ) / aspect; |
|
} |
|
else |
|
{ |
|
yy = y1 - ( x1 - xx ) / aspect; |
|
} |
|
} |
|
|
|
if ( xx < 0 ) |
|
{ |
|
x1 -= xx; |
|
xx = 0; |
|
} |
|
else if ( xx > boundx ) |
|
{ |
|
x1 -= xx - boundx; |
|
xx = boundx; |
|
} |
|
|
|
if ( yy < 0 ) |
|
{ |
|
y1 -= yy; |
|
yy = 0; |
|
} |
|
else if ( yy > boundy ) |
|
{ |
|
y1 -= yy - boundy; |
|
yy = boundy; |
|
} |
|
|
|
return makeObj( flipCoords( x1, y1, xx, yy ) ); |
|
} |
|
//}}} |
|
function rebound( p ) //{{{ |
|
{ |
|
if ( p[ 0 ] < 0 ) p[ 0 ] = 0; |
|
if ( p[ 1 ] < 0 ) p[ 1 ] = 0; |
|
|
|
if ( p[ 0 ] > boundx ) p[ 0 ] = boundx; |
|
if ( p[ 1 ] > boundy ) p[ 1 ] = boundy; |
|
|
|
return [ Math.round( p[ 0 ] ), Math.round( p[ 1 ] ) ]; |
|
} |
|
//}}} |
|
function flipCoords( x1, y1, x2, y2 ) //{{{ |
|
{ |
|
var xa = x1, |
|
xb = x2, |
|
ya = y1, |
|
yb = y2; |
|
if ( x2 < x1 ) |
|
{ |
|
xa = x2; |
|
xb = x1; |
|
} |
|
if ( y2 < y1 ) |
|
{ |
|
ya = y2; |
|
yb = y1; |
|
} |
|
return [ xa, ya, xb, yb ]; |
|
} |
|
//}}} |
|
function getRect() //{{{ |
|
{ |
|
var xsize = x2 - x1, |
|
ysize = y2 - y1, |
|
delta; |
|
|
|
if ( xlimit && ( Math.abs( xsize ) > xlimit ) ) |
|
{ |
|
x2 = ( xsize > 0 ) ? ( x1 + xlimit ) : ( x1 - xlimit ); |
|
} |
|
if ( ylimit && ( Math.abs( ysize ) > ylimit ) ) |
|
{ |
|
y2 = ( ysize > 0 ) ? ( y1 + ylimit ) : ( y1 - ylimit ); |
|
} |
|
|
|
if ( ymin / yscale && ( Math.abs( ysize ) < ymin / yscale ) ) |
|
{ |
|
y2 = ( ysize > 0 ) ? ( y1 + ymin / yscale ) : ( y1 - ymin / yscale ); |
|
} |
|
if ( xmin / xscale && ( Math.abs( xsize ) < xmin / xscale ) ) |
|
{ |
|
x2 = ( xsize > 0 ) ? ( x1 + xmin / xscale ) : ( x1 - xmin / xscale ); |
|
} |
|
|
|
if ( x1 < 0 ) |
|
{ |
|
x2 -= x1; |
|
x1 -= x1; |
|
} |
|
if ( y1 < 0 ) |
|
{ |
|
y2 -= y1; |
|
y1 -= y1; |
|
} |
|
if ( x2 < 0 ) |
|
{ |
|
x1 -= x2; |
|
x2 -= x2; |
|
} |
|
if ( y2 < 0 ) |
|
{ |
|
y1 -= y2; |
|
y2 -= y2; |
|
} |
|
if ( x2 > boundx ) |
|
{ |
|
delta = x2 - boundx; |
|
x1 -= delta; |
|
x2 -= delta; |
|
} |
|
if ( y2 > boundy ) |
|
{ |
|
delta = y2 - boundy; |
|
y1 -= delta; |
|
y2 -= delta; |
|
} |
|
if ( x1 > boundx ) |
|
{ |
|
delta = x1 - boundy; |
|
y2 -= delta; |
|
y1 -= delta; |
|
} |
|
if ( y1 > boundy ) |
|
{ |
|
delta = y1 - boundy; |
|
y2 -= delta; |
|
y1 -= delta; |
|
} |
|
|
|
return makeObj( flipCoords( x1, y1, x2, y2 ) ); |
|
} |
|
//}}} |
|
function makeObj( a ) //{{{ |
|
{ |
|
return { |
|
x: a[ 0 ], |
|
y: a[ 1 ], |
|
x2: a[ 2 ], |
|
y2: a[ 3 ], |
|
w: a[ 2 ] - a[ 0 ], |
|
h: a[ 3 ] - a[ 1 ] |
|
}; |
|
} |
|
//}}} |
|
|
|
return { |
|
flipCoords: flipCoords, |
|
setPressed: setPressed, |
|
setCurrent: setCurrent, |
|
getOffset: getOffset, |
|
moveOffset: moveOffset, |
|
getCorner: getCorner, |
|
getFixed: getFixed |
|
}; |
|
}() ); |
|
|
|
//}}} |
|
// Shade Module {{{ |
|
var Shade = ( function () |
|
{ |
|
var enabled = false, |
|
holder = $( '<div />' ).css( |
|
{ |
|
position: 'absolute', |
|
zIndex: 240, |
|
opacity: 0 |
|
} ), |
|
shades = { |
|
top: createShade(), |
|
left: createShade().height( boundy ), |
|
right: createShade().height( boundy ), |
|
bottom: createShade() |
|
}; |
|
|
|
function resizeShades( w, h ) |
|
{ |
|
shades.left.css( |
|
{ |
|
height: px( h ) |
|
} ); |
|
shades.right.css( |
|
{ |
|
height: px( h ) |
|
} ); |
|
} |
|
|
|
function updateAuto() |
|
{ |
|
return updateShade( Coords.getFixed() ); |
|
} |
|
|
|
function updateShade( c ) |
|
{ |
|
shades.top.css( |
|
{ |
|
left: px( c.x ), |
|
width: px( c.w ), |
|
height: px( c.y ) |
|
} ); |
|
shades.bottom.css( |
|
{ |
|
top: px( c.y2 ), |
|
left: px( c.x ), |
|
width: px( c.w ), |
|
height: px( boundy - c.y2 ) |
|
} ); |
|
shades.right.css( |
|
{ |
|
left: px( c.x2 ), |
|
width: px( boundx - c.x2 ) |
|
} ); |
|
shades.left.css( |
|
{ |
|
width: px( c.x ) |
|
} ); |
|
} |
|
|
|
function createShade() |
|
{ |
|
return $( '<div />' ).css( |
|
{ |
|
position: 'absolute', |
|
backgroundColor: options.shadeColor || options.bgColor |
|
} ).appendTo( holder ); |
|
} |
|
|
|
function enableShade() |
|
{ |
|
if ( !enabled ) |
|
{ |
|
enabled = true; |
|
holder.insertBefore( $img ); |
|
updateAuto(); |
|
Selection.setBgOpacity( 1, 0, 1 ); |
|
$img2.hide(); |
|
|
|
setBgColor( options.shadeColor || options.bgColor, 1 ); |
|
if ( Selection.isAwake() ) |
|
{ |
|
setOpacity( options.bgOpacity, 1 ); |
|
} |
|
else setOpacity( 1, 1 ); |
|
} |
|
} |
|
|
|
function setBgColor( color, now ) |
|
{ |
|
colorChangeMacro( getShades(), color, now ); |
|
} |
|
|
|
function disableShade() |
|
{ |
|
if ( enabled ) |
|
{ |
|
holder.remove(); |
|
$img2.show(); |
|
enabled = false; |
|
if ( Selection.isAwake() ) |
|
{ |
|
Selection.setBgOpacity( options.bgOpacity, 1, 1 ); |
|
} |
|
else |
|
{ |
|
Selection.setBgOpacity( 1, 1, 1 ); |
|
Selection.disableHandles(); |
|
} |
|
colorChangeMacro( $div, 0, 1 ); |
|
} |
|
} |
|
|
|
function setOpacity( opacity, now ) |
|
{ |
|
if ( enabled ) |
|
{ |
|
if ( options.bgFade && !now ) |
|
{ |
|
holder.animate( |
|
{ |
|
opacity: 1 - opacity |
|
}, |
|
{ |
|
queue: false, |
|
duration: options.fadeTime |
|
} ); |
|
} |
|
else holder.css( |
|
{ |
|
opacity: 1 - opacity |
|
} ); |
|
} |
|
} |
|
|
|
function refreshAll() |
|
{ |
|
options.shade ? enableShade() : disableShade(); |
|
if ( Selection.isAwake() ) setOpacity( options.bgOpacity ); |
|
} |
|
|
|
function getShades() |
|
{ |
|
return holder.children(); |
|
} |
|
|
|
return { |
|
update: updateAuto, |
|
updateRaw: updateShade, |
|
getShades: getShades, |
|
setBgColor: setBgColor, |
|
enable: enableShade, |
|
disable: disableShade, |
|
resize: resizeShades, |
|
refresh: refreshAll, |
|
opacity: setOpacity |
|
}; |
|
}() ); |
|
// }}} |
|
// Selection Module {{{ |
|
var Selection = ( function () |
|
{ |
|
var awake, |
|
hdep = 370, |
|
borders = {}, |
|
handle = {}, |
|
dragbar = {}, |
|
seehandles = false; |
|
|
|
// Private Methods |
|
function insertBorder( type ) //{{{ |
|
{ |
|
var jq = $( '<div />' ).css( |
|
{ |
|
position: 'absolute', |
|
opacity: options.borderOpacity |
|
} ).addClass( cssClass( type ) ); |
|
$img_holder.append( jq ); |
|
return jq; |
|
} |
|
//}}} |
|
function dragDiv( ord, zi ) //{{{ |
|
{ |
|
var jq = $( '<div />' ).mousedown( createDragger( ord ) ).css( |
|
{ |
|
cursor: ord + '-resize', |
|
position: 'absolute', |
|
zIndex: zi |
|
} ).addClass( 'ord-' + ord ); |
|
|
|
if ( Touch.support ) |
|
{ |
|
jq.bind( 'touchstart.jcrop', Touch.createDragger( ord ) ); |
|
} |
|
|
|
$hdl_holder.append( jq ); |
|
return jq; |
|
} |
|
//}}} |
|
function insertHandle( ord ) //{{{ |
|
{ |
|
var hs = options.handleSize, |
|
|
|
div = dragDiv( ord, hdep++ ).css( |
|
{ |
|
opacity: options.handleOpacity |
|
} ).addClass( cssClass( 'handle' ) ); |
|
|
|
if ( hs ) |
|
{ |
|
div.width( hs ).height( hs ); |
|
} |
|
|
|
return div; |
|
} |
|
//}}} |
|
function insertDragbar( ord ) //{{{ |
|
{ |
|
return dragDiv( ord, hdep++ ).addClass( 'jcrop-dragbar' ); |
|
} |
|
//}}} |
|
function createDragbars( li ) //{{{ |
|
{ |
|
var i; |
|
for ( i = 0; i < li.length; i++ ) |
|
{ |
|
dragbar[ li[ i ] ] = insertDragbar( li[ i ] ); |
|
} |
|
} |
|
//}}} |
|
function createBorders( li ) //{{{ |
|
{ |
|
var cl, i; |
|
for ( i = 0; i < li.length; i++ ) |
|
{ |
|
switch ( li[ i ] ) |
|
{ |
|
case 'n': |
|
cl = 'hline'; |
|
break; |
|
case 's': |
|
cl = 'hline bottom'; |
|
break; |
|
case 'e': |
|
cl = 'vline right'; |
|
break; |
|
case 'w': |
|
cl = 'vline'; |
|
break; |
|
} |
|
borders[ li[ i ] ] = insertBorder( cl ); |
|
} |
|
} |
|
//}}} |
|
function createHandles( li ) //{{{ |
|
{ |
|
var i; |
|
for ( i = 0; i < li.length; i++ ) |
|
{ |
|
handle[ li[ i ] ] = insertHandle( li[ i ] ); |
|
} |
|
} |
|
//}}} |
|
function moveto( x, y ) //{{{ |
|
{ |
|
if ( !options.shade ) |
|
{ |
|
$img2.css( |
|
{ |
|
top: px( -y ), |
|
left: px( -x ) |
|
} ); |
|
} |
|
$sel.css( |
|
{ |
|
top: px( y ), |
|
left: px( x ) |
|
} ); |
|
} |
|
//}}} |
|
function resize( w, h ) //{{{ |
|
{ |
|
$sel.width( Math.round( w ) ).height( Math.round( h ) ); |
|
} |
|
//}}} |
|
function refresh() //{{{ |
|
{ |
|
var c = Coords.getFixed(); |
|
|
|
Coords.setPressed( [ c.x, c.y ] ); |
|
Coords.setCurrent( [ c.x2, c.y2 ] ); |
|
|
|
updateVisible(); |
|
} |
|
//}}} |
|
|
|
// Internal Methods |
|
function updateVisible( select ) //{{{ |
|
{ |
|
if ( awake ) |
|
{ |
|
return update( select ); |
|
} |
|
} |
|
//}}} |
|
function update( select ) //{{{ |
|
{ |
|
var c = Coords.getFixed(); |
|
|
|
resize( c.w, c.h ); |
|
moveto( c.x, c.y ); |
|
if ( options.shade ) Shade.updateRaw( c ); |
|
|
|
awake || show(); |
|
|
|
if ( select ) |
|
{ |
|
options.onSelect.call( api, unscale( c ) ); |
|
} |
|
else |
|
{ |
|
options.onChange.call( api, unscale( c ) ); |
|
} |
|
} |
|
//}}} |
|
function setBgOpacity( opacity, force, now ) //{{{ |
|
{ |
|
if ( !awake && !force ) return; |
|
if ( options.bgFade && !now ) |
|
{ |
|
$img.animate( |
|
{ |
|
opacity: opacity |
|
}, |
|
{ |
|
queue: false, |
|
duration: options.fadeTime |
|
} ); |
|
} |
|
else |
|
{ |
|
$img.css( 'opacity', opacity ); |
|
} |
|
} |
|
//}}} |
|
function show() //{{{ |
|
{ |
|
$sel.show(); |
|
|
|
if ( options.shade ) Shade.opacity( bgopacity ); |
|
else setBgOpacity( bgopacity, true ); |
|
|
|
awake = true; |
|
} |
|
//}}} |
|
function release() //{{{ |
|
{ |
|
disableHandles(); |
|
$sel.hide(); |
|
|
|
if ( options.shade ) Shade.opacity( 1 ); |
|
else setBgOpacity( 1 ); |
|
|
|
awake = false; |
|
options.onRelease.call( api ); |
|
} |
|
//}}} |
|
function showHandles() //{{{ |
|
{ |
|
if ( seehandles ) |
|
{ |
|
$hdl_holder.show(); |
|
} |
|
} |
|
//}}} |
|
function enableHandles() //{{{ |
|
{ |
|
seehandles = true; |
|
if ( options.allowResize ) |
|
{ |
|
$hdl_holder.show(); |
|
return true; |
|
} |
|
} |
|
//}}} |
|
function disableHandles() //{{{ |
|
{ |
|
seehandles = false; |
|
$hdl_holder.hide(); |
|
} |
|
//}}} |
|
function animMode( v ) //{{{ |
|
{ |
|
if ( v ) |
|
{ |
|
animating = true; |
|
disableHandles(); |
|
} |
|
else |
|
{ |
|
animating = false; |
|
enableHandles(); |
|
} |
|
} |
|
//}}} |
|
function done() //{{{ |
|
{ |
|
animMode( false ); |
|
refresh(); |
|
} |
|
//}}} |
|
// Insert draggable elements {{{ |
|
// Insert border divs for outline |
|
|
|
if ( options.dragEdges && $.isArray( options.createDragbars ) ) |
|
createDragbars( options.createDragbars ); |
|
|
|
if ( $.isArray( options.createHandles ) ) |
|
createHandles( options.createHandles ); |
|
|
|
if ( options.drawBorders && $.isArray( options.createBorders ) ) |
|
createBorders( options.createBorders ); |
|
|
|
//}}} |
|
|
|
// This is a hack for iOS5 to support drag/move touch functionality |
|
$( document ).bind( 'touchstart.jcrop-ios', function ( e ) |
|
{ |
|
if ( $( e.currentTarget ).hasClass( 'jcrop-tracker' ) ) e.stopPropagation(); |
|
} ); |
|
|
|
var $track = newTracker().mousedown( createDragger( 'move' ) ).css( |
|
{ |
|
cursor: 'move', |
|
position: 'absolute', |
|
zIndex: 360 |
|
} ); |
|
|
|
if ( Touch.support ) |
|
{ |
|
$track.bind( 'touchstart.jcrop', Touch.createDragger( 'move' ) ); |
|
} |
|
|
|
$img_holder.append( $track ); |
|
disableHandles(); |
|
|
|
return { |
|
updateVisible: updateVisible, |
|
update: update, |
|
release: release, |
|
refresh: refresh, |
|
isAwake: function () |
|
{ |
|
return awake; |
|
}, |
|
setCursor: function ( cursor ) |
|
{ |
|
$track.css( 'cursor', cursor ); |
|
}, |
|
enableHandles: enableHandles, |
|
enableOnly: function () |
|
{ |
|
seehandles = true; |
|
}, |
|
showHandles: showHandles, |
|
disableHandles: disableHandles, |
|
animMode: animMode, |
|
setBgOpacity: setBgOpacity, |
|
done: done |
|
}; |
|
}() ); |
|
|
|
//}}} |
|
// Tracker Module {{{ |
|
var Tracker = ( function () |
|
{ |
|
var onMove = function () {}, |
|
onDone = function () {}, |
|
trackDoc = options.trackDocument; |
|
|
|
function toFront( touch ) //{{{ |
|
{ |
|
$trk.css( |
|
{ |
|
zIndex: 450 |
|
} ); |
|
|
|
if ( touch ) |
|
$( document ) |
|
.bind( 'touchmove.jcrop', trackTouchMove ) |
|
.bind( 'touchend.jcrop', trackTouchEnd ); |
|
|
|
else if ( trackDoc ) |
|
$( document ) |
|
.bind( 'mousemove.jcrop', trackMove ) |
|
.bind( 'mouseup.jcrop', trackUp ); |
|
} |
|
//}}} |
|
function toBack() //{{{ |
|
{ |
|
$trk.css( |
|
{ |
|
zIndex: 290 |
|
} ); |
|
$( document ).unbind( '.jcrop' ); |
|
} |
|
//}}} |
|
function trackMove( e ) //{{{ |
|
{ |
|
onMove( mouseAbs( e ) ); |
|
return false; |
|
} |
|
//}}} |
|
function trackUp( e ) //{{{ |
|
{ |
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
|
|
if ( btndown ) |
|
{ |
|
btndown = false; |
|
|
|
onDone( mouseAbs( e ) ); |
|
|
|
if ( Selection.isAwake() ) |
|
{ |
|
options.onSelect.call( api, unscale( Coords.getFixed() ) ); |
|
} |
|
|
|
toBack(); |
|
onMove = function () {}; |
|
onDone = function () {}; |
|
} |
|
|
|
return false; |
|
} |
|
//}}} |
|
function activateHandlers( move, done, touch ) //{{{ |
|
{ |
|
btndown = true; |
|
onMove = move; |
|
onDone = done; |
|
toFront( touch ); |
|
return false; |
|
} |
|
//}}} |
|
function trackTouchMove( e ) //{{{ |
|
{ |
|
onMove( mouseAbs( Touch.cfilter( e ) ) ); |
|
return false; |
|
} |
|
//}}} |
|
function trackTouchEnd( e ) //{{{ |
|
{ |
|
return trackUp( Touch.cfilter( e ) ); |
|
} |
|
//}}} |
|
function setCursor( t ) //{{{ |
|
{ |
|
$trk.css( 'cursor', t ); |
|
} |
|
//}}} |
|
|
|
if ( !trackDoc ) |
|
{ |
|
$trk.mousemove( trackMove ).mouseup( trackUp ).mouseout( trackUp ); |
|
} |
|
|
|
$img.before( $trk ); |
|
return { |
|
activateHandlers: activateHandlers, |
|
setCursor: setCursor |
|
}; |
|
}() ); |
|
//}}} |
|
// KeyManager Module {{{ |
|
var KeyManager = ( function () |
|
{ |
|
var $keymgr = $( '<input type="radio" />' ).css( |
|
{ |
|
position: 'fixed', |
|
left: '-120px', |
|
width: '12px' |
|
} ).addClass( 'jcrop-keymgr' ), |
|
|
|
$keywrap = $( '<div />' ).css( |
|
{ |
|
position: 'absolute', |
|
overflow: 'hidden' |
|
} ).append( $keymgr ); |
|
|
|
function watchKeys() //{{{ |
|
{ |
|
if ( options.keySupport ) |
|
{ |
|
$keymgr.show(); |
|
$keymgr.focus(); |
|
} |
|
} |
|
//}}} |
|
function onBlur( e ) //{{{ |
|
{ |
|
$keymgr.hide(); |
|
} |
|
//}}} |
|
function doNudge( e, x, y ) //{{{ |
|
{ |
|
if ( options.allowMove ) |
|
{ |
|
Coords.moveOffset( [ x, y ] ); |
|
Selection.updateVisible( true ); |
|
} |
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
} |
|
//}}} |
|
function parseKey( e ) //{{{ |
|
{ |
|
if ( e.ctrlKey || e.metaKey ) |
|
{ |
|
return true; |
|
} |
|
shift_down = e.shiftKey ? true : false; |
|
var nudge = shift_down ? 10 : 1; |
|
|
|
switch ( e.keyCode ) |
|
{ |
|
case 37: |
|
doNudge( e, -nudge, 0 ); |
|
break; |
|
case 39: |
|
doNudge( e, nudge, 0 ); |
|
break; |
|
case 38: |
|
doNudge( e, 0, -nudge ); |
|
break; |
|
case 40: |
|
doNudge( e, 0, nudge ); |
|
break; |
|
case 27: |
|
if ( options.allowSelect ) Selection.release(); |
|
break; |
|
case 9: |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
//}}} |
|
|
|
if ( options.keySupport ) |
|
{ |
|
$keymgr.keydown( parseKey ).blur( onBlur ); |
|
if ( ie6mode || !options.fixedSupport ) |
|
{ |
|
$keymgr.css( |
|
{ |
|
position: 'absolute', |
|
left: '-20px' |
|
} ); |
|
$keywrap.append( $keymgr ).insertBefore( $img ); |
|
} |
|
else |
|
{ |
|
$keymgr.insertBefore( $img ); |
|
} |
|
} |
|
|
|
|
|
return { |
|
watchKeys: watchKeys |
|
}; |
|
}() ); |
|
//}}} |
|
// }}} |
|
// API methods {{{ |
|
function setClass( cname ) //{{{ |
|
{ |
|
$div.removeClass().addClass( cssClass( 'holder' ) ).addClass( cname ); |
|
} |
|
//}}} |
|
function animateTo( a, callback ) //{{{ |
|
{ |
|
var x1 = a[ 0 ] / xscale, |
|
y1 = a[ 1 ] / yscale, |
|
x2 = a[ 2 ] / xscale, |
|
y2 = a[ 3 ] / yscale; |
|
|
|
if ( animating ) |
|
{ |
|
return; |
|
} |
|
|
|
var animto = Coords.flipCoords( x1, y1, x2, y2 ), |
|
c = Coords.getFixed(), |
|
initcr = [ c.x, c.y, c.x2, c.y2 ], |
|
animat = initcr, |
|
interv = options.animationDelay, |
|
ix1 = animto[ 0 ] - initcr[ 0 ], |
|
iy1 = animto[ 1 ] - initcr[ 1 ], |
|
ix2 = animto[ 2 ] - initcr[ 2 ], |
|
iy2 = animto[ 3 ] - initcr[ 3 ], |
|
pcent = 0, |
|
velocity = options.swingSpeed; |
|
|
|
x1 = animat[ 0 ]; |
|
y1 = animat[ 1 ]; |
|
x2 = animat[ 2 ]; |
|
y2 = animat[ 3 ]; |
|
|
|
Selection.animMode( true ); |
|
var anim_timer; |
|
|
|
function queueAnimator() |
|
{ |
|
window.setTimeout( animator, interv ); |
|
} |
|
var animator = ( function () |
|
{ |
|
return function () |
|
{ |
|
pcent += ( 100 - pcent ) / velocity; |
|
|
|
animat[ 0 ] = Math.round( x1 + ( ( pcent / 100 ) * ix1 ) ); |
|
animat[ 1 ] = Math.round( y1 + ( ( pcent / 100 ) * iy1 ) ); |
|
animat[ 2 ] = Math.round( x2 + ( ( pcent / 100 ) * ix2 ) ); |
|
animat[ 3 ] = Math.round( y2 + ( ( pcent / 100 ) * iy2 ) ); |
|
|
|
if ( pcent >= 99.8 ) |
|
{ |
|
pcent = 100; |
|
} |
|
if ( pcent < 100 ) |
|
{ |
|
setSelectRaw( animat ); |
|
queueAnimator(); |
|
} |
|
else |
|
{ |
|
Selection.done(); |
|
Selection.animMode( false ); |
|
if ( typeof ( callback ) === 'function' ) |
|
{ |
|
callback.call( api ); |
|
} |
|
} |
|
}; |
|
}() ); |
|
queueAnimator(); |
|
} |
|
//}}} |
|
function setSelect( rect ) //{{{ |
|
{ |
|
setSelectRaw( [ rect[ 0 ] / xscale, rect[ 1 ] / yscale, rect[ 2 ] / xscale, rect[ 3 ] / yscale ] ); |
|
options.onSelect.call( api, unscale( Coords.getFixed() ) ); |
|
Selection.enableHandles(); |
|
} |
|
//}}} |
|
function setSelectRaw( l ) //{{{ |
|
{ |
|
Coords.setPressed( [ l[ 0 ], l[ 1 ] ] ); |
|
Coords.setCurrent( [ l[ 2 ], l[ 3 ] ] ); |
|
Selection.update(); |
|
} |
|
//}}} |
|
function tellSelect() //{{{ |
|
{ |
|
return unscale( Coords.getFixed() ); |
|
} |
|
//}}} |
|
function tellScaled() //{{{ |
|
{ |
|
return Coords.getFixed(); |
|
} |
|
//}}} |
|
function setOptionsNew( opt ) //{{{ |
|
{ |
|
setOptions( opt ); |
|
interfaceUpdate(); |
|
} |
|
//}}} |
|
function disableCrop() //{{{ |
|
{ |
|
options.disabled = true; |
|
Selection.disableHandles(); |
|
Selection.setCursor( 'default' ); |
|
Tracker.setCursor( 'default' ); |
|
} |
|
//}}} |
|
function enableCrop() //{{{ |
|
{ |
|
options.disabled = false; |
|
interfaceUpdate(); |
|
} |
|
//}}} |
|
function cancelCrop() //{{{ |
|
{ |
|
Selection.done(); |
|
Tracker.activateHandlers( null, null ); |
|
} |
|
//}}} |
|
function destroy() //{{{ |
|
{ |
|
$div.remove(); |
|
$origimg.show(); |
|
$origimg.css( 'visibility', 'visible' ); |
|
$( obj ).removeData( 'Jcrop' ); |
|
} |
|
//}}} |
|
function setImage( src, callback ) //{{{ |
|
{ |
|
Selection.release(); |
|
disableCrop(); |
|
var img = new Image(); |
|
img.onload = function () |
|
{ |
|
var iw = img.width; |
|
var ih = img.height; |
|
var bw = options.boxWidth; |
|
var bh = options.boxHeight; |
|
$img.width( iw ).height( ih ); |
|
$img.attr( 'src', src ); |
|
$img2.attr( 'src', src ); |
|
presize( $img, bw, bh ); |
|
boundx = $img.width(); |
|
boundy = $img.height(); |
|
$img2.width( boundx ).height( boundy ); |
|
$trk.width( boundx + ( bound * 2 ) ).height( boundy + ( bound * 2 ) ); |
|
$div.width( boundx ).height( boundy ); |
|
Shade.resize( boundx, boundy ); |
|
enableCrop(); |
|
|
|
if ( typeof ( callback ) === 'function' ) |
|
{ |
|
callback.call( api ); |
|
} |
|
}; |
|
img.src = src; |
|
} |
|
//}}} |
|
function colorChangeMacro( $obj, color, now ) |
|
{ |
|
var mycolor = color || options.bgColor; |
|
if ( options.bgFade && supportsColorFade() && options.fadeTime && !now ) |
|
{ |
|
$obj.animate( |
|
{ |
|
backgroundColor: mycolor |
|
}, |
|
{ |
|
queue: false, |
|
duration: options.fadeTime |
|
} ); |
|
} |
|
else |
|
{ |
|
$obj.css( 'backgroundColor', mycolor ); |
|
} |
|
} |
|
|
|
function interfaceUpdate( alt ) //{{{ |
|
// This method tweaks the interface based on options object. |
|
// Called when options are changed and at end of initialization. |
|
{ |
|
if ( options.allowResize ) |
|
{ |
|
if ( alt ) |
|
{ |
|
Selection.enableOnly(); |
|
} |
|
else |
|
{ |
|
Selection.enableHandles(); |
|
} |
|
} |
|
else |
|
{ |
|
Selection.disableHandles(); |
|
} |
|
|
|
Tracker.setCursor( options.allowSelect ? 'crosshair' : 'default' ); |
|
Selection.setCursor( options.allowMove ? 'move' : 'default' ); |
|
|
|
if ( options.hasOwnProperty( 'trueSize' ) ) |
|
{ |
|
xscale = options.trueSize[ 0 ] / boundx; |
|
yscale = options.trueSize[ 1 ] / boundy; |
|
} |
|
|
|
if ( options.hasOwnProperty( 'setSelect' ) ) |
|
{ |
|
setSelect( options.setSelect ); |
|
Selection.done(); |
|
delete( options.setSelect ); |
|
} |
|
|
|
Shade.refresh(); |
|
|
|
if ( options.bgColor != bgcolor ) |
|
{ |
|
colorChangeMacro( |
|
options.shade ? Shade.getShades() : $div, |
|
options.shade ? |
|
( options.shadeColor || options.bgColor ) : |
|
options.bgColor |
|
); |
|
bgcolor = options.bgColor; |
|
} |
|
|
|
if ( bgopacity != options.bgOpacity ) |
|
{ |
|
bgopacity = options.bgOpacity; |
|
if ( options.shade ) Shade.refresh(); |
|
else Selection.setBgOpacity( bgopacity ); |
|
} |
|
|
|
xlimit = options.maxSize[ 0 ] || 0; |
|
ylimit = options.maxSize[ 1 ] || 0; |
|
xmin = options.minSize[ 0 ] || 0; |
|
ymin = options.minSize[ 1 ] || 0; |
|
|
|
if ( options.hasOwnProperty( 'outerImage' ) ) |
|
{ |
|
$img.attr( 'src', options.outerImage ); |
|
delete( options.outerImage ); |
|
} |
|
|
|
Selection.refresh(); |
|
} |
|
//}}} |
|
//}}} |
|
|
|
if ( Touch.support ) $trk.bind( 'touchstart.jcrop', Touch.newSelection ); |
|
|
|
$hdl_holder.hide(); |
|
interfaceUpdate( true ); |
|
|
|
var api = { |
|
setImage: setImage, |
|
animateTo: animateTo, |
|
setSelect: setSelect, |
|
setOptions: setOptionsNew, |
|
tellSelect: tellSelect, |
|
tellScaled: tellScaled, |
|
setClass: setClass, |
|
|
|
disable: disableCrop, |
|
enable: enableCrop, |
|
cancel: cancelCrop, |
|
release: Selection.release, |
|
destroy: destroy, |
|
|
|
focus: KeyManager.watchKeys, |
|
|
|
getBounds: function () |
|
{ |
|
return [ boundx * xscale, boundy * yscale ]; |
|
}, |
|
getWidgetSize: function () |
|
{ |
|
return [ boundx, boundy ]; |
|
}, |
|
getScaleFactor: function () |
|
{ |
|
return [ xscale, yscale ]; |
|
}, |
|
getOptions: function () |
|
{ |
|
// careful: internal values are returned |
|
return options; |
|
}, |
|
|
|
ui: |
|
{ |
|
holder: $div, |
|
selection: $sel |
|
} |
|
}; |
|
|
|
if ( is_msie ) $div.bind( 'selectstart', function () |
|
{ |
|
return false; |
|
} ); |
|
|
|
$origimg.data( 'Jcrop', api ); |
|
return api; |
|
}; |
|
$.fn.Jcrop = function ( options, callback ) //{{{ |
|
{ |
|
var api; |
|
// Iterate over each object, attach Jcrop |
|
this.each( function () |
|
{ |
|
// If we've already attached to this object |
|
if ( $( this ).data( 'Jcrop' ) ) |
|
{ |
|
// The API can be requested this way (undocumented) |
|
if ( options === 'api' ) return $( this ).data( 'Jcrop' ); |
|
// Otherwise, we just reset the options... |
|
else $( this ).data( 'Jcrop' ).setOptions( options ); |
|
} |
|
// If we haven't been attached, preload and attach |
|
else |
|
{ |
|
if ( this.tagName == 'IMG' ) |
|
$.Jcrop.Loader( this, function () |
|
{ |
|
$( this ).css( |
|
{ |
|
display: 'block', |
|
visibility: 'hidden' |
|
} ); |
|
api = $.Jcrop( this, options ); |
|
if ( $.isFunction( callback ) ) callback.call( api ); |
|
} ); |
|
else |
|
{ |
|
$( this ).css( |
|
{ |
|
display: 'block', |
|
visibility: 'hidden' |
|
} ); |
|
api = $.Jcrop( this, options ); |
|
if ( $.isFunction( callback ) ) callback.call( api ); |
|
} |
|
} |
|
} ); |
|
|
|
// Return "this" so the object is chainable (jQuery-style) |
|
return this; |
|
}; |
|
//}}} |
|
// $.Jcrop.Loader - basic image loader {{{ |
|
|
|
$.Jcrop.Loader = function ( imgobj, success, error ) |
|
{ |
|
var $img = $( imgobj ), |
|
img = $img[ 0 ]; |
|
|
|
function completeCheck() |
|
{ |
|
if ( img.complete ) |
|
{ |
|
$img.unbind( '.jcloader' ); |
|
if ( $.isFunction( success ) ) success.call( img ); |
|
} |
|
else window.setTimeout( completeCheck, 50 ); |
|
} |
|
|
|
$img |
|
.bind( 'load.jcloader', completeCheck ) |
|
.bind( 'error.jcloader', function ( e ) |
|
{ |
|
$img.unbind( '.jcloader' ); |
|
if ( $.isFunction( error ) ) error.call( img ); |
|
} ); |
|
|
|
if ( img.complete && $.isFunction( success ) ) |
|
{ |
|
$img.unbind( '.jcloader' ); |
|
success.call( img ); |
|
} |
|
}; |
|
|
|
//}}} |
|
// Global Defaults {{{ |
|
$.Jcrop.defaults = { |
|
|
|
// Basic Settings |
|
allowSelect: true, |
|
allowMove: true, |
|
allowResize: true, |
|
|
|
trackDocument: true, |
|
|
|
// Styling Options |
|
baseClass: 'jcrop', |
|
addClass: null, |
|
bgColor: 'black', |
|
bgOpacity: 0.6, |
|
bgFade: false, |
|
borderOpacity: 0.4, |
|
handleOpacity: 0.5, |
|
handleSize: null, |
|
|
|
aspectRatio: 0, |
|
keySupport: true, |
|
createHandles: [ 'n', 's', 'e', 'w', 'nw', 'ne', 'se', 'sw' ], |
|
createDragbars: [ 'n', 's', 'e', 'w' ], |
|
createBorders: [ 'n', 's', 'e', 'w' ], |
|
drawBorders: true, |
|
dragEdges: true, |
|
fixedSupport: true, |
|
touchSupport: null, |
|
|
|
shade: null, |
|
|
|
boxWidth: 0, |
|
boxHeight: 0, |
|
boundary: 2, |
|
fadeTime: 400, |
|
animationDelay: 20, |
|
swingSpeed: 3, |
|
|
|
minSelect: [ 0, 0 ], |
|
maxSize: [ 0, 0 ], |
|
minSize: [ 0, 0 ], |
|
|
|
// Callbacks / Event Handlers |
|
onChange: function () {}, |
|
onSelect: function () {}, |
|
onDblClick: function () {}, |
|
onRelease: function () {} |
|
}; |
|
|
|
// }}} |
|
}( jQuery ) ); |