diff options
| author | spider@dev <spiderr@bitweaver.org> | 2016-07-23 17:33:04 -0400 |
|---|---|---|
| committer | spider@dev <spiderr@bitweaver.org> | 2016-07-23 17:33:04 -0400 |
| commit | f63fbefabdd884bac1095cde5ca1291a11696af8 (patch) | |
| tree | fabdcde7eb6d80f3254daf448057336520532427 | |
| parent | 1468e29c86adc9948ebecbb928adfe8cf8f36ba8 (diff) | |
| download | util-f63fbefabdd884bac1095cde5ca1291a11696af8.tar.gz util-f63fbefabdd884bac1095cde5ca1291a11696af8.tar.bz2 util-f63fbefabdd884bac1095cde5ca1291a11696af8.zip | |
update cropper from v0.7.9 to v1.0.0
| -rw-r--r-- | javascript/jquery/plugins/cropper/cropper.css | 156 | ||||
| -rw-r--r-- | javascript/jquery/plugins/cropper/cropper.js | 2836 | ||||
| -rw-r--r-- | javascript/jquery/plugins/cropper/cropper.min.css | 10 | ||||
| -rw-r--r-- | javascript/jquery/plugins/cropper/cropper.min.js | 9 |
4 files changed, 1951 insertions, 1060 deletions
diff --git a/javascript/jquery/plugins/cropper/cropper.css b/javascript/jquery/plugins/cropper/cropper.css index 9677011..6df89f1 100644 --- a/javascript/jquery/plugins/cropper/cropper.css +++ b/javascript/jquery/plugins/cropper/cropper.css @@ -1,34 +1,44 @@ /*! - * Cropper v0.7.9 + * Cropper v1.0.0 * https://github.com/fengyuanchen/cropper * - * Copyright 2014-2015 Fengyuan Chen + * Copyright (c) 2014-2015 Fengyuan Chen and contributors * Released under the MIT license + * + * Date: 2015-10-10T02:10:06.999Z */ - .cropper-container { position: relative; overflow: hidden; + font-size: 0; + line-height: 0; + -ms-touch-action: none; + touch-action: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; + direction: ltr !important; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } - .cropper-container img { + display: block; width: 100%; min-width: 0 !important; max-width: none !important; - height: 100%; + height: 100%; min-height: 0 !important; max-height: none !important; + + image-orientation: 0deg !important; } -.cropper-modal, -.cropper-canvas { +.cropper-canvas, +.cropper-drag-box, +.cropper-crop-box, +.cropper-modal { position: absolute; top: 0; right: 0; @@ -36,63 +46,81 @@ left: 0; } -.cropper-canvas { +.cropper-drag-box { background-color: #fff; - filter: alpha(opacity=0); + filter: alpha(opacity=0); opacity: 0; } .cropper-modal { background-color: #000; - filter: alpha(opacity=50); + filter: alpha(opacity=50); opacity: .5; } -.cropper-dragger { - position: absolute; - top: 10%; - left: 10%; - width: 80%; - height: 80%; -} - -.cropper-viewer { +.cropper-view-box { display: block; width: 100%; - height: 100%; + height: 100%; overflow: hidden; - outline-width: 1px; - outline-style: solid; - outline-color: #69f; - outline-color: rgba(51, 102, 255, .75); + outline: 1px solid #39f; + outline-color: rgba(51, 153, 255, .75); } .cropper-dashed { position: absolute; display: block; - filter: alpha(opacity=50); - border: 0 dashed #fff; + filter: alpha(opacity=50); + border: 0 dashed #eee; opacity: .5; } - .cropper-dashed.dashed-h { - top: 33.3%; + top: 33.33333%; left: 0; width: 100%; - height: 33.3%; + height: 33.33333%; border-top-width: 1px; border-bottom-width: 1px; } - .cropper-dashed.dashed-v { top: 0; - left: 33.3%; - width: 33.3%; - height: 100%; + left: 33.33333%; + width: 33.33333%; + height: 100%; border-right-width: 1px; border-left-width: 1px; } +.cropper-center { + position: absolute; + top: 50%; + left: 50%; + display: block; + width: 0; + height: 0; + filter: alpha(opacity=75); + opacity: .75; +} +.cropper-center:before, + .cropper-center:after { + position: absolute; + display: block; + content: " "; + background-color: #eee; +} +.cropper-center:before { + top: 0; + left: -3px; + width: 7px; + height: 1px; +} +.cropper-center:after { + top: -3px; + left: 0; + width: 1px; + height: 7px; +} + .cropper-face, .cropper-line, .cropper-point { @@ -100,42 +128,37 @@ display: block; width: 100%; height: 100%; - filter: alpha(opacity=10); + filter: alpha(opacity=10); opacity: .1; } .cropper-face { top: 0; left: 0; - cursor: move; background-color: #fff; } .cropper-line { - background-color: #69f; + background-color: #39f; } - .cropper-line.line-e { top: 0; right: -3px; width: 5px; cursor: e-resize; } - .cropper-line.line-n { top: -3px; left: 0; height: 5px; cursor: n-resize; } - .cropper-line.line-w { top: 0; left: -3px; width: 5px; cursor: w-resize; } - .cropper-line.line-s { bottom: -3px; left: 0; @@ -146,67 +169,58 @@ .cropper-point { width: 5px; height: 5px; - background-color: #69f; - filter: alpha(opacity=75); + background-color: #39f; + filter: alpha(opacity=75); opacity: .75; } - .cropper-point.point-e { top: 50%; right: -3px; margin-top: -3px; cursor: e-resize; } - .cropper-point.point-n { top: -3px; left: 50%; margin-left: -3px; cursor: n-resize; } - .cropper-point.point-w { top: 50%; left: -3px; margin-top: -3px; cursor: w-resize; } - .cropper-point.point-s { bottom: -3px; left: 50%; margin-left: -3px; cursor: s-resize; } - .cropper-point.point-ne { top: -3px; right: -3px; cursor: ne-resize; } - .cropper-point.point-nw { top: -3px; left: -3px; cursor: nw-resize; } - .cropper-point.point-sw { bottom: -3px; left: -3px; cursor: sw-resize; } - .cropper-point.point-se { right: -3px; bottom: -3px; width: 20px; height: 20px; cursor: se-resize; - filter: alpha(opacity=100); + filter: alpha(opacity=100); opacity: 1; } - .cropper-point.point-se:before { position: absolute; right: -50%; @@ -215,53 +229,51 @@ width: 200%; height: 200%; content: " "; - background-color: #69f; - filter: alpha(opacity=0); + background-color: #39f; + filter: alpha(opacity=0); opacity: 0; } - @media (min-width: 768px) { .cropper-point.point-se { width: 15px; height: 15px; } } - @media (min-width: 992px) { .cropper-point.point-se { width: 10px; height: 10px; } } - @media (min-width: 1200px) { .cropper-point.point-se { width: 5px; height: 5px; - filter: alpha(opacity=75); + filter: alpha(opacity=75); opacity: .75; } } -/* Helper classes for JavaScript */ - -.cropper-hidden { - display: none !important; +.cropper-bg { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC"); } .cropper-invisible { - position: fixed; - top: 0; - left: 0; - z-index: -1; - width: auto !important; - max-width: none !important; - height: auto !important; - max-height: none !important; - filter: alpha(opacity=0); + filter: alpha(opacity=0); opacity: 0; } +.cropper-hide { + position: absolute; + display: block; + width: 0; + height: 0; +} + +.cropper-hidden { + display: none !important; +} + .cropper-move { cursor: move; } @@ -270,7 +282,7 @@ cursor: crosshair; } -.cropper-disabled .cropper-canvas, +.cropper-disabled .cropper-drag-box, .cropper-disabled .cropper-face, .cropper-disabled .cropper-line, .cropper-disabled .cropper-point { diff --git a/javascript/jquery/plugins/cropper/cropper.js b/javascript/jquery/plugins/cropper/cropper.js index 8c416a3..124fc63 100644 --- a/javascript/jquery/plugins/cropper/cropper.js +++ b/javascript/jquery/plugins/cropper/cropper.js @@ -1,995 +1,1130 @@ /*! - * Cropper v0.7.9 + * Cropper v1.0.0 * https://github.com/fengyuanchen/cropper * - * Copyright 2014-2015 Fengyuan Chen + * Copyright (c) 2014-2015 Fengyuan Chen and contributors * Released under the MIT license + * + * Date: 2015-10-10T02:10:08.624Z */ (function (factory) { - if (typeof define === "function" && define.amd) { + if (typeof define === 'function' && define.amd) { // AMD. Register as anonymous module. - define(["jquery"], factory); - } else if (typeof exports === "object") { + define(['jquery'], factory); + } else if (typeof exports === 'object') { // Node / CommonJS - factory(require("jquery")); + factory(require('jquery')); } else { // Browser globals. factory(jQuery); } })(function ($) { - "use strict"; + 'use strict'; - var $window = $(window), - $document = $(document), - location = window.location, + // Globals + var $window = $(window); + var $document = $(document); + var location = window.location; - // Constants - TRUE = true, - FALSE = false, - NULL = null, - NAN = NaN, - INFINITY = Infinity, - STRING_UNDEFINED = "undefined", - STRING_DIRECTIVE = "directive", - CROPPER_NAMESPACE = ".cropper", + // Constants + var NAMESPACE = 'cropper'; - // RegExps - REGEXP_DIRECTIVES = /^(e|n|w|s|ne|nw|sw|se|all|crop|move|zoom)$/, - REGEXP_OPTIONS = /^(x|y|width|height)$/, - REGEXP_PROPERTIES = /^(naturalWidth|naturalHeight|width|height|aspectRatio|ratio|rotate)$/, + // Classes + var CLASS_MODAL = 'cropper-modal'; + var CLASS_HIDE = 'cropper-hide'; + var CLASS_HIDDEN = 'cropper-hidden'; + var CLASS_INVISIBLE = 'cropper-invisible'; + var CLASS_MOVE = 'cropper-move'; + var CLASS_CROP = 'cropper-crop'; + var CLASS_DISABLED = 'cropper-disabled'; + var CLASS_BG = 'cropper-bg'; - // Classes - CLASS_MODAL = "cropper-modal", - CLASS_HIDDEN = "cropper-hidden", - CLASS_INVISIBLE = "cropper-invisible", - CLASS_MOVE = "cropper-move", - CLASS_CROP = "cropper-crop", - CLASS_DISABLED = "cropper-disabled", + // Events + var EVENT_MOUSE_DOWN = 'mousedown touchstart pointerdown MSPointerDown'; + var EVENT_MOUSE_MOVE = 'mousemove touchmove pointermove MSPointerMove'; + var EVENT_MOUSE_UP = 'mouseup touchend touchcancel pointerup pointercancel MSPointerUp MSPointerCancel'; + var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll'; + var EVENT_DBLCLICK = 'dblclick'; + var EVENT_LOAD = 'load.' + NAMESPACE; + var EVENT_ERROR = 'error.' + NAMESPACE; + var EVENT_RESIZE = 'resize.' + NAMESPACE; // Bind to window with namespace + var EVENT_BUILD = 'build.' + NAMESPACE; + var EVENT_BUILT = 'built.' + NAMESPACE; + var EVENT_CROP_START = 'cropstart.' + NAMESPACE; + var EVENT_CROP_MOVE = 'cropmove.' + NAMESPACE; + var EVENT_CROP_END = 'cropend.' + NAMESPACE; + var EVENT_CROP = 'crop.' + NAMESPACE; + var EVENT_ZOOM = 'zoom.' + NAMESPACE; - // Events - EVENT_MOUSE_DOWN = "mousedown touchstart", - EVENT_MOUSE_MOVE = "mousemove touchmove", - EVENT_MOUSE_UP = "mouseup mouseleave touchend touchleave touchcancel", - EVENT_WHEEL = "wheel mousewheel DOMMouseScroll", - EVENT_RESIZE = "resize" + CROPPER_NAMESPACE, // Bind to window with namespace - EVENT_DBLCLICK = "dblclick", - EVENT_BUILD = "build" + CROPPER_NAMESPACE, - EVENT_BUILT = "built" + CROPPER_NAMESPACE, - EVENT_DRAG_START = "dragstart" + CROPPER_NAMESPACE, - EVENT_DRAG_MOVE = "dragmove" + CROPPER_NAMESPACE, - EVENT_DRAG_END = "dragend" + CROPPER_NAMESPACE, + // RegExps + var REGEXP_ACTIONS = /^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/; - // Functions - isNumber = function (n) { - return typeof n === "number"; - }, + // Data keys + var DATA_PREVIEW = 'preview'; + var DATA_ACTION = 'action'; - toArray = function (obj, offset) { - var args = []; + // Actions + var ACTION_EAST = 'e'; + var ACTION_WEST = 'w'; + var ACTION_SOUTH = 's'; + var ACTION_NORTH = 'n'; + var ACTION_SOUTH_EAST = 'se'; + var ACTION_SOUTH_WEST = 'sw'; + var ACTION_NORTH_EAST = 'ne'; + var ACTION_NORTH_WEST = 'nw'; + var ACTION_ALL = 'all'; + var ACTION_CROP = 'crop'; + var ACTION_MOVE = 'move'; + var ACTION_ZOOM = 'zoom'; + var ACTION_NONE = 'none'; - if (isNumber(offset)) { // It's necessary for IE8 - args.push(offset); - } + // Supports + var SUPPORT_CANVAS = $.isFunction($('<canvas>')[0].getContext); - return args.slice.apply(obj, args); - }, + // Maths + var sqrt = Math.sqrt; + var min = Math.min; + var max = Math.max; + var abs = Math.abs; + var sin = Math.sin; + var cos = Math.cos; + var num = parseFloat; - // Custom proxy to avoid jQuery's guid - proxy = function (fn, context) { - var args = toArray(arguments, 2); + // Prototype + var prototype = { + version: '1.0.0' + }; - return function () { - return fn.apply(context, args.concat(toArray(arguments))); - }; - }, + function isNumber(n) { + return typeof n === 'number' && !isNaN(n); + } - addTimestamp = function (url) { - var timestamp = "timestamp=" + (new Date()).getTime(); + function isUndefined(n) { + return typeof n === 'undefined'; + } - return (url + (url.indexOf("?") === -1 ? "?" : "&") + timestamp); - }, + function toArray(obj, offset) { + var args = []; - // Constructor - Cropper = function (element, options) { - this.element = element; - this.$element = $(element); - this.defaults = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) ? options : {}); - this.$original = NULL; - this.ready = FALSE; - this.built = FALSE; - this.cropped = FALSE; - this.rotated = FALSE; - this.disabled = FALSE; - this.replaced = FALSE; - this.init(); - }, + // This is necessary for IE8 + if (isNumber(offset)) { + args.push(offset); + } - // Others - sqrt = Math.sqrt, - min = Math.min, - max = Math.max, - abs = Math.abs, - sin = Math.sin, - cos = Math.cos, - num = parseFloat; + return args.slice.apply(obj, args); + } - Cropper.prototype = { - constructor: Cropper, + // Custom proxy to avoid jQuery's guid + function proxy(fn, context) { + var args = toArray(arguments, 2); - support: { - canvas: $.isFunction($("<canvas>")[0].getContext) - }, + return function () { + return fn.apply(context, args.concat(toArray(arguments))); + }; + } - init: function () { - var defaults = this.defaults; + function isCrossOriginURL(url) { + var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i); - $.each(defaults, function (i, n) { - switch (i) { - case "aspectRatio": - defaults[i] = abs(num(n)) || NAN; // 0 -> NaN - break; + return parts && ( + parts[1] !== location.protocol || + parts[2] !== location.hostname || + parts[3] !== location.port + ); + } - case "autoCropArea": - defaults[i] = abs(num(n)) || 0.8; // 0 | NaN -> 0.8 - break; + function addTimestamp(url) { + var timestamp = 'timestamp=' + (new Date()).getTime(); - case "minWidth": - case "minHeight": - defaults[i] = abs(num(n)) || 0; // NaN -> 0 - break; + return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp); + } - case "maxWidth": - case "maxHeight": - defaults[i] = abs(num(n)) || INFINITY; // 0 | NaN -> Infinity - break; + function getCrossOrigin(crossOrigin) { + return crossOrigin ? ' crossOrigin="' + crossOrigin + '"' : ''; + } - // No default - } - }); + function getImageSize(image, callback) { + var newImage; - // Set default image data - this.image = { - rotate: 0 - }; + // Modern browsers + if (image.naturalWidth) { + return callback(image.naturalWidth, image.naturalHeight); + } - this.load(); - }, + // IE8: Don't use `new Image()` here (#319) + newImage = document.createElement('img'); - load: function () { - var _this = this, - $this = this.$element, - element = this.element, - image = this.image, - crossOrigin = "", - $clone, - url; + newImage.onload = function () { + callback(this.width, this.height); + }; - if ($this.is("img")) { - url = $this.prop("src"); - } else if ($this.is("canvas") && this.support.canvas) { - url = element.toDataURL(); - } + newImage.src = image.src; + } - if (!url) { - return; - } + function getTransform(options) { + var transforms = []; + var rotate = options.rotate; + var scaleX = options.scaleX; + var scaleY = options.scaleY; - // Reset image rotate degree - if (this.replaced) { - image.rotate = 0; - } + if (isNumber(rotate)) { + transforms.push('rotate(' + rotate + 'deg)'); + } - if (this.defaults.checkImageOrigin && this.isCrossOriginURL(url)) { - crossOrigin = " crossOrigin"; - url = addTimestamp(url); // Bust cache (#119, #148) - } + if (isNumber(scaleX) && isNumber(scaleY)) { + transforms.push('scale(' + scaleX + ',' + scaleY + ')'); + } - this.$clone = ($clone = $("<img" + crossOrigin + ' src="' + url + '">')); + return transforms.length ? transforms.join(' ') : 'none'; + } - $clone.one("load", function () { - image.naturalWidth = this.naturalWidth || $clone.width(); - image.naturalHeight = this.naturalHeight || $clone.height(); - image.aspectRatio = image.naturalWidth / image.naturalHeight; + function getRotatedSizes(data, reverse) { + var deg = abs(data.degree) % 180; + var arc = (deg > 90 ? (180 - deg) : deg) * Math.PI / 180; + var sinArc = sin(arc); + var cosArc = cos(arc); + var width = data.width; + var height = data.height; + var aspectRatio = data.aspectRatio; + var newWidth; + var newHeight; - _this.url = url; - _this.ready = TRUE; - _this.build(); - }); + if (!reverse) { + newWidth = width * cosArc + height * sinArc; + newHeight = width * sinArc + height * cosArc; + } else { + newWidth = width / (cosArc + sinArc / aspectRatio); + newHeight = newWidth / aspectRatio; + } - // Hide and prepend the clone iamge to the document body (Don't append to). - $clone.addClass(CLASS_INVISIBLE).prependTo("body"); - }, + return { + width: newWidth, + height: newHeight + }; + } - isCrossOriginURL: function (url) { - var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i); + function getSourceCanvas(image, data) { + var canvas = $('<canvas>')[0]; + var context = canvas.getContext('2d'); + var x = 0; + var y = 0; + var width = data.naturalWidth; + var height = data.naturalHeight; + var rotate = data.rotate; + var scaleX = data.scaleX; + var scaleY = data.scaleY; + var scalable = isNumber(scaleX) && isNumber(scaleY) && (scaleX !== 1 || scaleY !== 1); + var rotatable = isNumber(rotate) && rotate !== 0; + var advanced = rotatable || scalable; + var canvasWidth = width; + var canvasHeight = height; + var translateX; + var translateY; + var rotated; - if (parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port)) { - return TRUE; - } + if (scalable) { + translateX = width / 2; + translateY = height / 2; + } - return FALSE; - }, + if (rotatable) { + rotated = getRotatedSizes({ + width: width, + height: height, + degree: rotate + }); - build: function () { - var $this = this.$element, - defaults = this.defaults, - buildEvent, - $cropper; + canvasWidth = rotated.width; + canvasHeight = rotated.height; + translateX = rotated.width / 2; + translateY = rotated.height / 2; + } - if (!this.ready) { - return; - } + canvas.width = canvasWidth; + canvas.height = canvasHeight; - if (this.built) { - this.unbuild(); - } + if (advanced) { + x = -width / 2; + y = -height / 2; - $this.one(EVENT_BUILD, defaults.build); // Only trigger once - buildEvent = $.Event(EVENT_BUILD); - $this.trigger(buildEvent); + context.save(); + context.translate(translateX, translateY); + } - if (buildEvent.isDefaultPrevented()) { - return; - } + if (rotatable) { + context.rotate(rotate * Math.PI / 180); + } - // Create cropper elements - this.$cropper = ($cropper = $(Cropper.TEMPLATE)); + // Should call `scale` after rotated + if (scalable) { + context.scale(scaleX, scaleY); + } - // Hide the original image - $this.addClass(CLASS_HIDDEN); + context.drawImage(image, x, y, width, height); + + if (advanced) { + context.restore(); + } + + return canvas; + } - // Show and prepend the clone iamge to the cropper - this.$clone.removeClass(CLASS_INVISIBLE).prependTo($cropper); + function Cropper(element, options) { + this.$element = $(element); + this.options = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) && options); + this.ready = false; + this.built = false; + this.complete = false; + this.rotated = false; + this.cropped = false; + this.disabled = false; + this.replaced = false; + this.isImg = false; + this.originalUrl = ''; + this.crossOrigin = ''; + this.canvas = null; + this.cropBox = null; + this.init(); + } - // Save original image for rotation - if (!this.rotated) { - this.$original = this.$clone.clone(); + $.extend(prototype, { + init: function () { + var $this = this.$element; + var url; - // Append the image to document to avoid "NS_ERROR_NOT_AVAILABLE" error on Firefox when call the "drawImage" method. - this.$original.addClass(CLASS_HIDDEN).prependTo(this.$cropper); + if ($this.is('img')) { + this.isImg = true; - this.originalImage = $.extend({}, this.image); - } + // Should use `$.fn.attr` here. e.g.: "img/picture.jpg" + this.originalUrl = url = $this.attr('src'); - this.$container = $this.parent(); - this.$container.append($cropper); + // Stop when it's a blank image + if (!url) { + return; + } - this.$canvas = $cropper.find(".cropper-canvas"); - this.$dragger = $cropper.find(".cropper-dragger"); - this.$viewer = $cropper.find(".cropper-viewer"); + // Should use `$.fn.prop` here. e.g.: "http://example.com/img/picture.jpg" + url = $this.prop('src'); + } else if ($this.is('canvas') && SUPPORT_CANVAS) { + url = $this[0].toDataURL(); + } - defaults.autoCrop ? (this.cropped = TRUE) : this.$dragger.addClass(CLASS_HIDDEN); - defaults.modal && this.$canvas.addClass(CLASS_MODAL); - !defaults.dashed && this.$dragger.find(".cropper-dashed").addClass(CLASS_HIDDEN); - !defaults.movable && this.$dragger.find(".cropper-face").data(STRING_DIRECTIVE, "move"); - !defaults.resizable && this.$dragger.find(".cropper-line, .cropper-point").addClass(CLASS_HIDDEN); + this.load(url); + }, - this.addListeners(); - this.initPreview(); + // A shortcut for triggering custom events + trigger: function (type, data) { + var e = $.Event(type, data); - this.built = TRUE; // Set `true` before update - defaults.dragCrop && this.setDragMode("crop"); // Set after built - this.update(); - this.replaced = FALSE; // Reset to `false` after update + this.$element.trigger(e); - $this.one(EVENT_BUILT, defaults.built); // Only trigger once - $this.trigger(EVENT_BUILT); + return e; }, - unbuild: function () { - if (!this.built) { + load: function (url) { + var options = this.options; + var $this = this.$element; + var crossOrigin = ''; + var bustCacheUrl; + var $clone; + + if (!url) { return; } - this.built = FALSE; - this.removeListeners(); + this.url = url; - this.$preview.empty(); - this.$preview = NULL; + // Trigger build event first + $this.one(EVENT_BUILD, options.build); - this.$dragger = NULL; - this.$canvas = NULL; - this.$container = NULL; + if (this.trigger(EVENT_BUILD).isDefaultPrevented()) { + return; + } - this.$cropper.remove(); - this.$cropper = NULL; - }, + if (options.checkImageOrigin && isCrossOriginURL(url)) { + crossOrigin = $this.prop('crossOrigin'); - update: function (data) { - this.initContainer(); - this.initCropper(); - this.initImage(); - this.initDragger(); + // Bust cache (#148), only when there was not a "crossOrigin" property + if (!crossOrigin) { + crossOrigin = 'anonymous'; + bustCacheUrl = addTimestamp(url); + } + + this.crossOrigin = crossOrigin; + } - if (data) { - this.setData(data, TRUE); - this.setDragMode("crop"); + this.$clone = $clone = $('<img' + getCrossOrigin(crossOrigin) + ' src="' + (bustCacheUrl || url) + '">'); + + if (this.isImg) { + if ($this[0].complete) { + this.start(); + } else { + $this.one(EVENT_LOAD, $.proxy(this.start, this)); + } } else { - this.setData(this.defaults.data); + $clone. + one(EVENT_LOAD, $.proxy(this.start, this)). + one(EVENT_ERROR, $.proxy(this.stop, this)). + addClass(CLASS_HIDE). + insertAfter($this); } }, - resize: function () { - clearTimeout(this.resizing); - this.resizing = setTimeout($.proxy(this.update, this, this.getData()), 200); - }, + start: function () { + var $image = this.$element; + var $clone = this.$clone; - preview: function () { - var image = this.image, - dragger = this.dragger, - width = image.width, - height = image.height, - left = dragger.left - image.left, - top = dragger.top - image.top; + if (!this.isImg) { + $clone.off(EVENT_ERROR, this.stop); + $image = $clone; + } - this.$viewer.find("img").css({ - width: width, - height: height, - marginLeft: -left, - marginTop: -top - }); + getImageSize($image[0], $.proxy(function (naturalWidth, naturalHeight) { + this.image = { + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + aspectRatio: naturalWidth / naturalHeight + }; - this.$preview.each(function () { - var $this = $(this), - data = $this.data(), - ratio = data.width / dragger.width, - newWidth = data.width, - newHeight = dragger.height * ratio; + this.ready = true; + this.build(); + }, this)); + }, - if (newHeight > data.height) { - ratio = data.height / dragger.height, - newWidth = dragger.width * ratio; - newHeight = data.height; - } + stop: function () { + this.$clone.remove(); + this.$clone = null; + } + }); - $this.width(newWidth).height(newHeight).find("img").css({ - width: width * ratio, - height: height * ratio, - marginLeft: -left * ratio, - marginTop: -top * ratio - }); - }); - }, + $.extend(prototype, { + build: function () { + var options = this.options; + var $this = this.$element; + var $clone = this.$clone; + var $cropper; + var $cropBox; + var $face; - addListeners: function () { - var defaults = this.defaults; + if (!this.ready) { + return; + } - this.$element.on(EVENT_DRAG_START, defaults.dragstart).on(EVENT_DRAG_MOVE, defaults.dragmove).on(EVENT_DRAG_END, defaults.dragend); - this.$cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.dragstart, this)).on(EVENT_DBLCLICK, $.proxy(this.dblclick, this)); + // Unbuild first when replace + if (this.built) { + this.unbuild(); + } + + // Create cropper elements + this.$container = $this.parent(); + this.$cropper = $cropper = $(Cropper.TEMPLATE); + this.$canvas = $cropper.find('.cropper-canvas').append($clone); + this.$dragBox = $cropper.find('.cropper-drag-box'); + this.$cropBox = $cropBox = $cropper.find('.cropper-crop-box'); + this.$viewBox = $cropper.find('.cropper-view-box'); + this.$face = $face = $cropBox.find('.cropper-face'); + + // Hide the original image + $this.addClass(CLASS_HIDDEN).after($cropper); - if (defaults.zoomable) { - this.$cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this)); + // Show the clone image if is hidden + if (!this.isImg) { + $clone.removeClass(CLASS_HIDE); } - if (defaults.multiple) { - this.$cropper.on(EVENT_MOUSE_MOVE, $.proxy(this.dragmove, this)).on(EVENT_MOUSE_UP, $.proxy(this.dragend, this)); + this.initPreview(); + this.bind(); + + // Format aspect ratio (0 -> NaN) + options.aspectRatio = num(options.aspectRatio) || NaN; + + if (options.autoCrop) { + this.cropped = true; + + if (options.modal) { + this.$dragBox.addClass(CLASS_MODAL); + } } else { - $document.on(EVENT_MOUSE_MOVE, (this._dragmove = proxy(this.dragmove, this))).on(EVENT_MOUSE_UP, (this._dragend = proxy(this.dragend, this))); + $cropBox.addClass(CLASS_HIDDEN); } - $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this))); - }, + if (!options.guides) { + $cropBox.find('.cropper-dashed').addClass(CLASS_HIDDEN); + } - removeListeners: function () { - var defaults = this.defaults; + if (!options.center) { + $cropBox.find('.cropper-center').addClass(CLASS_HIDDEN); + } - this.$element.off(EVENT_DRAG_START, defaults.dragstart).off(EVENT_DRAG_MOVE, defaults.dragmove).off(EVENT_DRAG_END, defaults.dragend); - this.$cropper.off(EVENT_MOUSE_DOWN, this.dragstart).off(EVENT_DBLCLICK, this.dblclick); + if (options.cropBoxMovable) { + $face.addClass(CLASS_MOVE).data(DATA_ACTION, ACTION_ALL); + } - if (defaults.zoomable) { - this.$cropper.off(EVENT_WHEEL, this.wheel); + if (!options.highlight) { + $face.addClass(CLASS_INVISIBLE); } - if (defaults.multiple) { - this.$cropper.off(EVENT_MOUSE_MOVE, this.dragmove).off(EVENT_MOUSE_UP, this.dragend); - } else { - $document.off(EVENT_MOUSE_MOVE, this._dragmove).off(EVENT_MOUSE_UP, this._dragend); + if (options.background) { + $cropper.addClass(CLASS_BG); } - $window.off(EVENT_RESIZE, this._resize); + if (!options.cropBoxResizable) { + $cropBox.find('.cropper-line, .cropper-point').addClass(CLASS_HIDDEN); + } + + this.setDragMode(options.dragCrop ? ACTION_CROP : (options.movable ? ACTION_MOVE : ACTION_NONE)); + + this.render(); + this.built = true; + this.setData(options.data); + $this.one(EVENT_BUILT, options.built); + + // Trigger the built event asynchronously to keep `data('cropper')` is defined + setTimeout($.proxy(function () { + this.trigger(EVENT_BUILT); + this.complete = true; + }, this), 0); }, - initPreview: function () { - var url = this.url; + unbuild: function () { + if (!this.built) { + return; + } - this.$preview = $(this.defaults.preview); - this.$viewer.html('<img src="' + url + '">'); + this.built = false; + this.initialImage = null; - this.$preview.each(function () { - var $this = $(this); + // Clear `initialCanvas` is necessary when replace + this.initialCanvas = null; + this.initialCropBox = null; + this.container = null; + this.canvas = null; - $this.data({ - width: $this.width(), - height: $this.height() - }).html('<img src="' + url + '" style="display:block;width:100%;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;">'); - }); + // Clear `cropBox` is necessary when replace + this.cropBox = null; + this.unbind(); + + this.resetPreview(); + this.$preview = null; + + this.$viewBox = null; + this.$cropBox = null; + this.$dragBox = null; + this.$canvas = null; + this.$container = null; + + this.$cropper.remove(); + this.$cropper = null; + } + }); + + $.extend(prototype, { + render: function () { + this.initContainer(); + this.initCanvas(); + this.initCropBox(); + + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } }, initContainer: function () { - var $this = this.$element, - $container = this.$container, - $cropper = this.$cropper, - defaults = this.defaults; + var options = this.options; + var $this = this.$element; + var $container = this.$container; + var $cropper = this.$cropper; $cropper.addClass(CLASS_HIDDEN); $this.removeClass(CLASS_HIDDEN); - this.container = { - width: max($container.width(), defaults.minContainerWidth), - height: max($container.height(), defaults.minContainerHeight) - }; + $cropper.css((this.container = { + width: max($container.width(), num(options.minContainerWidth) || 200), + height: max($container.height(), num(options.minContainerHeight) || 100) + })); $this.addClass(CLASS_HIDDEN); $cropper.removeClass(CLASS_HIDDEN); }, - initCropper: function () { - var container = this.container, - image = this.image, - cropper; - - if (((image.naturalWidth * container.height / image.naturalHeight) - container.width) >= 0) { - cropper = { - width: container.width, - height: container.width / image.aspectRatio, - left: 0 - }; + // Canvas (image wrapper) + initCanvas: function () { + var container = this.container; + var containerWidth = container.width; + var containerHeight = container.height; + var image = this.image; + var aspectRatio = image.aspectRatio; + var canvas = { + aspectRatio: aspectRatio, + width: containerWidth, + height: containerHeight + }; - cropper.top = (container.height - cropper.height) / 2; + if (containerHeight * aspectRatio > containerWidth) { + canvas.height = containerWidth / aspectRatio; } else { - cropper = { - width: container.height * image.aspectRatio, - height: container.height, - top: 0 - }; - - cropper.left = (container.width - cropper.width) / 2; + canvas.width = containerHeight * aspectRatio; } - this.$cropper.css({ - width: cropper.width, - height: cropper.height, - left: cropper.left, - top: cropper.top - }); + canvas.oldLeft = canvas.left = (containerWidth - canvas.width) / 2; + canvas.oldTop = canvas.top = (containerHeight - canvas.height) / 2; - this.cropper = cropper; + this.canvas = canvas; + this.limitCanvas(true, true); + this.initialImage = $.extend({}, image); + this.initialCanvas = $.extend({}, canvas); }, - initImage: function () { - var image = this.image, - cropper = this.cropper, - defaultImage = { - _width: cropper.width, - _height: cropper.height, - width: cropper.width, - height: cropper.height, - left: 0, - top: 0, - ratio: cropper.width / image.naturalWidth - }; + limitCanvas: function (size, position) { + var options = this.options; + var strict = options.strict; + var container = this.container; + var containerWidth = container.width; + var containerHeight = container.height; + var canvas = this.canvas; + var aspectRatio = canvas.aspectRatio; + var cropBox = this.cropBox; + var cropped = this.cropped && cropBox; + var initialCanvas = this.initialCanvas || canvas; + var minCanvasWidth; + var minCanvasHeight; - this.defaultImage = $.extend({}, image, defaultImage); + if (size) { + minCanvasWidth = num(options.minCanvasWidth) || 0; + minCanvasHeight = num(options.minCanvasHeight) || 0; - if (image._width !== cropper.width || image._height !== cropper.height) { - $.extend(image, defaultImage); - } else { - image = $.extend({}, defaultImage, image); + if (strict) { + if (minCanvasWidth) { + minCanvasWidth = max(minCanvasWidth, cropped ? cropBox.width : initialCanvas.width); + } else if (minCanvasHeight) { + minCanvasHeight = max(minCanvasHeight, cropped ? cropBox.height : initialCanvas.height); + } else if (cropped) { + minCanvasWidth = cropBox.width; + minCanvasHeight = cropBox.height; - // Reset image ratio - if (this.replaced) { - image.ratio = defaultImage.ratio; + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } } - } - - this.image = image; - this.renderImage(); - }, - renderImage: function (mode) { - var image = this.image; + if (minCanvasWidth && minCanvasHeight) { + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasHeight = minCanvasWidth / aspectRatio; + } else { + minCanvasWidth = minCanvasHeight * aspectRatio; + } + } else if (minCanvasWidth) { + minCanvasHeight = minCanvasWidth / aspectRatio; + } else if (minCanvasHeight) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } - if (mode === "zoom") { - image.left -= (image.width - image.oldWidth) / 2; - image.top -= (image.height - image.oldHeight) / 2; + canvas.minWidth = minCanvasWidth; + canvas.minHeight = minCanvasHeight; + canvas.maxWidth = Infinity; + canvas.maxHeight = Infinity; } - image.left = min(max(image.left, image._width - image.width), 0); - image.top = min(max(image.top, image._height - image.height), 0); - - this.$clone.css({ - width: image.width, - height: image.height, - marginLeft: image.left, - marginTop: image.top - }); - - if (mode) { - this.defaults.done(this.getData()); - this.preview(); + if (position) { + if (strict) { + canvas.minLeft = cropped ? + min(cropBox.left, (cropBox.left + cropBox.width) - canvas.width) : + min(0, containerWidth - canvas.width); + canvas.minTop = cropped ? + min(cropBox.top, (cropBox.top + cropBox.height) - canvas.height) : + min(0, containerHeight - canvas.height); + canvas.maxLeft = cropped ? cropBox.left : max(0, containerWidth - canvas.width); + canvas.maxTop = cropped ? cropBox.top : max(0, containerHeight - canvas.height); + } else { + canvas.minLeft = -canvas.width; + canvas.minTop = -canvas.height; + canvas.maxLeft = containerWidth; + canvas.maxTop = containerHeight; + } } }, - initDragger: function () { - var defaults = this.defaults, - cropper = this.cropper, - // If not set, use the original aspect ratio of the image. - aspectRatio = defaults.aspectRatio || this.image.aspectRatio, - ratio = this.image.ratio, - autoCropDragger, - dragger; + renderCanvas: function (changed) { + var options = this.options; + var canvas = this.canvas; + var image = this.image; + var aspectRatio; + var rotated; - if (((cropper.height * aspectRatio) - cropper.width) >= 0) { - dragger = { - height: cropper.width / aspectRatio, - width: cropper.width, - left: 0, - top: (cropper.height - (cropper.width / aspectRatio)) / 2, - maxWidth: cropper.width, - maxHeight: cropper.width / aspectRatio - }; - } else { - dragger = { - height: cropper.height, - width: cropper.height * aspectRatio, - left: (cropper.width - (cropper.height * aspectRatio)) / 2, - top: 0, - maxWidth: cropper.height * aspectRatio, - maxHeight: cropper.height - }; - } + if (this.rotated) { + this.rotated = false; - dragger.minWidth = 0; - dragger.minHeight = 0; + // Computes rotated sizes with image sizes + rotated = getRotatedSizes({ + width: image.width, + height: image.height, + degree: image.rotate + }); - if (defaults.aspectRatio) { - if (isFinite(defaults.maxWidth)) { - dragger.maxWidth = min(dragger.maxWidth, defaults.maxWidth * ratio); - dragger.maxHeight = dragger.maxWidth / aspectRatio; - } else if (isFinite(defaults.maxHeight)) { - dragger.maxHeight = min(dragger.maxHeight, defaults.maxHeight * ratio); - dragger.maxWidth = dragger.maxHeight * aspectRatio; - } + aspectRatio = rotated.width / rotated.height; - if (defaults.minWidth > 0) { - dragger.minWidth = max(0, defaults.minWidth * ratio); - dragger.minHeight = dragger.minWidth / aspectRatio; - } else if (defaults.minHeight > 0) { - dragger.minHeight = max(0, defaults.minHeight * ratio); - dragger.minWidth = dragger.minHeight * aspectRatio; + if (aspectRatio !== canvas.aspectRatio) { + canvas.left -= (rotated.width - canvas.width) / 2; + canvas.top -= (rotated.height - canvas.height) / 2; + canvas.width = rotated.width; + canvas.height = rotated.height; + canvas.aspectRatio = aspectRatio; + this.limitCanvas(true, false); } - } else { - dragger.maxWidth = min(dragger.maxWidth, defaults.maxWidth * ratio); - dragger.maxHeight = min(dragger.maxHeight, defaults.maxHeight * ratio); - dragger.minWidth = max(0, defaults.minWidth * ratio); - dragger.minHeight = max(0, defaults.minHeight * ratio); } - // minWidth can't be greater than maxWidth, and minHeight too. - dragger.minWidth = min(dragger.maxWidth, dragger.minWidth); - dragger.minHeight = min(dragger.maxHeight, dragger.minHeight); + if (canvas.width > canvas.maxWidth || canvas.width < canvas.minWidth) { + canvas.left = canvas.oldLeft; + } - // Center the dragger by default - autoCropDragger = $.extend({}, dragger); + if (canvas.height > canvas.maxHeight || canvas.height < canvas.minHeight) { + canvas.top = canvas.oldTop; + } - // The width of auto crop area must large than minWidth, and the height too. (#164) - autoCropDragger.width = max(dragger.minWidth, dragger.width * defaults.autoCropArea); - autoCropDragger.height = max(dragger.minHeight, dragger.height * defaults.autoCropArea); - autoCropDragger.left = (cropper.width - autoCropDragger.width) / 2; - autoCropDragger.top = (cropper.height - autoCropDragger.height) / 2; + canvas.width = min(max(canvas.width, canvas.minWidth), canvas.maxWidth); + canvas.height = min(max(canvas.height, canvas.minHeight), canvas.maxHeight); - autoCropDragger.oldLeft = dragger.oldLeft = dragger.left; - autoCropDragger.oldTop = dragger.oldTop = dragger.top; + this.limitCanvas(false, true); - this.autoCropDragger = autoCropDragger; - this.defaultDragger = $.extend({}, dragger); - this.dragger = dragger; - }, + canvas.oldLeft = canvas.left = min(max(canvas.left, canvas.minLeft), canvas.maxLeft); + canvas.oldTop = canvas.top = min(max(canvas.top, canvas.minTop), canvas.maxTop); - renderDragger: function () { - var dragger = this.dragger, - cropper = this.cropper; + this.$canvas.css({ + width: canvas.width, + height: canvas.height, + left: canvas.left, + top: canvas.top + }); - if (dragger.width > dragger.maxWidth) { - dragger.width = dragger.maxWidth; - dragger.left = dragger.oldLeft; - } else if (dragger.width < dragger.minWidth) { - dragger.width = dragger.minWidth; - dragger.left = dragger.oldLeft; - } + this.renderImage(); - if (dragger.height > dragger.maxHeight) { - dragger.height = dragger.maxHeight; - dragger.top = dragger.oldTop; - } else if (dragger.height < dragger.minHeight) { - dragger.height = dragger.minHeight; - dragger.top = dragger.oldTop; + if (this.cropped && options.strict) { + this.limitCropBox(true, true); } - dragger.left = min(max(dragger.left, 0), cropper.width - dragger.width); - dragger.top = min(max(dragger.top, 0), cropper.height - dragger.height); - dragger.oldLeft = dragger.left; - dragger.oldTop = dragger.top; + if (changed) { + this.output(); + } + }, - // Re-render the dragger - this.dragger = dragger; + renderImage: function (changed) { + var canvas = this.canvas; + var image = this.image; + var reversed; - // #186 - if (this.defaults.movable) { - this.$dragger.find(".cropper-face").data(STRING_DIRECTIVE, (dragger.width === cropper.width && dragger.height === cropper.height) ? "move" : "all"); + if (image.rotate) { + reversed = getRotatedSizes({ + width: canvas.width, + height: canvas.height, + degree: image.rotate, + aspectRatio: image.aspectRatio + }, true); } - if (!this.disabled) { - this.defaults.done(this.getData()); - } + $.extend(image, reversed ? { + width: reversed.width, + height: reversed.height, + left: (canvas.width - reversed.width) / 2, + top: (canvas.height - reversed.height) / 2 + } : { + width: canvas.width, + height: canvas.height, + left: 0, + top: 0 + }); - this.$dragger.css({ - width: dragger.width, - height: dragger.height, - left: dragger.left, - top: dragger.top + this.$clone.css({ + width: image.width, + height: image.height, + marginLeft: image.left, + marginTop: image.top, + transform: getTransform(image) }); - this.preview(); + if (changed) { + this.output(); + } }, - reset: function (deep) { - if (!this.cropped || this.disabled) { - return; - } + initCropBox: function () { + var options = this.options; + var canvas = this.canvas; + var aspectRatio = options.aspectRatio; + var autoCropArea = num(options.autoCropArea) || 0.8; + var cropBox = { + width: canvas.width, + height: canvas.height + }; - if (deep) { - this.defaults.data = {}; + if (aspectRatio) { + if (canvas.height * aspectRatio > canvas.width) { + cropBox.height = cropBox.width / aspectRatio; + } else { + cropBox.width = cropBox.height * aspectRatio; + } } - this.image = $.extend({}, this.defaultImage); - this.renderImage(); - this.dragger = $.extend({}, this.defaultDragger); - this.setData(this.defaults.data); - }, - - clear: function () { - if (!this.cropped || this.disabled) { - return; - } + this.cropBox = cropBox; + this.limitCropBox(true, true); - this.cropped = FALSE; + // Initialize auto crop area + cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth); + cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight); - this.setData({ - x: 0, - y: 0, - width: 0, - height: 0 - }); + // The width of auto crop area must large than "minWidth", and the height too. (#164) + cropBox.width = max(cropBox.minWidth, cropBox.width * autoCropArea); + cropBox.height = max(cropBox.minHeight, cropBox.height * autoCropArea); + cropBox.oldLeft = cropBox.left = canvas.left + (canvas.width - cropBox.width) / 2; + cropBox.oldTop = cropBox.top = canvas.top + (canvas.height - cropBox.height) / 2; - this.$canvas.removeClass(CLASS_MODAL); - this.$dragger.addClass(CLASS_HIDDEN); + this.initialCropBox = $.extend({}, cropBox); }, - destroy: function () { - var $this = this.$element; + limitCropBox: function (size, position) { + var options = this.options; + var strict = options.strict; + var container = this.container; + var containerWidth = container.width; + var containerHeight = container.height; + var canvas = this.canvas; + var cropBox = this.cropBox; + var aspectRatio = options.aspectRatio; + var minCropBoxWidth; + var minCropBoxHeight; + var maxCropBoxWidth; + var maxCropBoxHeight; - if (!this.ready) { - this.$clone.off("load").remove(); - } + if (size) { + minCropBoxWidth = num(options.minCropBoxWidth) || 0; + minCropBoxHeight = num(options.minCropBoxHeight) || 0; - this.unbuild(); - $this.removeClass(CLASS_HIDDEN).removeData("cropper"); + // The min/maxCropBoxWidth/Height must be less than containerWidth/Height + minCropBoxWidth = min(minCropBoxWidth, containerWidth); + minCropBoxHeight = min(minCropBoxHeight, containerHeight); + maxCropBoxWidth = min(containerWidth, strict ? canvas.width : containerWidth); + maxCropBoxHeight = min(containerHeight, strict ? canvas.height : containerHeight); - if (this.rotated) { - $this.attr("src", this.$original.attr("src")); - } - }, - - replace: function (url, /*INTERNAL*/ rotated) { - var _this = this, - $this = this.$element, - element = this.element, - context; + if (aspectRatio) { + if (minCropBoxWidth && minCropBoxHeight) { + if (minCropBoxHeight * aspectRatio > minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + } else if (minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else if (minCropBoxHeight) { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } - if (!this.disabled && url && url !== this.url && url !== $this.attr("src")) { - if (!rotated) { - this.rotated = FALSE; - this.replaced = TRUE; + if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) { + maxCropBoxHeight = maxCropBoxWidth / aspectRatio; + } else { + maxCropBoxWidth = maxCropBoxHeight * aspectRatio; + } } - if ($this.is("img")) { - $this.attr("src", url); - this.load(); - } else if ($this.is("canvas") && this.support.canvas) { - context = element.getContext("2d"); + // The minWidth/Height must be less than maxWidth/Height + cropBox.minWidth = min(minCropBoxWidth, maxCropBoxWidth); + cropBox.minHeight = min(minCropBoxHeight, maxCropBoxHeight); + cropBox.maxWidth = maxCropBoxWidth; + cropBox.maxHeight = maxCropBoxHeight; + } - $('<img src="' + url + '">').one("load", function () { - element.width = this.width; - element.height = this.height; - context.clearRect(0, 0, element.width, element.height); - context.drawImage(this, 0, 0); - _this.load(); - }); + if (position) { + if (strict) { + cropBox.minLeft = max(0, canvas.left); + cropBox.minTop = max(0, canvas.top); + cropBox.maxLeft = min(containerWidth, canvas.left + canvas.width) - cropBox.width; + cropBox.maxTop = min(containerHeight, canvas.top + canvas.height) - cropBox.height; + } else { + cropBox.minLeft = 0; + cropBox.minTop = 0; + cropBox.maxLeft = containerWidth - cropBox.width; + cropBox.maxTop = containerHeight - cropBox.height; } } }, - setData: function (data, /*INTERNAL*/ once) { - var cropper = this.cropper, - dragger = this.dragger, - image = this.image, - aspectRatio = this.defaults.aspectRatio; + renderCropBox: function () { + var options = this.options; + var container = this.container; + var containerWidth = container.width; + var containerHeight = container.height; + var cropBox = this.cropBox; - if (!this.built || this.disabled || typeof data === STRING_UNDEFINED) { - return; + if (cropBox.width > cropBox.maxWidth || cropBox.width < cropBox.minWidth) { + cropBox.left = cropBox.oldLeft; } - if (data === NULL || $.isEmptyObject(data)) { - dragger = $.extend({}, this.autoCropDragger); + if (cropBox.height > cropBox.maxHeight || cropBox.height < cropBox.minHeight) { + cropBox.top = cropBox.oldTop; } - if ($.isPlainObject(data) && !$.isEmptyObject(data)) { + cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth); + cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight); - if (!once) { - this.defaults.data = data; - } + this.limitCropBox(false, true); - data = this.transformData(data); + cropBox.oldLeft = cropBox.left = min(max(cropBox.left, cropBox.minLeft), cropBox.maxLeft); + cropBox.oldTop = cropBox.top = min(max(cropBox.top, cropBox.minTop), cropBox.maxTop); - if (isNumber(data.x) && data.x <= cropper.width - image.left) { - dragger.left = data.x + image.left; - } + if (options.movable && options.cropBoxMovable) { - if (isNumber(data.y) && data.y <= cropper.height - image.top) { - dragger.top = data.y + image.top; - } + // Turn to move the canvas when the crop box is equal to the container + this.$face.data(DATA_ACTION, (cropBox.width === containerWidth && cropBox.height === containerHeight) ? ACTION_MOVE : ACTION_ALL); + } - if (aspectRatio) { - if (isNumber(data.width) && data.width <= dragger.maxWidth && data.width >= dragger.minWidth) { - dragger.width = data.width; - dragger.height = dragger.width / aspectRatio; - } else if (isNumber(data.height) && data.height <= dragger.maxHeight && data.height >= dragger.minHeight) { - dragger.height = data.height; - dragger.width = dragger.height * aspectRatio; - } - } else { - if (isNumber(data.width) && data.width <= dragger.maxWidth && data.width >= dragger.minWidth) { - dragger.width = data.width; - } + this.$cropBox.css({ + width: cropBox.width, + height: cropBox.height, + left: cropBox.left, + top: cropBox.top + }); - if (isNumber(data.height) && data.height <= dragger.maxHeight && data.height >= dragger.minHeight) { - dragger.height = data.height; - } - } + if (this.cropped && options.strict) { + this.limitCanvas(true, true); } - this.dragger = dragger; - this.renderDragger(); + if (!this.disabled) { + this.output(); + } }, - getData: function (rounded) { - var dragger = this.dragger, - image = this.image, - data = {}; + output: function () { + this.preview(); - if (this.built) { - data = { - x: dragger.left - image.left, - y: dragger.top - image.top, - width: dragger.width, - height: dragger.height - }; + if (this.complete) { + this.trigger(EVENT_CROP, this.getData()); + } else if (!this.built) { - data = this.transformData(data, TRUE, rounded); + // Only trigger one crop event before complete + this.$element.one(EVENT_BUILT, $.proxy(function () { + this.trigger(EVENT_CROP, this.getData()); + }, this)); } + } + }); - return data; - }, + $.extend(prototype, { + initPreview: function () { + var crossOrigin = getCrossOrigin(this.crossOrigin); + var url = this.url; - transformData: function (data, reversed, rounded) { - var ratio = this.image.ratio, - result = {}; + this.$preview = $(this.options.preview); + this.$viewBox.html('<img' + crossOrigin + ' src="' + url + '">'); + this.$preview.each(function () { + var $this = $(this); - $.each(data, function (i, n) { - n = num(n); + // Save the original size for recover + $this.data(DATA_PREVIEW, { + width: $this.width(), + height: $this.height(), + original: $this.html() + }); - if (REGEXP_OPTIONS.test(i) && !isNaN(n)) { - result[i] = reversed ? (rounded ? Math.round(n / ratio) : n / ratio) : n * ratio; - } + /** + * Override img element styles + * Add `display:block` to avoid margin top issue + * (Occur only when margin-top <= -height) + */ + $this.html( + '<img' + crossOrigin + ' src="' + url + '" style="' + + 'display:block;width:100%;height:auto;' + + 'min-width:0!important;min-height:0!important;' + + 'max-width:none!important;max-height:none!important;' + + 'image-orientation:0deg!important">' + ); }); + }, - return result; + resetPreview: function () { + this.$preview.each(function () { + var $this = $(this); + + $this.html($this.data(DATA_PREVIEW).original).removeData(DATA_PREVIEW); + }); }, - setAspectRatio: function (aspectRatio) { - var freeRatio = aspectRatio === "auto"; + preview: function () { + var image = this.image; + var canvas = this.canvas; + var cropBox = this.cropBox; + var cropBoxWidth = cropBox.width; + var cropBoxHeight = cropBox.height; + var width = image.width; + var height = image.height; + var left = cropBox.left - canvas.left - image.left; + var top = cropBox.top - canvas.top - image.top; - if (this.disabled) { + if (!this.cropped || this.disabled) { return; } - aspectRatio = num(aspectRatio); + this.$viewBox.find('img').css({ + width: width, + height: height, + marginLeft: -left, + marginTop: -top, + transform: getTransform(image) + }); - if (freeRatio || (!isNaN(aspectRatio) && aspectRatio > 0)) { - this.defaults.aspectRatio = freeRatio ? NAN : aspectRatio; + this.$preview.each(function () { + var $this = $(this); + var data = $this.data(DATA_PREVIEW); + var originalWidth = data.width; + var originalHeight = data.height; + var newWidth = originalWidth; + var newHeight = originalHeight; + var ratio = 1; - if (this.built) { - this.initDragger(); - this.renderDragger(); - this.setData(this.defaults.data); // Reset to initial state + if (cropBoxWidth) { + ratio = originalWidth / cropBoxWidth; + newHeight = cropBoxHeight * ratio; } - } - }, - getImageData: function () { - var data = {}; + if (cropBoxHeight && newHeight > originalHeight) { + ratio = originalHeight / cropBoxHeight; + newWidth = cropBoxWidth * ratio; + newHeight = originalHeight; + } - if (this.ready) { - $.each(this.image, function (name, value) { - if (REGEXP_PROPERTIES.test(name)) { - data[name] = value; - } + $this.width(newWidth).height(newHeight).find('img').css({ + width: width * ratio, + height: height * ratio, + marginLeft: -left * ratio, + marginTop: -top * ratio, + transform: getTransform(image) }); - } - - return data; - }, + }); + } + }); - getDataURL: function (options, type, quality) { - var canvas = $("<canvas>")[0], - data = this.getData(), - dataURL = "", - context; + $.extend(prototype, { + bind: function () { + var options = this.options; + var $this = this.$element; + var $cropper = this.$cropper; - if (!$.isPlainObject(options)) { - quality = type; - type = options; - options = {}; + if ($.isFunction(options.cropstart)) { + $this.on(EVENT_CROP_START, options.cropstart); } - options = $.extend({ - width: data.width, - height: data.height - }, options); - - if (this.cropped && this.support.canvas) { - canvas.width = options.width; - canvas.height = options.height; - context = canvas.getContext("2d"); - - if (type === "image/jpeg") { - context.fillStyle = "#fff"; - context.fillRect(0, 0, options.width, options.height); - } - - context.drawImage(this.$clone[0], data.x, data.y, data.width, data.height, 0, 0, options.width, options.height); - dataURL = canvas.toDataURL(type, quality); + if ($.isFunction(options.cropmove)) { + $this.on(EVENT_CROP_MOVE, options.cropmove); } - return dataURL; - }, - - setDragMode: function (mode) { - var $canvas = this.$canvas, - defaults = this.defaults, - cropable = FALSE, - movable = FALSE; - - if (!this.built || this.disabled) { - return; + if ($.isFunction(options.cropend)) { + $this.on(EVENT_CROP_END, options.cropend); } - switch (mode) { - case "crop": - if (defaults.dragCrop) { - cropable = TRUE; - $canvas.data(STRING_DIRECTIVE, mode); - } + if ($.isFunction(options.crop)) { + $this.on(EVENT_CROP, options.crop); + } - break; + if ($.isFunction(options.zoom)) { + $this.on(EVENT_ZOOM, options.zoom); + } - case "move": - movable = TRUE; - $canvas.data(STRING_DIRECTIVE, mode); + $cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.cropStart, this)); - break; - - default: - $canvas.removeData(STRING_DIRECTIVE); + if (options.zoomable && options.mouseWheelZoom) { + $cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this)); } - $canvas.toggleClass(CLASS_CROP, cropable).toggleClass(CLASS_MOVE, movable); - }, - - enable: function () { - if (this.built) { - this.disabled = FALSE; - this.$cropper.removeClass(CLASS_DISABLED); + if (options.doubleClickToggle) { + $cropper.on(EVENT_DBLCLICK, $.proxy(this.dblclick, this)); } - }, - disable: function () { - if (this.built) { - this.disabled = TRUE; - this.$cropper.addClass(CLASS_DISABLED); + $document. + on(EVENT_MOUSE_MOVE, (this._cropMove = proxy(this.cropMove, this))). + on(EVENT_MOUSE_UP, (this._cropEnd = proxy(this.cropEnd, this))); + + if (options.responsive) { + $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this))); } }, - rotate: function (degree) { - var image = this.image; - - degree = num(degree) || 0; + unbind: function () { + var options = this.options; + var $this = this.$element; + var $cropper = this.$cropper; - if (!this.built || degree === 0 || this.disabled || !this.defaults.rotatable || !this.support.canvas) { - return; + if ($.isFunction(options.cropstart)) { + $this.off(EVENT_CROP_START, options.cropstart); } - this.rotated = TRUE; - degree = (image.rotate = (image.rotate + degree) % 360); - - // replace with "true" to prevent to override the original image - this.replace(this.getRotatedDataURL(degree), true); - }, + if ($.isFunction(options.cropmove)) { + $this.off(EVENT_CROP_MOVE, options.cropmove); + } - getRotatedDataURL: function (degree) { - var canvas = $("<canvas>")[0], - context = canvas.getContext("2d"), - originalImage = this.originalImage, - naturalWidth = originalImage.naturalWidth, - naturalHeight = originalImage.naturalHeight, - deg = abs(degree) % 180, - arc = (deg > 90 ? (180 - deg) : deg) * Math.PI / 180, - width = naturalWidth * cos(arc) + naturalHeight * sin(arc), - height = naturalWidth * sin(arc) + naturalHeight * cos(arc); + if ($.isFunction(options.cropend)) { + $this.off(EVENT_CROP_END, options.cropend); + } - canvas.width = width; - canvas.height = height; - context.save(); - context.translate(width / 2, height / 2); - context.rotate(degree * Math.PI / 180); - context.drawImage(this.$original[0], -naturalWidth / 2, -naturalHeight / 2, naturalWidth, naturalHeight); - context.restore(); + if ($.isFunction(options.crop)) { + $this.off(EVENT_CROP, options.crop); + } - return canvas.toDataURL(); - }, + if ($.isFunction(options.zoom)) { + $this.off(EVENT_ZOOM, options.zoom); + } - zoom: function (delta) { - var image = this.image, - width, - height, - range; + $cropper.off(EVENT_MOUSE_DOWN, this.cropStart); - delta = num(delta); + if (options.zoomable && options.mouseWheelZoom) { + $cropper.off(EVENT_WHEEL, this.wheel); + } - if (!this.built || !delta || this.disabled || !this.defaults.zoomable) { - return; + if (options.doubleClickToggle) { + $cropper.off(EVENT_DBLCLICK, this.dblclick); } - width = image.width * (1 + delta); - height = image.height * (1 + delta); - range = width / image._width; + $document. + off(EVENT_MOUSE_MOVE, this._cropMove). + off(EVENT_MOUSE_UP, this._cropEnd); - if (range > 10) { - return; + if (options.responsive) { + $window.off(EVENT_RESIZE, this._resize); } + } + }); - if (range < 1) { - width = image._width; - height = image._height; - } + $.extend(prototype, { + resize: function () { + var $container = this.$container; + var container = this.container; + var canvasData; + var cropBoxData; + var ratio; - if (range <= 1) { - this.setDragMode("crop"); - } else { - this.setDragMode("move"); + // Check `container` is necessary for IE8 + if (this.disabled || !container) { + return; } - image.oldWidth = image.width; - image.oldHeight = image.height; + ratio = $container.width() / container.width; - image.width = width; - image.height = height; - image.ratio = image.width / image.naturalWidth; + // Resize when width changed or height changed + if (ratio !== 1 || $container.height() !== container.height) { + canvasData = this.getCanvasData(); + cropBoxData = this.getCropBoxData(); - this.renderImage("zoom"); + this.render(); + this.setCanvasData($.each(canvasData, function (i, n) { + canvasData[i] = n * ratio; + })); + this.setCropBoxData($.each(cropBoxData, function (i, n) { + cropBoxData[i] = n * ratio; + })); + } }, dblclick: function () { @@ -997,16 +1132,18 @@ return; } - if (this.$canvas.hasClass(CLASS_CROP)) { - this.setDragMode("move"); + if (this.$dragBox.hasClass(CLASS_CROP)) { + this.setDragMode(ACTION_MOVE); } else { - this.setDragMode("crop"); + this.setDragMode(ACTION_CROP); } }, wheel: function (event) { - var e = event.originalEvent, - delta = 1; + var originalEvent = event.originalEvent; + var e = originalEvent; + var ratio = num(this.options.wheelZoomRatio) || 0.1; + var delta = 1; if (this.disabled) { return; @@ -1022,15 +1159,16 @@ delta = e.detail > 0 ? 1 : -1; } - this.zoom(delta * 0.1); + this.zoom(-delta * ratio, originalEvent); }, - dragstart: function (event) { - var touches = event.originalEvent.touches, - e = event, - directive, - dragStartEvent, - touchesLength; + cropStart: function (event) { + var options = this.options; + var originalEvent = event.originalEvent; + var touches = originalEvent && originalEvent.touches; + var e = event; + var touchesLength; + var action; if (this.disabled) { return; @@ -1040,11 +1178,11 @@ touchesLength = touches.length; if (touchesLength > 1) { - if (this.defaults.zoomable && touchesLength === 2) { + if (options.zoomable && options.touchDragZoom && touchesLength === 2) { e = touches[1]; this.startX2 = e.pageX; this.startY2 = e.pageY; - directive = "zoom"; + action = ACTION_ZOOM; } else { return; } @@ -1053,35 +1191,40 @@ e = touches[0]; } - directive = directive || $(e.target).data(STRING_DIRECTIVE); - - if (REGEXP_DIRECTIVES.test(directive)) { - event.preventDefault(); - - dragStartEvent = $.Event(EVENT_DRAG_START); - this.$element.trigger(dragStartEvent); + action = action || $(e.target).data(DATA_ACTION); - if (dragStartEvent.isDefaultPrevented()) { + if (REGEXP_ACTIONS.test(action)) { + if (this.trigger(EVENT_CROP_START, { + originalEvent: originalEvent, + action: action + }).isDefaultPrevented()) { return; } - this.directive = directive; - this.cropping = FALSE; - this.startX = e.pageX; - this.startY = e.pageY; + event.preventDefault(); + + this.action = action; + this.cropping = false; + + // IE8 has `event.pageX/Y`, but not `event.originalEvent.pageX/Y` + // IE10 has `event.originalEvent.pageX/Y`, but not `event.pageX/Y` + this.startX = e.pageX || originalEvent && originalEvent.pageX; + this.startY = e.pageY || originalEvent && originalEvent.pageY; - if (directive === "crop") { - this.cropping = TRUE; - this.$canvas.addClass(CLASS_MODAL); + if (action === ACTION_CROP) { + this.cropping = true; + this.$dragBox.addClass(CLASS_MODAL); } } }, - dragmove: function (event) { - var touches = event.originalEvent.touches, - e = event, - dragMoveEvent, - touchesLength; + cropMove: function (event) { + var options = this.options; + var originalEvent = event.originalEvent; + var touches = originalEvent && originalEvent.touches; + var e = event; + var action = this.action; + var touchesLength; if (this.disabled) { return; @@ -1091,7 +1234,7 @@ touchesLength = touches.length; if (touchesLength > 1) { - if (this.defaults.zoomable && touchesLength === 2) { + if (options.zoomable && options.touchDragZoom && touchesLength === 2) { e = touches[1]; this.endX2 = e.pageX; this.endY2 = e.pageY; @@ -1103,87 +1246,106 @@ e = touches[0]; } - if (this.directive) { - event.preventDefault(); - - dragMoveEvent = $.Event(EVENT_DRAG_MOVE); - this.$element.trigger(dragMoveEvent); - - if (dragMoveEvent.isDefaultPrevented()) { + if (action) { + if (this.trigger(EVENT_CROP_MOVE, { + originalEvent: originalEvent, + action: action + }).isDefaultPrevented()) { return; } - this.endX = e.pageX; - this.endY = e.pageY; + event.preventDefault(); + + this.endX = e.pageX || originalEvent && originalEvent.pageX; + this.endY = e.pageY || originalEvent && originalEvent.pageY; - this.dragging(); + this.change(e.shiftKey, action === ACTION_ZOOM ? originalEvent : null); } }, - dragend: function (event) { - var dragEndEvent; + cropEnd: function (event) { + var originalEvent = event.originalEvent; + var action = this.action; if (this.disabled) { return; } - if (this.directive) { + if (action) { event.preventDefault(); - dragEndEvent = $.Event(EVENT_DRAG_END); - this.$element.trigger(dragEndEvent); - - if (dragEndEvent.isDefaultPrevented()) { - return; - } - if (this.cropping) { - this.cropping = FALSE; - this.$canvas.toggleClass(CLASS_MODAL, this.cropped && this.defaults.modal); + this.cropping = false; + this.$dragBox.toggleClass(CLASS_MODAL, this.cropped && this.options.modal); } - this.directive = ""; + this.action = ''; + + this.trigger(EVENT_CROP_END, { + originalEvent: originalEvent, + action: action + }); + } + } + }); + + $.extend(prototype, { + change: function (shiftKey, originalEvent) { + var options = this.options; + var aspectRatio = options.aspectRatio; + var action = this.action; + var container = this.container; + var canvas = this.canvas; + var cropBox = this.cropBox; + var width = cropBox.width; + var height = cropBox.height; + var left = cropBox.left; + var top = cropBox.top; + var right = left + width; + var bottom = top + height; + var minLeft = 0; + var minTop = 0; + var maxWidth = container.width; + var maxHeight = container.height; + var renderable = true; + var offset; + var range; + + // Locking aspect ratio in "free mode" by holding shift key (#259) + if (!aspectRatio && shiftKey) { + aspectRatio = width && height ? width / height : 1; } - }, - dragging: function () { - var directive = this.directive, - image = this.image, - cropper = this.cropper, - maxWidth = cropper.width, - maxHeight = cropper.height, - dragger = this.dragger, - width = dragger.width, - height = dragger.height, - left = dragger.left, - top = dragger.top, - right = left + width, - bottom = top + height, - renderable = TRUE, - aspectRatio = this.defaults.aspectRatio, - range = { - x: this.endX - this.startX, - y: this.endY - this.startY - }, - offset; + if (options.strict) { + minLeft = cropBox.minLeft; + minTop = cropBox.minTop; + maxWidth = minLeft + min(container.width, canvas.width); + maxHeight = minTop + min(container.height, canvas.height); + } + + range = { + x: this.endX - this.startX, + y: this.endY - this.startY + }; if (aspectRatio) { range.X = range.y * aspectRatio; range.Y = range.x / aspectRatio; } - switch (directive) { - // Move dragger - case "all": + switch (action) { + // Move crop box + case ACTION_ALL: left += range.x; top += range.y; - break; - // Resize dragger - case "e": - if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= 0 || bottom >= maxHeight))) { - renderable = FALSE; + // Resize crop box + case ACTION_EAST: + if (range.x >= 0 && (right >= maxWidth || aspectRatio && + (top <= minTop || bottom >= maxHeight))) { + + renderable = false; break; } @@ -1195,15 +1357,17 @@ } if (width < 0) { - directive = "w"; + action = ACTION_WEST; width = 0; } break; - case "n": - if (range.y <= 0 && (top <= 0 || aspectRatio && (left <= 0 || right >= maxWidth))) { - renderable = FALSE; + case ACTION_NORTH: + if (range.y <= 0 && (top <= minTop || aspectRatio && + (left <= minLeft || right >= maxWidth))) { + + renderable = false; break; } @@ -1216,15 +1380,17 @@ } if (height < 0) { - directive = "s"; + action = ACTION_SOUTH; height = 0; } break; - case "w": - if (range.x <= 0 && (left <= 0 || aspectRatio && (top <= 0 || bottom >= maxHeight))) { - renderable = FALSE; + case ACTION_WEST: + if (range.x <= 0 && (left <= minLeft || aspectRatio && + (top <= minTop || bottom >= maxHeight))) { + + renderable = false; break; } @@ -1237,15 +1403,17 @@ } if (width < 0) { - directive = "e"; + action = ACTION_EAST; width = 0; } break; - case "s": - if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= 0 || right >= maxWidth))) { - renderable = FALSE; + case ACTION_SOUTH: + if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && + (left <= minLeft || right >= maxWidth))) { + + renderable = false; break; } @@ -1257,16 +1425,16 @@ } if (height < 0) { - directive = "n"; + action = ACTION_NORTH; height = 0; } break; - case "ne": + case ACTION_NORTH_EAST: if (aspectRatio) { - if (range.y <= 0 && (top <= 0 || right >= maxWidth)) { - renderable = FALSE; + if (range.y <= 0 && (top <= minTop || right >= maxWidth)) { + renderable = false; break; } @@ -1277,15 +1445,15 @@ if (range.x >= 0) { if (right < maxWidth) { width += range.x; - } else if (range.y <= 0 && top <= 0) { - renderable = FALSE; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; } } else { width += range.x; } if (range.y <= 0) { - if (top > 0) { + if (top > minTop) { height -= range.y; top += range.y; } @@ -1296,23 +1464,23 @@ } if (width < 0 && height < 0) { - directive = "sw"; + action = ACTION_SOUTH_WEST; height = 0; width = 0; } else if (width < 0) { - directive = "nw"; + action = ACTION_NORTH_WEST; width = 0; } else if (height < 0) { - directive = "se"; + action = ACTION_SOUTH_EAST; height = 0; } break; - case "nw": + case ACTION_NORTH_WEST: if (aspectRatio) { - if (range.y <= 0 && (top <= 0 || left <= 0)) { - renderable = FALSE; + if (range.y <= 0 && (top <= minTop || left <= minLeft)) { + renderable = false; break; } @@ -1322,11 +1490,11 @@ left += range.X; } else { if (range.x <= 0) { - if (left > 0) { + if (left > minLeft) { width -= range.x; left += range.x; - } else if (range.y <= 0 && top <= 0) { - renderable = FALSE; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; } } else { width -= range.x; @@ -1334,7 +1502,7 @@ } if (range.y <= 0) { - if (top > 0) { + if (top > minTop) { height -= range.y; top += range.y; } @@ -1345,23 +1513,23 @@ } if (width < 0 && height < 0) { - directive = "se"; + action = ACTION_SOUTH_EAST; height = 0; width = 0; } else if (width < 0) { - directive = "ne"; + action = ACTION_NORTH_EAST; width = 0; } else if (height < 0) { - directive = "sw"; + action = ACTION_SOUTH_WEST; height = 0; } break; - case "sw": + case ACTION_SOUTH_WEST: if (aspectRatio) { - if (range.x <= 0 && (left <= 0 || bottom >= maxHeight)) { - renderable = FALSE; + if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) { + renderable = false; break; } @@ -1370,11 +1538,11 @@ height = width / aspectRatio; } else { if (range.x <= 0) { - if (left > 0) { + if (left > minLeft) { width -= range.x; left += range.x; } else if (range.y >= 0 && bottom >= maxHeight) { - renderable = FALSE; + renderable = false; } } else { width -= range.x; @@ -1391,23 +1559,23 @@ } if (width < 0 && height < 0) { - directive = "ne"; + action = ACTION_NORTH_EAST; height = 0; width = 0; } else if (width < 0) { - directive = "se"; + action = ACTION_SOUTH_EAST; width = 0; } else if (height < 0) { - directive = "nw"; + action = ACTION_NORTH_WEST; height = 0; } break; - case "se": + case ACTION_SOUTH_EAST: if (aspectRatio) { if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) { - renderable = FALSE; + renderable = false; break; } @@ -1418,7 +1586,7 @@ if (right < maxWidth) { width += range.x; } else if (range.y >= 0 && bottom >= maxHeight) { - renderable = FALSE; + renderable = false; } } else { width += range.x; @@ -1434,76 +1602,74 @@ } if (width < 0 && height < 0) { - directive = "nw"; + action = ACTION_NORTH_WEST; height = 0; width = 0; } else if (width < 0) { - directive = "sw"; + action = ACTION_SOUTH_WEST; width = 0; } else if (height < 0) { - directive = "ne"; + action = ACTION_NORTH_EAST; height = 0; } break; - // Move image - case "move": - image.left += range.x; - image.top += range.y; - this.renderImage("move"); - renderable = FALSE; + // Move canvas + case ACTION_MOVE: + this.move(range.x, range.y); + renderable = false; break; - // Scale image - case "zoom": - this.zoom(function (x, y, x1, y1, x2, y2) { - return (sqrt(x2 * x2 + y2 * y2) - sqrt(x1 * x1 + y1 * y1)) / sqrt(x * x + y * y); - }( - image.width, - image.height, + // Zoom canvas + case ACTION_ZOOM: + this.zoom((function (x1, y1, x2, y2) { + var z1 = sqrt(x1 * x1 + y1 * y1); + var z2 = sqrt(x2 * x2 + y2 * y2); + + return (z2 - z1) / z1; + })( abs(this.startX - this.startX2), abs(this.startY - this.startY2), abs(this.endX - this.endX2), abs(this.endY - this.endY2) - )); - - this.endX2 = this.startX2; - this.endY2 = this.startY2; - renderable = FALSE; + ), originalEvent); + this.startX2 = this.endX2; + this.startY2 = this.endY2; + renderable = false; break; - // Crop image - case "crop": + // Create crop box + case ACTION_CROP: if (range.x && range.y) { offset = this.$cropper.offset(); left = this.startX - offset.left; top = this.startY - offset.top; - width = dragger.minWidth; - height = dragger.minHeight; + width = cropBox.minWidth; + height = cropBox.minHeight; if (range.x > 0) { if (range.y > 0) { - directive = "se"; + action = ACTION_SOUTH_EAST; } else { - directive = "ne"; + action = ACTION_NORTH_EAST; top -= height; } } else { if (range.y > 0) { - directive = "sw"; + action = ACTION_SOUTH_WEST; left -= width; } else { - directive = "nw"; + action = ACTION_NORTH_WEST; left -= width; top -= height; } } - // Show the dragger if is hidden + // Show the crop box if is hidden if (!this.cropped) { - this.cropped = TRUE; - this.$dragger.removeClass(CLASS_HIDDEN); + this.cropped = true; + this.$cropBox.removeClass(CLASS_HIDDEN); } } @@ -1513,121 +1679,832 @@ } if (renderable) { - dragger.width = width; - dragger.height = height; - dragger.left = left; - dragger.top = top; - this.directive = directive; + cropBox.width = width; + cropBox.height = height; + cropBox.left = left; + cropBox.top = top; + this.action = action; - this.renderDragger(); + this.renderCropBox(); } // Override this.startX = this.endX; this.startY = this.endY; } - }; + }); - // Use the string compressor: Strmin (https://github.com/fengyuanchen/strmin) - Cropper.TEMPLATE = (function (source, words) { - words = words.split(","); - return source.replace(/\d+/g, function (i) { - return words[i]; - }); - })('<0 6="5-container"><0 6="5-canvas"></0><0 6="5-dragger"><1 6="5-viewer"></1><1 6="5-8 8-h"></1><1 6="5-8 8-v"></1><1 6="5-face" 3-2="all"></1><1 6="5-7 7-e" 3-2="e"></1><1 6="5-7 7-n" 3-2="n"></1><1 6="5-7 7-w" 3-2="w"></1><1 6="5-7 7-s" 3-2="s"></1><1 6="5-4 4-e" 3-2="e"></1><1 6="5-4 4-n" 3-2="n"></1><1 6="5-4 4-w" 3-2="w"></1><1 6="5-4 4-s" 3-2="s"></1><1 6="5-4 4-ne" 3-2="ne"></1><1 6="5-4 4-nw" 3-2="nw"></1><1 6="5-4 4-sw" 3-2="sw"></1><1 6="5-4 4-se" 3-2="se"></1></0></0>', "div,span,directive,data,point,cropper,class,line,dashed"); + $.extend(prototype, { - /* Template source: - <div class="cropper-container"> - <div class="cropper-canvas"></div> - <div class="cropper-dragger"> - <span class="cropper-viewer"></span> - <span class="cropper-dashed dashed-h"></span> - <span class="cropper-dashed dashed-v"></span> - <span class="cropper-face" data-directive="all"></span> - <span class="cropper-line line-e" data-directive="e"></span> - <span class="cropper-line line-n" data-directive="n"></span> - <span class="cropper-line line-w" data-directive="w"></span> - <span class="cropper-line line-s" data-directive="s"></span> - <span class="cropper-point point-e" data-directive="e"></span> - <span class="cropper-point point-n" data-directive="n"></span> - <span class="cropper-point point-w" data-directive="w"></span> - <span class="cropper-point point-s" data-directive="s"></span> - <span class="cropper-point point-ne" data-directive="ne"></span> - <span class="cropper-point point-nw" data-directive="nw"></span> - <span class="cropper-point point-sw" data-directive="sw"></span> - <span class="cropper-point point-se" data-directive="se"></span> - </div> - </div> - */ + // Show the crop box manually + crop: function () { + if (!this.built || this.disabled) { + return; + } - Cropper.DEFAULTS = { - // Basic - aspectRatio: "auto", - autoCropArea: 0.8, // 80% - data: { - // x: 0, - // y: 0, - // width: 300, - // height: 150 + if (!this.cropped) { + this.cropped = true; + this.limitCropBox(true, true); + + if (this.options.modal) { + this.$dragBox.addClass(CLASS_MODAL); + } + + this.$cropBox.removeClass(CLASS_HIDDEN); + } + + this.setCropBoxData(this.initialCropBox); }, - done: $.noop, - preview: "", - // Toggles - multiple: FALSE, - autoCrop: TRUE, - dragCrop: TRUE, - dashed: TRUE, - modal: TRUE, - movable: TRUE, - resizable: TRUE, - zoomable: TRUE, - rotatable: TRUE, - checkImageOrigin: TRUE, + // Reset the image and crop box to their initial states + reset: function () { + if (!this.built || this.disabled) { + return; + } + + this.image = $.extend({}, this.initialImage); + this.canvas = $.extend({}, this.initialCanvas); + + // Required for strict mode + this.cropBox = $.extend({}, this.initialCropBox); - // Dimensions - minWidth: 0, - minHeight: 0, - maxWidth: INFINITY, - maxHeight: INFINITY, - minContainerWidth: 300, - minContainerHeight: 150, + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + }, + + // Clear the crop box + clear: function () { + if (!this.cropped || this.disabled) { + return; + } + + $.extend(this.cropBox, { + left: 0, + top: 0, + width: 0, + height: 0 + }); - // Events - build: NULL, - built: NULL, - dragstart: NULL, - dragmove: NULL, - dragend: NULL + this.cropped = false; + this.renderCropBox(); + + this.limitCanvas(true, true); + + // Render canvas after crop box rendered + this.renderCanvas(); + + this.$dragBox.removeClass(CLASS_MODAL); + this.$cropBox.addClass(CLASS_HIDDEN); + }, + + /** + * Replace the image's src and rebuild the cropper + * + * @param {String} url + */ + replace: function (url) { + if (!this.disabled && url) { + if (this.isImg) { + this.replaced = true; + this.$element.attr('src', url); + } + + // Clear previous data + this.options.data = null; + this.load(url); + } + }, + + // Enable (unfreeze) the cropper + enable: function () { + if (this.built) { + this.disabled = false; + this.$cropper.removeClass(CLASS_DISABLED); + } + }, + + // Disable (freeze) the cropper + disable: function () { + if (this.built) { + this.disabled = true; + this.$cropper.addClass(CLASS_DISABLED); + } + }, + + // Destroy the cropper and remove the instance from the image + destroy: function () { + var $this = this.$element; + + if (this.ready) { + if (this.isImg && this.replaced) { + $this.attr('src', this.originalUrl); + } + + this.unbuild(); + $this.removeClass(CLASS_HIDDEN); + } else { + if (this.isImg) { + $this.off(EVENT_LOAD, this.start); + } else if (this.$clone) { + this.$clone.remove(); + } + } + + $this.removeData(NAMESPACE); + }, + + /** + * Move the canvas + * + * @param {Number} offsetX + * @param {Number} offsetY (optional) + */ + move: function (offsetX, offsetY) { + var canvas = this.canvas; + + // If "offsetY" is not present, its default value is "offsetX" + if (isUndefined(offsetY)) { + offsetY = offsetX; + } + + offsetX = num(offsetX); + offsetY = num(offsetY); + + if (this.built && !this.disabled && this.options.movable) { + canvas.left += isNumber(offsetX) ? offsetX : 0; + canvas.top += isNumber(offsetY) ? offsetY : 0; + this.renderCanvas(true); + } + }, + + /** + * Zoom the canvas + * + * @param {Number} ratio + * @param {Event} _originalEvent (private) + */ + zoom: function (ratio, _originalEvent) { + var canvas = this.canvas; + var width; + var height; + + ratio = num(ratio); + + if (ratio && this.built && !this.disabled && this.options.zoomable) { + if (this.trigger(EVENT_ZOOM, { + originalEvent: _originalEvent, + ratio: ratio + }).isDefaultPrevented()) { + return; + } + + if (ratio < 0) { + ratio = 1 / (1 - ratio); + } else { + ratio = 1 + ratio; + } + + width = canvas.width * ratio; + height = canvas.height * ratio; + canvas.left -= (width - canvas.width) / 2; + canvas.top -= (height - canvas.height) / 2; + canvas.width = width; + canvas.height = height; + this.renderCanvas(true); + this.setDragMode(ACTION_MOVE); + } + }, + + /** + * Rotate the canvas + * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate() + * + * @param {Number} degree + */ + rotate: function (degree) { + var image = this.image; + var rotate = image.rotate || 0; + + degree = num(degree) || 0; + + if (this.built && !this.disabled && this.options.rotatable) { + image.rotate = (rotate + degree) % 360; + this.rotated = true; + this.renderCanvas(true); + } + }, + + /** + * Scale the image + * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#scale() + * + * @param {Number} scaleX + * @param {Number} scaleY (optional) + */ + scale: function (scaleX, scaleY) { + var image = this.image; + + // If "scaleY" is not present, its default value is "scaleX" + if (isUndefined(scaleY)) { + scaleY = scaleX; + } + + scaleX = num(scaleX); + scaleY = num(scaleY); + + if (this.built && !this.disabled && this.options.scalable) { + image.scaleX = isNumber(scaleX) ? scaleX : 1; + image.scaleY = isNumber(scaleY) ? scaleY : 1; + this.renderImage(true); + } + }, + + /** + * Get the cropped area position and size data (base on the original image) + * + * @param {Boolean} rounded (optional) + * @return {Object} data + */ + getData: function (rounded) { + var options = this.options; + var image = this.image; + var canvas = this.canvas; + var cropBox = this.cropBox; + var ratio; + var data; + + if (this.built && this.cropped) { + data = { + x: cropBox.left - canvas.left, + y: cropBox.top - canvas.top, + width: cropBox.width, + height: cropBox.height + }; + + ratio = image.width / image.naturalWidth; + + $.each(data, function (i, n) { + n = n / ratio; + data[i] = rounded ? Math.round(n) : n; + }); + + } else { + data = { + x: 0, + y: 0, + width: 0, + height: 0 + }; + } + + if (options.rotatable) { + data.rotate = image.rotate || 0; + } + + if (options.scalable) { + data.scaleX = image.scaleX || 1; + data.scaleY = image.scaleY || 1; + } + + return data; + }, + + /** + * Set the cropped area position and size with new data + * + * @param {Object} data + */ + setData: function (data) { + var options = this.options; + var image = this.image; + var canvas = this.canvas; + var cropBoxData = {}; + var rotated; + var scaled; + var ratio; + + if ($.isFunction(data)) { + data = data.call(this.element); + } + + if (this.built && !this.disabled && $.isPlainObject(data)) { + if (options.rotatable) { + if (isNumber(data.rotate) && data.rotate !== image.rotate) { + image.rotate = data.rotate; + this.rotated = rotated = true; + } + } + + if (options.scalable) { + if (isNumber(data.scaleX) && data.scaleX !== image.scaleX) { + image.scaleX = data.scaleX; + scaled = true; + } + + if (isNumber(data.scaleY) && data.scaleY !== image.scaleY) { + image.scaleY = data.scaleY; + scaled = true; + } + } + + if (rotated) { + this.renderCanvas(); + } else if (scaled) { + this.renderImage(); + } + + ratio = image.width / image.naturalWidth; + + if (isNumber(data.x)) { + cropBoxData.left = data.x * ratio + canvas.left; + } + + if (isNumber(data.y)) { + cropBoxData.top = data.y * ratio + canvas.top; + } + + if (isNumber(data.width)) { + cropBoxData.width = data.width * ratio; + } + + if (isNumber(data.height)) { + cropBoxData.height = data.height * ratio; + } + + this.setCropBoxData(cropBoxData); + } + }, + + /** + * Get the container size data + * + * @return {Object} data + */ + getContainerData: function () { + return this.built ? this.container : {}; + }, + + /** + * Get the image position and size data + * + * @return {Object} data + */ + getImageData: function () { + return this.ready ? this.image : {}; + }, + + /** + * Get the canvas position and size data + * + * @return {Object} data + */ + getCanvasData: function () { + var canvas = this.canvas; + var data; + + if (this.built) { + data = { + left: canvas.left, + top: canvas.top, + width: canvas.width, + height: canvas.height + }; + } + + return data || {}; + }, + + /** + * Set the canvas position and size with new data + * + * @param {Object} data + */ + setCanvasData: function (data) { + var canvas = this.canvas; + var aspectRatio = canvas.aspectRatio; + + if ($.isFunction(data)) { + data = data.call(this.$element); + } + + if (this.built && !this.disabled && $.isPlainObject(data)) { + if (isNumber(data.left)) { + canvas.left = data.left; + } + + if (isNumber(data.top)) { + canvas.top = data.top; + } + + if (isNumber(data.width)) { + canvas.width = data.width; + canvas.height = data.width / aspectRatio; + } else if (isNumber(data.height)) { + canvas.height = data.height; + canvas.width = data.height * aspectRatio; + } + + this.renderCanvas(true); + } + }, + + /** + * Get the crop box position and size data + * + * @return {Object} data + */ + getCropBoxData: function () { + var cropBox = this.cropBox; + var data; + + if (this.built && this.cropped) { + data = { + left: cropBox.left, + top: cropBox.top, + width: cropBox.width, + height: cropBox.height + }; + } + + return data || {}; + }, + + /** + * Set the crop box position and size with new data + * + * @param {Object} data + */ + setCropBoxData: function (data) { + var cropBox = this.cropBox; + var aspectRatio = this.options.aspectRatio; + var widthChanged; + var heightChanged; + + if ($.isFunction(data)) { + data = data.call(this.$element); + } + + if (this.built && this.cropped && !this.disabled && $.isPlainObject(data)) { + + if (isNumber(data.left)) { + cropBox.left = data.left; + } + + if (isNumber(data.top)) { + cropBox.top = data.top; + } + + if (isNumber(data.width) && data.width !== cropBox.width) { + widthChanged = true; + cropBox.width = data.width; + } + + if (isNumber(data.height) && data.height !== cropBox.height) { + heightChanged = true; + cropBox.height = data.height; + } + + if (aspectRatio) { + if (widthChanged) { + cropBox.height = cropBox.width / aspectRatio; + } else if (heightChanged) { + cropBox.width = cropBox.height * aspectRatio; + } + } + + this.renderCropBox(); + } + }, + + /** + * Get a canvas drawn the cropped image + * + * @param {Object} options (optional) + * @return {HTMLCanvasElement} canvas + */ + getCroppedCanvas: function (options) { + var originalWidth; + var originalHeight; + var canvasWidth; + var canvasHeight; + var scaledWidth; + var scaledHeight; + var scaledRatio; + var aspectRatio; + var canvas; + var context; + var data; + + if (!this.built || !this.cropped || !SUPPORT_CANVAS) { + return; + } + + if (!$.isPlainObject(options)) { + options = {}; + } + + data = this.getData(); + originalWidth = data.width; + originalHeight = data.height; + aspectRatio = originalWidth / originalHeight; + + if ($.isPlainObject(options)) { + scaledWidth = options.width; + scaledHeight = options.height; + + if (scaledWidth) { + scaledHeight = scaledWidth / aspectRatio; + scaledRatio = scaledWidth / originalWidth; + } else if (scaledHeight) { + scaledWidth = scaledHeight * aspectRatio; + scaledRatio = scaledHeight / originalHeight; + } + } + + canvasWidth = scaledWidth || originalWidth; + canvasHeight = scaledHeight || originalHeight; + + canvas = $('<canvas>')[0]; + canvas.width = canvasWidth; + canvas.height = canvasHeight; + context = canvas.getContext('2d'); + + if (options.fillColor) { + context.fillStyle = options.fillColor; + context.fillRect(0, 0, canvasWidth, canvasHeight); + } + + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage + context.drawImage.apply(context, (function () { + var source = getSourceCanvas(this.$clone[0], this.image); + var sourceWidth = source.width; + var sourceHeight = source.height; + var args = [source]; + + // Source canvas + var srcX = data.x; + var srcY = data.y; + var srcWidth; + var srcHeight; + + // Destination canvas + var dstX; + var dstY; + var dstWidth; + var dstHeight; + + if (srcX <= -originalWidth || srcX > sourceWidth) { + srcX = srcWidth = dstX = dstWidth = 0; + } else if (srcX <= 0) { + dstX = -srcX; + srcX = 0; + srcWidth = dstWidth = min(sourceWidth, originalWidth + srcX); + } else if (srcX <= sourceWidth) { + dstX = 0; + srcWidth = dstWidth = min(originalWidth, sourceWidth - srcX); + } + + if (srcWidth <= 0 || srcY <= -originalHeight || srcY > sourceHeight) { + srcY = srcHeight = dstY = dstHeight = 0; + } else if (srcY <= 0) { + dstY = -srcY; + srcY = 0; + srcHeight = dstHeight = min(sourceHeight, originalHeight + srcY); + } else if (srcY <= sourceHeight) { + dstY = 0; + srcHeight = dstHeight = min(originalHeight, sourceHeight - srcY); + } + + args.push(srcX, srcY, srcWidth, srcHeight); + + // Scale destination sizes + if (scaledRatio) { + dstX *= scaledRatio; + dstY *= scaledRatio; + dstWidth *= scaledRatio; + dstHeight *= scaledRatio; + } + + // Avoid "IndexSizeError" in IE and Firefox + if (dstWidth > 0 && dstHeight > 0) { + args.push(dstX, dstY, dstWidth, dstHeight); + } + + return args; + }).call(this)); + + return canvas; + }, + + /** + * Change the aspect ratio of the crop box + * + * @param {Number} aspectRatio + */ + setAspectRatio: function (aspectRatio) { + var options = this.options; + + if (!this.disabled && !isUndefined(aspectRatio)) { + + // 0 -> NaN + options.aspectRatio = num(aspectRatio) || NaN; + + if (this.built) { + this.initCropBox(); + + if (this.cropped) { + this.renderCropBox(); + } + } + } + }, + + /** + * Change the drag mode + * + * @param {String} mode (optional) + */ + setDragMode: function (mode) { + var options = this.options; + var croppable; + var movable; + + if (this.ready && !this.disabled) { + croppable = options.dragCrop && mode === ACTION_CROP; + movable = options.movable && mode === ACTION_MOVE; + mode = (croppable || movable) ? mode : ACTION_NONE; + + this.$dragBox. + data(DATA_ACTION, mode). + toggleClass(CLASS_CROP, croppable). + toggleClass(CLASS_MOVE, movable); + + if (!options.cropBoxMovable) { + + // Sync drag mode to crop box when it is not movable(#300) + this.$face. + data(DATA_ACTION, mode). + toggleClass(CLASS_CROP, croppable). + toggleClass(CLASS_MOVE, movable); + } + } + } + }); + + $.extend(Cropper.prototype, prototype); + + Cropper.DEFAULTS = { + + // Define the aspect ratio of the crop box + aspectRatio: NaN, + + // An object with the previous cropping result data + data: null, + + // A jQuery selector for adding extra containers to preview + preview: '', + + // Strict mode, the image cannot zoom out less than the container + strict: true, + + // Rebuild when resize the window + responsive: true, + + // Check if the target image is cross origin + checkImageOrigin: true, + + // Show the black modal + modal: true, + + // Show the dashed lines for guiding + guides: true, + + // Show the center indicator for guiding + center: true, + + // Show the white modal to highlight the crop box + highlight: true, + + // Show the grid background + background: true, + + // Enable to crop the image automatically when initialize + autoCrop: true, + + // Define the percentage of automatic cropping area when initializes + autoCropArea: 0.8, + + // Enable to create new crop box by dragging over the image + dragCrop: true, + + // Enable to move the image + movable: true, + + // Enable to rotate the image + rotatable: true, + + // Enable to scale the image + scalable: true, + + // Enable to zoom the image + zoomable: true, + + // Enable to zoom the image by wheeling mouse + mouseWheelZoom: true, + + // Define zoom ratio when zoom the image by wheeling mouse + wheelZoomRatio: 0.1, + + // Enable to zoom the image by dragging touch + touchDragZoom: true, + + // Enable to move the crop box + cropBoxMovable: true, + + // Enable to resize the crop box + cropBoxResizable: true, + + // Toggle drag mode between "crop" and "move" when double click on the cropper + doubleClickToggle: true, + + // Size limitation + minCanvasWidth: 0, + minCanvasHeight: 0, + minCropBoxWidth: 0, + minCropBoxHeight: 0, + minContainerWidth: 200, + minContainerHeight: 100, + + // Shortcuts of events + build: null, + built: null, + cropstart: null, + cropmove: null, + cropend: null, + crop: null, + zoom: null }; Cropper.setDefaults = function (options) { $.extend(Cropper.DEFAULTS, options); }; + Cropper.TEMPLATE = ( + '<div class="cropper-container">' + + '<div class="cropper-canvas"></div>' + + '<div class="cropper-drag-box"></div>' + + '<div class="cropper-crop-box">' + + '<span class="cropper-view-box"></span>' + + '<span class="cropper-dashed dashed-h"></span>' + + '<span class="cropper-dashed dashed-v"></span>' + + '<span class="cropper-center"></span>' + + '<span class="cropper-face"></span>' + + '<span class="cropper-line line-e" data-action="e"></span>' + + '<span class="cropper-line line-n" data-action="n"></span>' + + '<span class="cropper-line line-w" data-action="w"></span>' + + '<span class="cropper-line line-s" data-action="s"></span>' + + '<span class="cropper-point point-e" data-action="e"></span>' + + '<span class="cropper-point point-n" data-action="n"></span>' + + '<span class="cropper-point point-w" data-action="w"></span>' + + '<span class="cropper-point point-s" data-action="s"></span>' + + '<span class="cropper-point point-ne" data-action="ne"></span>' + + '<span class="cropper-point point-nw" data-action="nw"></span>' + + '<span class="cropper-point point-sw" data-action="sw"></span>' + + '<span class="cropper-point point-se" data-action="se"></span>' + + '</div>' + + '</div>' + ); + // Save the other cropper Cropper.other = $.fn.cropper; // Register as jQuery plugin $.fn.cropper = function (options) { - var args = toArray(arguments, 1), - result; + var args = toArray(arguments, 1); + var result; this.each(function () { - var $this = $(this), - data = $this.data("cropper"), - fn; + var $this = $(this); + var data = $this.data(NAMESPACE); + var fn; if (!data) { - $this.data("cropper", (data = new Cropper(this, options))); + if (/destroy/.test(options)) { + return; + } + + $this.data(NAMESPACE, (data = new Cropper(this, options))); } - if (typeof options === "string" && $.isFunction((fn = data[options]))) { + if (typeof options === 'string' && $.isFunction(fn = data[options])) { result = fn.apply(data, args); } }); - return (typeof result !== STRING_UNDEFINED ? result : this); + return isUndefined(result) ? this : result; }; $.fn.cropper.Constructor = Cropper; @@ -1638,4 +2515,5 @@ $.fn.cropper = Cropper.other; return this; }; + }); diff --git a/javascript/jquery/plugins/cropper/cropper.min.css b/javascript/jquery/plugins/cropper/cropper.min.css index 4cf0820..cf3d050 100644 --- a/javascript/jquery/plugins/cropper/cropper.min.css +++ b/javascript/jquery/plugins/cropper/cropper.min.css @@ -1,9 +1,9 @@ /*! - * Cropper v0.7.9 + * Cropper v1.0.0 * https://github.com/fengyuanchen/cropper * - * Copyright 2014-2015 Fengyuan Chen + * Copyright (c) 2014-2015 Fengyuan Chen and contributors * Released under the MIT license - */ - -.cropper-container{position:relative;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.cropper-container img{width:100%;height:100%;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important}.cropper-canvas,.cropper-modal{position:absolute;top:0;right:0;bottom:0;left:0}.cropper-canvas{background-color:#fff;opacity:0;filter:alpha(opacity=0)}.cropper-modal{background-color:#000;opacity:.5;filter:alpha(opacity=50)}.cropper-dragger{position:absolute;top:10%;left:10%;width:80%;height:80%}.cropper-viewer{display:block;width:100%;height:100%;overflow:hidden;outline:#69f solid 1px;outline-color:rgba(51,102,255,.75)}.cropper-dashed{position:absolute;display:block;border:0 dashed #fff;opacity:.5;filter:alpha(opacity=50)}.cropper-dashed.dashed-h{top:33.3%;left:0;width:100%;height:33.3%;border-top-width:1px;border-bottom-width:1px}.cropper-dashed.dashed-v{top:0;left:33.3%;width:33.3%;height:100%;border-right-width:1px;border-left-width:1px}.cropper-face,.cropper-line,.cropper-point{position:absolute;display:block;width:100%;height:100%;opacity:.1;filter:alpha(opacity=10)}.cropper-face{top:0;left:0;cursor:move;background-color:#fff}.cropper-line{background-color:#69f}.cropper-line.line-e{top:0;right:-3px;width:5px;cursor:e-resize}.cropper-line.line-n{top:-3px;left:0;height:5px;cursor:n-resize}.cropper-line.line-w{top:0;left:-3px;width:5px;cursor:w-resize}.cropper-line.line-s{bottom:-3px;left:0;height:5px;cursor:s-resize}.cropper-point{width:5px;height:5px;background-color:#69f;opacity:.75;filter:alpha(opacity=75)}.cropper-point.point-e{top:50%;right:-3px;margin-top:-3px;cursor:e-resize}.cropper-point.point-n{top:-3px;left:50%;margin-left:-3px;cursor:n-resize}.cropper-point.point-w{top:50%;left:-3px;margin-top:-3px;cursor:w-resize}.cropper-point.point-s{bottom:-3px;left:50%;margin-left:-3px;cursor:s-resize}.cropper-point.point-ne{top:-3px;right:-3px;cursor:ne-resize}.cropper-point.point-nw{top:-3px;left:-3px;cursor:nw-resize}.cropper-point.point-sw{bottom:-3px;left:-3px;cursor:sw-resize}.cropper-point.point-se{right:-3px;bottom:-3px;width:20px;height:20px;cursor:se-resize;opacity:1;filter:alpha(opacity=100)}.cropper-point.point-se:before{position:absolute;right:-50%;bottom:-50%;display:block;width:200%;height:200%;content:" ";background-color:#69f;opacity:0;filter:alpha(opacity=0)}@media (min-width:768px){.cropper-point.point-se{width:15px;height:15px}}@media (min-width:992px){.cropper-point.point-se{width:10px;height:10px}}@media (min-width:1200px){.cropper-point.point-se{width:5px;height:5px;opacity:.75;filter:alpha(opacity=75)}}.cropper-hidden{display:none!important}.cropper-invisible{position:fixed;top:0;left:0;z-index:-1;width:auto!important;max-width:none!important;height:auto!important;max-height:none!important;opacity:0;filter:alpha(opacity=0)}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-canvas,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}
\ No newline at end of file + * + * Date: 2015-10-10T02:10:06.999Z + */.cropper-container{position:relative;overflow:hidden;font-size:0;line-height:0;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;direction:ltr!important;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.cropper-container img{display:block;width:100%;min-width:0!important;max-width:none!important;height:100%;min-height:0!important;max-height:none!important;image-orientation:0deg!important}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal{position:absolute;top:0;right:0;bottom:0;left:0}.cropper-drag-box{background-color:#fff;filter:alpha(opacity=0);opacity:0}.cropper-dashed,.cropper-modal{filter:alpha(opacity=50);opacity:.5}.cropper-modal{background-color:#000}.cropper-view-box{display:block;width:100%;height:100%;overflow:hidden;outline:#39f solid 1px;outline-color:rgba(51,153,255,.75)}.cropper-dashed{position:absolute;display:block;border:0 dashed #eee}.cropper-dashed.dashed-h{top:33.33333%;left:0;width:100%;height:33.33333%;border-top-width:1px;border-bottom-width:1px}.cropper-dashed.dashed-v{top:0;left:33.33333%;width:33.33333%;height:100%;border-right-width:1px;border-left-width:1px}.cropper-center{position:absolute;top:50%;left:50%;display:block;width:0;height:0;filter:alpha(opacity=75);opacity:.75}.cropper-center:after,.cropper-center:before{position:absolute;display:block;content:" ";background-color:#eee}.cropper-center:before{top:0;left:-3px;width:7px;height:1px}.cropper-center:after{top:-3px;left:0;width:1px;height:7px}.cropper-face,.cropper-line,.cropper-point{position:absolute;display:block;width:100%;height:100%;filter:alpha(opacity=10);opacity:.1}.cropper-face{top:0;left:0;background-color:#fff}.cropper-line,.cropper-point{background-color:#39f}.cropper-line.line-e{top:0;right:-3px;width:5px;cursor:e-resize}.cropper-line.line-n{top:-3px;left:0;height:5px;cursor:n-resize}.cropper-line.line-w{top:0;left:-3px;width:5px;cursor:w-resize}.cropper-line.line-s{bottom:-3px;left:0;height:5px;cursor:s-resize}.cropper-point{width:5px;height:5px;filter:alpha(opacity=75);opacity:.75}.cropper-point.point-e{top:50%;right:-3px;margin-top:-3px;cursor:e-resize}.cropper-point.point-n{top:-3px;left:50%;margin-left:-3px;cursor:n-resize}.cropper-point.point-w{top:50%;left:-3px;margin-top:-3px;cursor:w-resize}.cropper-point.point-s{bottom:-3px;left:50%;margin-left:-3px;cursor:s-resize}.cropper-point.point-ne{top:-3px;right:-3px;cursor:ne-resize}.cropper-point.point-nw{top:-3px;left:-3px;cursor:nw-resize}.cropper-point.point-sw{bottom:-3px;left:-3px;cursor:sw-resize}.cropper-point.point-se{right:-3px;bottom:-3px;width:20px;height:20px;cursor:se-resize;filter:alpha(opacity=100);opacity:1}.cropper-point.point-se:before{position:absolute;right:-50%;bottom:-50%;display:block;width:200%;height:200%;content:" ";background-color:#39f;filter:alpha(opacity=0);opacity:0}@media (min-width:768px){.cropper-point.point-se{width:15px;height:15px}}@media (min-width:992px){.cropper-point.point-se{width:10px;height:10px}}@media (min-width:1200px){.cropper-point.point-se{width:5px;height:5px;filter:alpha(opacity=75);opacity:.75}}.cropper-bg{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC)}.cropper-invisible{filter:alpha(opacity=0);opacity:0}.cropper-hide{position:absolute;display:block;width:0;height:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}
\ No newline at end of file diff --git a/javascript/jquery/plugins/cropper/cropper.min.js b/javascript/jquery/plugins/cropper/cropper.min.js index 51e1362..1a619a1 100644 --- a/javascript/jquery/plugins/cropper/cropper.min.js +++ b/javascript/jquery/plugins/cropper/cropper.min.js @@ -1,9 +1,10 @@ /*! - * Cropper v0.7.9 + * Cropper v1.0.0 * https://github.com/fengyuanchen/cropper * - * Copyright 2014-2015 Fengyuan Chen + * Copyright (c) 2014-2015 Fengyuan Chen and contributors * Released under the MIT license + * + * Date: 2015-10-10T02:10:08.624Z */ - -!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){"use strict";var b=a(window),c=a(document),d=window.location,e=!0,f=!1,g=null,h=0/0,i=1/0,j="undefined",k="directive",l=".cropper",m=/^(e|n|w|s|ne|nw|sw|se|all|crop|move|zoom)$/,n=/^(x|y|width|height)$/,o=/^(naturalWidth|naturalHeight|width|height|aspectRatio|ratio|rotate)$/,p="cropper-modal",q="cropper-hidden",r="cropper-invisible",s="cropper-move",t="cropper-crop",u="cropper-disabled",v="mousedown touchstart",w="mousemove touchmove",x="mouseup mouseleave touchend touchleave touchcancel",y="wheel mousewheel DOMMouseScroll",z="resize"+l,A="dblclick",B="build"+l,C="built"+l,D="dragstart"+l,E="dragmove"+l,F="dragend"+l,G=function(a){return"number"==typeof a},H=function(a,b){var c=[];return G(b)&&c.push(b),c.slice.apply(a,c)},I=function(a,b){var c=H(arguments,2);return function(){return a.apply(b,c.concat(H(arguments)))}},J=function(a){var b="timestamp="+(new Date).getTime();return a+(-1===a.indexOf("?")?"?":"&")+b},K=function(b,c){this.element=b,this.$element=a(b),this.defaults=a.extend({},K.DEFAULTS,a.isPlainObject(c)?c:{}),this.$original=g,this.ready=f,this.built=f,this.cropped=f,this.rotated=f,this.disabled=f,this.replaced=f,this.init()},L=Math.sqrt,M=Math.min,N=Math.max,O=Math.abs,P=Math.sin,Q=Math.cos,R=parseFloat;K.prototype={constructor:K,support:{canvas:a.isFunction(a("<canvas>")[0].getContext)},init:function(){var b=this.defaults;a.each(b,function(a,c){switch(a){case"aspectRatio":b[a]=O(R(c))||h;break;case"autoCropArea":b[a]=O(R(c))||.8;break;case"minWidth":case"minHeight":b[a]=O(R(c))||0;break;case"maxWidth":case"maxHeight":b[a]=O(R(c))||i}}),this.image={rotate:0},this.load()},load:function(){var b,c,d=this,f=this.$element,g=this.element,h=this.image,i="";f.is("img")?c=f.prop("src"):f.is("canvas")&&this.support.canvas&&(c=g.toDataURL()),c&&(this.replaced&&(h.rotate=0),this.defaults.checkImageOrigin&&this.isCrossOriginURL(c)&&(i=" crossOrigin",c=J(c)),this.$clone=b=a("<img"+i+' src="'+c+'">'),b.one("load",function(){h.naturalWidth=this.naturalWidth||b.width(),h.naturalHeight=this.naturalHeight||b.height(),h.aspectRatio=h.naturalWidth/h.naturalHeight,d.url=c,d.ready=e,d.build()}),b.addClass(r).prependTo("body"))},isCrossOriginURL:function(a){var b=a.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);return!b||b[1]===d.protocol&&b[2]===d.hostname&&b[3]===d.port?f:e},build:function(){var b,c,d=this.$element,g=this.defaults;this.ready&&(this.built&&this.unbuild(),d.one(B,g.build),b=a.Event(B),d.trigger(b),b.isDefaultPrevented()||(this.$cropper=c=a(K.TEMPLATE),d.addClass(q),this.$clone.removeClass(r).prependTo(c),this.rotated||(this.$original=this.$clone.clone(),this.$original.addClass(q).prependTo(this.$cropper),this.originalImage=a.extend({},this.image)),this.$container=d.parent(),this.$container.append(c),this.$canvas=c.find(".cropper-canvas"),this.$dragger=c.find(".cropper-dragger"),this.$viewer=c.find(".cropper-viewer"),g.autoCrop?this.cropped=e:this.$dragger.addClass(q),g.modal&&this.$canvas.addClass(p),!g.dashed&&this.$dragger.find(".cropper-dashed").addClass(q),!g.movable&&this.$dragger.find(".cropper-face").data(k,"move"),!g.resizable&&this.$dragger.find(".cropper-line, .cropper-point").addClass(q),this.addListeners(),this.initPreview(),this.built=e,g.dragCrop&&this.setDragMode("crop"),this.update(),this.replaced=f,d.one(C,g.built),d.trigger(C)))},unbuild:function(){this.built&&(this.built=f,this.removeListeners(),this.$preview.empty(),this.$preview=g,this.$dragger=g,this.$canvas=g,this.$container=g,this.$cropper.remove(),this.$cropper=g)},update:function(a){this.initContainer(),this.initCropper(),this.initImage(),this.initDragger(),a?(this.setData(a,e),this.setDragMode("crop")):this.setData(this.defaults.data)},resize:function(){clearTimeout(this.resizing),this.resizing=setTimeout(a.proxy(this.update,this,this.getData()),200)},preview:function(){var b=this.image,c=this.dragger,d=b.width,e=b.height,f=c.left-b.left,g=c.top-b.top;this.$viewer.find("img").css({width:d,height:e,marginLeft:-f,marginTop:-g}),this.$preview.each(function(){var b=a(this),h=b.data(),i=h.width/c.width,j=h.width,k=c.height*i;k>h.height&&(i=h.height/c.height,j=c.width*i,k=h.height),b.width(j).height(k).find("img").css({width:d*i,height:e*i,marginLeft:-f*i,marginTop:-g*i})})},addListeners:function(){var d=this.defaults;this.$element.on(D,d.dragstart).on(E,d.dragmove).on(F,d.dragend),this.$cropper.on(v,a.proxy(this.dragstart,this)).on(A,a.proxy(this.dblclick,this)),d.zoomable&&this.$cropper.on(y,a.proxy(this.wheel,this)),d.multiple?this.$cropper.on(w,a.proxy(this.dragmove,this)).on(x,a.proxy(this.dragend,this)):c.on(w,this._dragmove=I(this.dragmove,this)).on(x,this._dragend=I(this.dragend,this)),b.on(z,this._resize=I(this.resize,this))},removeListeners:function(){var a=this.defaults;this.$element.off(D,a.dragstart).off(E,a.dragmove).off(F,a.dragend),this.$cropper.off(v,this.dragstart).off(A,this.dblclick),a.zoomable&&this.$cropper.off(y,this.wheel),a.multiple?this.$cropper.off(w,this.dragmove).off(x,this.dragend):c.off(w,this._dragmove).off(x,this._dragend),b.off(z,this._resize)},initPreview:function(){var b=this.url;this.$preview=a(this.defaults.preview),this.$viewer.html('<img src="'+b+'">'),this.$preview.each(function(){var c=a(this);c.data({width:c.width(),height:c.height()}).html('<img src="'+b+'" style="display:block;width:100%;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;">')})},initContainer:function(){var a=this.$element,b=this.$container,c=this.$cropper,d=this.defaults;c.addClass(q),a.removeClass(q),this.container={width:N(b.width(),d.minContainerWidth),height:N(b.height(),d.minContainerHeight)},a.addClass(q),c.removeClass(q)},initCropper:function(){var a,b=this.container,c=this.image;c.naturalWidth*b.height/c.naturalHeight-b.width>=0?(a={width:b.width,height:b.width/c.aspectRatio,left:0},a.top=(b.height-a.height)/2):(a={width:b.height*c.aspectRatio,height:b.height,top:0},a.left=(b.width-a.width)/2),this.$cropper.css({width:a.width,height:a.height,left:a.left,top:a.top}),this.cropper=a},initImage:function(){var b=this.image,c=this.cropper,d={_width:c.width,_height:c.height,width:c.width,height:c.height,left:0,top:0,ratio:c.width/b.naturalWidth};this.defaultImage=a.extend({},b,d),b._width!==c.width||b._height!==c.height?a.extend(b,d):(b=a.extend({},d,b),this.replaced&&(b.ratio=d.ratio)),this.image=b,this.renderImage()},renderImage:function(a){var b=this.image;"zoom"===a&&(b.left-=(b.width-b.oldWidth)/2,b.top-=(b.height-b.oldHeight)/2),b.left=M(N(b.left,b._width-b.width),0),b.top=M(N(b.top,b._height-b.height),0),this.$clone.css({width:b.width,height:b.height,marginLeft:b.left,marginTop:b.top}),a&&(this.defaults.done(this.getData()),this.preview())},initDragger:function(){var b,c,d=this.defaults,e=this.cropper,f=d.aspectRatio||this.image.aspectRatio,g=this.image.ratio;c=e.height*f-e.width>=0?{height:e.width/f,width:e.width,left:0,top:(e.height-e.width/f)/2,maxWidth:e.width,maxHeight:e.width/f}:{height:e.height,width:e.height*f,left:(e.width-e.height*f)/2,top:0,maxWidth:e.height*f,maxHeight:e.height},c.minWidth=0,c.minHeight=0,d.aspectRatio?(isFinite(d.maxWidth)?(c.maxWidth=M(c.maxWidth,d.maxWidth*g),c.maxHeight=c.maxWidth/f):isFinite(d.maxHeight)&&(c.maxHeight=M(c.maxHeight,d.maxHeight*g),c.maxWidth=c.maxHeight*f),d.minWidth>0?(c.minWidth=N(0,d.minWidth*g),c.minHeight=c.minWidth/f):d.minHeight>0&&(c.minHeight=N(0,d.minHeight*g),c.minWidth=c.minHeight*f)):(c.maxWidth=M(c.maxWidth,d.maxWidth*g),c.maxHeight=M(c.maxHeight,d.maxHeight*g),c.minWidth=N(0,d.minWidth*g),c.minHeight=N(0,d.minHeight*g)),c.minWidth=M(c.maxWidth,c.minWidth),c.minHeight=M(c.maxHeight,c.minHeight),b=a.extend({},c),b.width=N(c.minWidth,c.width*d.autoCropArea),b.height=N(c.minHeight,c.height*d.autoCropArea),b.left=(e.width-b.width)/2,b.top=(e.height-b.height)/2,b.oldLeft=c.oldLeft=c.left,b.oldTop=c.oldTop=c.top,this.autoCropDragger=b,this.defaultDragger=a.extend({},c),this.dragger=c},renderDragger:function(){var a=this.dragger,b=this.cropper;a.width>a.maxWidth?(a.width=a.maxWidth,a.left=a.oldLeft):a.width<a.minWidth&&(a.width=a.minWidth,a.left=a.oldLeft),a.height>a.maxHeight?(a.height=a.maxHeight,a.top=a.oldTop):a.height<a.minHeight&&(a.height=a.minHeight,a.top=a.oldTop),a.left=M(N(a.left,0),b.width-a.width),a.top=M(N(a.top,0),b.height-a.height),a.oldLeft=a.left,a.oldTop=a.top,this.dragger=a,this.defaults.movable&&this.$dragger.find(".cropper-face").data(k,a.width===b.width&&a.height===b.height?"move":"all"),this.disabled||this.defaults.done(this.getData()),this.$dragger.css({width:a.width,height:a.height,left:a.left,top:a.top}),this.preview()},reset:function(b){this.cropped&&!this.disabled&&(b&&(this.defaults.data={}),this.image=a.extend({},this.defaultImage),this.renderImage(),this.dragger=a.extend({},this.defaultDragger),this.setData(this.defaults.data))},clear:function(){this.cropped&&!this.disabled&&(this.cropped=f,this.setData({x:0,y:0,width:0,height:0}),this.$canvas.removeClass(p),this.$dragger.addClass(q))},destroy:function(){var a=this.$element;this.ready||this.$clone.off("load").remove(),this.unbuild(),a.removeClass(q).removeData("cropper"),this.rotated&&a.attr("src",this.$original.attr("src"))},replace:function(b,c){var d,g=this,h=this.$element,i=this.element;!this.disabled&&b&&b!==this.url&&b!==h.attr("src")&&(c||(this.rotated=f,this.replaced=e),h.is("img")?(h.attr("src",b),this.load()):h.is("canvas")&&this.support.canvas&&(d=i.getContext("2d"),a('<img src="'+b+'">').one("load",function(){i.width=this.width,i.height=this.height,d.clearRect(0,0,i.width,i.height),d.drawImage(this,0,0),g.load()})))},setData:function(b,c){var d=this.cropper,e=this.dragger,f=this.image,h=this.defaults.aspectRatio;this.built&&!this.disabled&&typeof b!==j&&((b===g||a.isEmptyObject(b))&&(e=a.extend({},this.autoCropDragger)),a.isPlainObject(b)&&!a.isEmptyObject(b)&&(c||(this.defaults.data=b),b=this.transformData(b),G(b.x)&&b.x<=d.width-f.left&&(e.left=b.x+f.left),G(b.y)&&b.y<=d.height-f.top&&(e.top=b.y+f.top),h?G(b.width)&&b.width<=e.maxWidth&&b.width>=e.minWidth?(e.width=b.width,e.height=e.width/h):G(b.height)&&b.height<=e.maxHeight&&b.height>=e.minHeight&&(e.height=b.height,e.width=e.height*h):(G(b.width)&&b.width<=e.maxWidth&&b.width>=e.minWidth&&(e.width=b.width),G(b.height)&&b.height<=e.maxHeight&&b.height>=e.minHeight&&(e.height=b.height))),this.dragger=e,this.renderDragger())},getData:function(a){var b=this.dragger,c=this.image,d={};return this.built&&(d={x:b.left-c.left,y:b.top-c.top,width:b.width,height:b.height},d=this.transformData(d,e,a)),d},transformData:function(b,c,d){var e=this.image.ratio,f={};return a.each(b,function(a,b){b=R(b),n.test(a)&&!isNaN(b)&&(f[a]=c?d?Math.round(b/e):b/e:b*e)}),f},setAspectRatio:function(a){var b="auto"===a;this.disabled||(a=R(a),(b||!isNaN(a)&&a>0)&&(this.defaults.aspectRatio=b?h:a,this.built&&(this.initDragger(),this.renderDragger(),this.setData(this.defaults.data))))},getImageData:function(){var b={};return this.ready&&a.each(this.image,function(a,c){o.test(a)&&(b[a]=c)}),b},getDataURL:function(b,c,d){var e,f=a("<canvas>")[0],g=this.getData(),h="";return a.isPlainObject(b)||(d=c,c=b,b={}),b=a.extend({width:g.width,height:g.height},b),this.cropped&&this.support.canvas&&(f.width=b.width,f.height=b.height,e=f.getContext("2d"),"image/jpeg"===c&&(e.fillStyle="#fff",e.fillRect(0,0,b.width,b.height)),e.drawImage(this.$clone[0],g.x,g.y,g.width,g.height,0,0,b.width,b.height),h=f.toDataURL(c,d)),h},setDragMode:function(a){var b=this.$canvas,c=this.defaults,d=f,g=f;if(this.built&&!this.disabled){switch(a){case"crop":c.dragCrop&&(d=e,b.data(k,a));break;case"move":g=e,b.data(k,a);break;default:b.removeData(k)}b.toggleClass(t,d).toggleClass(s,g)}},enable:function(){this.built&&(this.disabled=f,this.$cropper.removeClass(u))},disable:function(){this.built&&(this.disabled=e,this.$cropper.addClass(u))},rotate:function(a){var b=this.image;a=R(a)||0,this.built&&0!==a&&!this.disabled&&this.defaults.rotatable&&this.support.canvas&&(this.rotated=e,a=b.rotate=(b.rotate+a)%360,this.replace(this.getRotatedDataURL(a),!0))},getRotatedDataURL:function(b){var c=a("<canvas>")[0],d=c.getContext("2d"),e=this.originalImage,f=e.naturalWidth,g=e.naturalHeight,h=O(b)%180,i=(h>90?180-h:h)*Math.PI/180,j=f*Q(i)+g*P(i),k=f*P(i)+g*Q(i);return c.width=j,c.height=k,d.save(),d.translate(j/2,k/2),d.rotate(b*Math.PI/180),d.drawImage(this.$original[0],-f/2,-g/2,f,g),d.restore(),c.toDataURL()},zoom:function(a){var b,c,d,e=this.image;a=R(a),this.built&&a&&!this.disabled&&this.defaults.zoomable&&(b=e.width*(1+a),c=e.height*(1+a),d=b/e._width,d>10||(1>d&&(b=e._width,c=e._height),this.setDragMode(1>=d?"crop":"move"),e.oldWidth=e.width,e.oldHeight=e.height,e.width=b,e.height=c,e.ratio=e.width/e.naturalWidth,this.renderImage("zoom")))},dblclick:function(){this.disabled||this.setDragMode(this.$canvas.hasClass(t)?"move":"crop")},wheel:function(a){var b=a.originalEvent,c=1;this.disabled||(a.preventDefault(),b.deltaY?c=b.deltaY>0?1:-1:b.wheelDelta?c=-b.wheelDelta/120:b.detail&&(c=b.detail>0?1:-1),this.zoom(.1*c))},dragstart:function(b){var c,d,g,h=b.originalEvent.touches,i=b;if(!this.disabled){if(h){if(g=h.length,g>1){if(!this.defaults.zoomable||2!==g)return;i=h[1],this.startX2=i.pageX,this.startY2=i.pageY,c="zoom"}i=h[0]}if(c=c||a(i.target).data(k),m.test(c)){if(b.preventDefault(),d=a.Event(D),this.$element.trigger(d),d.isDefaultPrevented())return;this.directive=c,this.cropping=f,this.startX=i.pageX,this.startY=i.pageY,"crop"===c&&(this.cropping=e,this.$canvas.addClass(p))}}},dragmove:function(b){var c,d,e=b.originalEvent.touches,f=b;if(!this.disabled){if(e){if(d=e.length,d>1){if(!this.defaults.zoomable||2!==d)return;f=e[1],this.endX2=f.pageX,this.endY2=f.pageY}f=e[0]}if(this.directive){if(b.preventDefault(),c=a.Event(E),this.$element.trigger(c),c.isDefaultPrevented())return;this.endX=f.pageX,this.endY=f.pageY,this.dragging()}}},dragend:function(b){var c;if(!this.disabled&&this.directive){if(b.preventDefault(),c=a.Event(F),this.$element.trigger(c),c.isDefaultPrevented())return;this.cropping&&(this.cropping=f,this.$canvas.toggleClass(p,this.cropped&&this.defaults.modal)),this.directive=""}},dragging:function(){var a,b=this.directive,c=this.image,d=this.cropper,g=d.width,h=d.height,i=this.dragger,j=i.width,k=i.height,l=i.left,m=i.top,n=l+j,o=m+k,p=e,r=this.defaults.aspectRatio,s={x:this.endX-this.startX,y:this.endY-this.startY};switch(r&&(s.X=s.y*r,s.Y=s.x/r),b){case"all":l+=s.x,m+=s.y;break;case"e":if(s.x>=0&&(n>=g||r&&(0>=m||o>=h))){p=f;break}j+=s.x,r&&(k=j/r,m-=s.Y/2),0>j&&(b="w",j=0);break;case"n":if(s.y<=0&&(0>=m||r&&(0>=l||n>=g))){p=f;break}k-=s.y,m+=s.y,r&&(j=k*r,l+=s.X/2),0>k&&(b="s",k=0);break;case"w":if(s.x<=0&&(0>=l||r&&(0>=m||o>=h))){p=f;break}j-=s.x,l+=s.x,r&&(k=j/r,m+=s.Y/2),0>j&&(b="e",j=0);break;case"s":if(s.y>=0&&(o>=h||r&&(0>=l||n>=g))){p=f;break}k+=s.y,r&&(j=k*r,l-=s.X/2),0>k&&(b="n",k=0);break;case"ne":if(r){if(s.y<=0&&(0>=m||n>=g)){p=f;break}k-=s.y,m+=s.y,j=k*r}else s.x>=0?g>n?j+=s.x:s.y<=0&&0>=m&&(p=f):j+=s.x,s.y<=0?m>0&&(k-=s.y,m+=s.y):(k-=s.y,m+=s.y);0>j&&0>k?(b="sw",k=0,j=0):0>j?(b="nw",j=0):0>k&&(b="se",k=0);break;case"nw":if(r){if(s.y<=0&&(0>=m||0>=l)){p=f;break}k-=s.y,m+=s.y,j=k*r,l+=s.X}else s.x<=0?l>0?(j-=s.x,l+=s.x):s.y<=0&&0>=m&&(p=f):(j-=s.x,l+=s.x),s.y<=0?m>0&&(k-=s.y,m+=s.y):(k-=s.y,m+=s.y);0>j&&0>k?(b="se",k=0,j=0):0>j?(b="ne",j=0):0>k&&(b="sw",k=0);break;case"sw":if(r){if(s.x<=0&&(0>=l||o>=h)){p=f;break}j-=s.x,l+=s.x,k=j/r}else s.x<=0?l>0?(j-=s.x,l+=s.x):s.y>=0&&o>=h&&(p=f):(j-=s.x,l+=s.x),s.y>=0?h>o&&(k+=s.y):k+=s.y;0>j&&0>k?(b="ne",k=0,j=0):0>j?(b="se",j=0):0>k&&(b="nw",k=0);break;case"se":if(r){if(s.x>=0&&(n>=g||o>=h)){p=f;break}j+=s.x,k=j/r}else s.x>=0?g>n?j+=s.x:s.y>=0&&o>=h&&(p=f):j+=s.x,s.y>=0?h>o&&(k+=s.y):k+=s.y;0>j&&0>k?(b="nw",k=0,j=0):0>j?(b="sw",j=0):0>k&&(b="ne",k=0);break;case"move":c.left+=s.x,c.top+=s.y,this.renderImage("move"),p=f;break;case"zoom":this.zoom(function(a,b,c,d,e,f){return(L(e*e+f*f)-L(c*c+d*d))/L(a*a+b*b)}(c.width,c.height,O(this.startX-this.startX2),O(this.startY-this.startY2),O(this.endX-this.endX2),O(this.endY-this.endY2))),this.endX2=this.startX2,this.endY2=this.startY2,p=f;break;case"crop":s.x&&s.y&&(a=this.$cropper.offset(),l=this.startX-a.left,m=this.startY-a.top,j=i.minWidth,k=i.minHeight,s.x>0?s.y>0?b="se":(b="ne",m-=k):s.y>0?(b="sw",l-=j):(b="nw",l-=j,m-=k),this.cropped||(this.cropped=e,this.$dragger.removeClass(q)))}p&&(i.width=j,i.height=k,i.left=l,i.top=m,this.directive=b,this.renderDragger()),this.startX=this.endX,this.startY=this.endY}},K.TEMPLATE=function(a,b){return b=b.split(","),a.replace(/\d+/g,function(a){return b[a]})}('<0 6="5-container"><0 6="5-canvas"></0><0 6="5-dragger"><1 6="5-viewer"></1><1 6="5-8 8-h"></1><1 6="5-8 8-v"></1><1 6="5-face" 3-2="all"></1><1 6="5-7 7-e" 3-2="e"></1><1 6="5-7 7-n" 3-2="n"></1><1 6="5-7 7-w" 3-2="w"></1><1 6="5-7 7-s" 3-2="s"></1><1 6="5-4 4-e" 3-2="e"></1><1 6="5-4 4-n" 3-2="n"></1><1 6="5-4 4-w" 3-2="w"></1><1 6="5-4 4-s" 3-2="s"></1><1 6="5-4 4-ne" 3-2="ne"></1><1 6="5-4 4-nw" 3-2="nw"></1><1 6="5-4 4-sw" 3-2="sw"></1><1 6="5-4 4-se" 3-2="se"></1></0></0>',"div,span,directive,data,point,cropper,class,line,dashed"),K.DEFAULTS={aspectRatio:"auto",autoCropArea:.8,data:{},done:a.noop,preview:"",multiple:f,autoCrop:e,dragCrop:e,dashed:e,modal:e,movable:e,resizable:e,zoomable:e,rotatable:e,checkImageOrigin:e,minWidth:0,minHeight:0,maxWidth:i,maxHeight:i,minContainerWidth:300,minContainerHeight:150,build:g,built:g,dragstart:g,dragmove:g,dragend:g},K.setDefaults=function(b){a.extend(K.DEFAULTS,b)},K.other=a.fn.cropper,a.fn.cropper=function(b){var c,d=H(arguments,1);return this.each(function(){var e,f=a(this),g=f.data("cropper");g||f.data("cropper",g=new K(this,b)),"string"==typeof b&&a.isFunction(e=g[b])&&(c=e.apply(g,d))}),typeof c!==j?c:this},a.fn.cropper.Constructor=K,a.fn.cropper.setDefaults=K.setDefaults,a.fn.cropper.noConflict=function(){return a.fn.cropper=K.other,this}});
\ No newline at end of file +!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){"use strict";function i(t){return"number"==typeof t&&!isNaN(t)}function e(t){return"undefined"==typeof t}function s(t,e){var s=[];return i(e)&&s.push(e),s.slice.apply(t,s)}function o(t,i){var e=s(arguments,2);return function(){return t.apply(i,e.concat(s(arguments)))}}function h(t){var i=t.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);return i&&(i[1]!==f.protocol||i[2]!==f.hostname||i[3]!==f.port)}function a(t){var i="timestamp="+(new Date).getTime();return t+(-1===t.indexOf("?")?"?":"&")+i}function n(t){return t?' crossOrigin="'+t+'"':""}function r(t,i){var e;return t.naturalWidth?i(t.naturalWidth,t.naturalHeight):(e=document.createElement("img"),e.onload=function(){i(this.width,this.height)},void(e.src=t.src))}function p(t){var e=[],s=t.rotate,o=t.scaleX,h=t.scaleY;return i(s)&&e.push("rotate("+s+"deg)"),i(o)&&i(h)&&e.push("scale("+o+","+h+")"),e.length?e.join(" "):"none"}function c(t,i){var e,s,o=at(t.degree)%180,h=(o>90?180-o:o)*Math.PI/180,a=nt(h),n=rt(h),r=t.width,p=t.height,c=t.aspectRatio;return i?(e=r/(n+a/c),s=e/c):(e=r*n+p*a,s=r*a+p*n),{width:e,height:s}}function d(e,s){var o,h,a,n=t("<canvas>")[0],r=n.getContext("2d"),p=0,d=0,l=s.naturalWidth,g=s.naturalHeight,u=s.rotate,f=s.scaleX,m=s.scaleY,v=i(f)&&i(m)&&(1!==f||1!==m),w=i(u)&&0!==u,x=w||v,b=l,C=g;return v&&(o=l/2,h=g/2),w&&(a=c({width:l,height:g,degree:u}),b=a.width,C=a.height,o=a.width/2,h=a.height/2),n.width=b,n.height=C,x&&(p=-l/2,d=-g/2,r.save(),r.translate(o,h)),w&&r.rotate(u*Math.PI/180),v&&r.scale(f,m),r.drawImage(e,p,d,l,g),x&&r.restore(),n}function l(i,e){this.$element=t(i),this.options=t.extend({},l.DEFAULTS,t.isPlainObject(e)&&e),this.ready=!1,this.built=!1,this.complete=!1,this.rotated=!1,this.cropped=!1,this.disabled=!1,this.replaced=!1,this.isImg=!1,this.originalUrl="",this.crossOrigin="",this.canvas=null,this.cropBox=null,this.init()}var g=t(window),u=t(document),f=window.location,m="cropper",v="cropper-modal",w="cropper-hide",x="cropper-hidden",b="cropper-invisible",C="cropper-move",y="cropper-crop",B="cropper-disabled",$="cropper-bg",D="mousedown touchstart pointerdown MSPointerDown",Y="mousemove touchmove pointermove MSPointerMove",X="mouseup touchend touchcancel pointerup pointercancel MSPointerUp MSPointerCancel",T="wheel mousewheel DOMMouseScroll",k="dblclick",M="load."+m,W="error."+m,L="resize."+m,H="build."+m,R="built."+m,z="cropstart."+m,I="cropmove."+m,P="cropend."+m,E="crop."+m,F="zoom."+m,O=/^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/,S="preview",j="action",A="e",N="w",U="s",Z="n",_="se",q="sw",K="ne",Q="nw",G="all",J="crop",V="move",tt="zoom",it="none",et=t.isFunction(t("<canvas>")[0].getContext),st=Math.sqrt,ot=Math.min,ht=Math.max,at=Math.abs,nt=Math.sin,rt=Math.cos,pt=parseFloat,ct={version:"1.0.0"};t.extend(ct,{init:function(){var t,i=this.$element;if(i.is("img")){if(this.isImg=!0,this.originalUrl=t=i.attr("src"),!t)return;t=i.prop("src")}else i.is("canvas")&&et&&(t=i[0].toDataURL());this.load(t)},trigger:function(i,e){var s=t.Event(i,e);return this.$element.trigger(s),s},load:function(i){var e,s,o=this.options,r=this.$element,p="";i&&(this.url=i,r.one(H,o.build),this.trigger(H).isDefaultPrevented()||(o.checkImageOrigin&&h(i)&&(p=r.prop("crossOrigin"),p||(p="anonymous",e=a(i)),this.crossOrigin=p),this.$clone=s=t("<img"+n(p)+' src="'+(e||i)+'">'),this.isImg?r[0].complete?this.start():r.one(M,t.proxy(this.start,this)):s.one(M,t.proxy(this.start,this)).one(W,t.proxy(this.stop,this)).addClass(w).insertAfter(r)))},start:function(){var i=this.$element,e=this.$clone;this.isImg||(e.off(W,this.stop),i=e),r(i[0],t.proxy(function(t,i){this.image={naturalWidth:t,naturalHeight:i,aspectRatio:t/i},this.ready=!0,this.build()},this))},stop:function(){this.$clone.remove(),this.$clone=null}}),t.extend(ct,{build:function(){var i,e,s,o=this.options,h=this.$element,a=this.$clone;this.ready&&(this.built&&this.unbuild(),this.$container=h.parent(),this.$cropper=i=t(l.TEMPLATE),this.$canvas=i.find(".cropper-canvas").append(a),this.$dragBox=i.find(".cropper-drag-box"),this.$cropBox=e=i.find(".cropper-crop-box"),this.$viewBox=i.find(".cropper-view-box"),this.$face=s=e.find(".cropper-face"),h.addClass(x).after(i),this.isImg||a.removeClass(w),this.initPreview(),this.bind(),o.aspectRatio=pt(o.aspectRatio)||NaN,o.autoCrop?(this.cropped=!0,o.modal&&this.$dragBox.addClass(v)):e.addClass(x),o.guides||e.find(".cropper-dashed").addClass(x),o.center||e.find(".cropper-center").addClass(x),o.cropBoxMovable&&s.addClass(C).data(j,G),o.highlight||s.addClass(b),o.background&&i.addClass($),o.cropBoxResizable||e.find(".cropper-line, .cropper-point").addClass(x),this.setDragMode(o.dragCrop?J:o.movable?V:it),this.render(),this.built=!0,this.setData(o.data),h.one(R,o.built),setTimeout(t.proxy(function(){this.trigger(R),this.complete=!0},this),0))},unbuild:function(){this.built&&(this.built=!1,this.initialImage=null,this.initialCanvas=null,this.initialCropBox=null,this.container=null,this.canvas=null,this.cropBox=null,this.unbind(),this.resetPreview(),this.$preview=null,this.$viewBox=null,this.$cropBox=null,this.$dragBox=null,this.$canvas=null,this.$container=null,this.$cropper.remove(),this.$cropper=null)}}),t.extend(ct,{render:function(){this.initContainer(),this.initCanvas(),this.initCropBox(),this.renderCanvas(),this.cropped&&this.renderCropBox()},initContainer:function(){var t=this.options,i=this.$element,e=this.$container,s=this.$cropper;s.addClass(x),i.removeClass(x),s.css(this.container={width:ht(e.width(),pt(t.minContainerWidth)||200),height:ht(e.height(),pt(t.minContainerHeight)||100)}),i.addClass(x),s.removeClass(x)},initCanvas:function(){var i=this.container,e=i.width,s=i.height,o=this.image,h=o.aspectRatio,a={aspectRatio:h,width:e,height:s};s*h>e?a.height=e/h:a.width=s*h,a.oldLeft=a.left=(e-a.width)/2,a.oldTop=a.top=(s-a.height)/2,this.canvas=a,this.limitCanvas(!0,!0),this.initialImage=t.extend({},o),this.initialCanvas=t.extend({},a)},limitCanvas:function(t,i){var e,s,o=this.options,h=o.strict,a=this.container,n=a.width,r=a.height,p=this.canvas,c=p.aspectRatio,d=this.cropBox,l=this.cropped&&d,g=this.initialCanvas||p;t&&(e=pt(o.minCanvasWidth)||0,s=pt(o.minCanvasHeight)||0,h&&(e?e=ht(e,l?d.width:g.width):s?s=ht(s,l?d.height:g.height):l&&(e=d.width,s=d.height,s*c>e?e=s*c:s=e/c)),e&&s?s*c>e?s=e/c:e=s*c:e?s=e/c:s&&(e=s*c),p.minWidth=e,p.minHeight=s,p.maxWidth=1/0,p.maxHeight=1/0),i&&(h?(p.minLeft=l?ot(d.left,d.left+d.width-p.width):ot(0,n-p.width),p.minTop=l?ot(d.top,d.top+d.height-p.height):ot(0,r-p.height),p.maxLeft=l?d.left:ht(0,n-p.width),p.maxTop=l?d.top:ht(0,r-p.height)):(p.minLeft=-p.width,p.minTop=-p.height,p.maxLeft=n,p.maxTop=r))},renderCanvas:function(t){var i,e,s=this.options,o=this.canvas,h=this.image;this.rotated&&(this.rotated=!1,e=c({width:h.width,height:h.height,degree:h.rotate}),i=e.width/e.height,i!==o.aspectRatio&&(o.left-=(e.width-o.width)/2,o.top-=(e.height-o.height)/2,o.width=e.width,o.height=e.height,o.aspectRatio=i,this.limitCanvas(!0,!1))),(o.width>o.maxWidth||o.width<o.minWidth)&&(o.left=o.oldLeft),(o.height>o.maxHeight||o.height<o.minHeight)&&(o.top=o.oldTop),o.width=ot(ht(o.width,o.minWidth),o.maxWidth),o.height=ot(ht(o.height,o.minHeight),o.maxHeight),this.limitCanvas(!1,!0),o.oldLeft=o.left=ot(ht(o.left,o.minLeft),o.maxLeft),o.oldTop=o.top=ot(ht(o.top,o.minTop),o.maxTop),this.$canvas.css({width:o.width,height:o.height,left:o.left,top:o.top}),this.renderImage(),this.cropped&&s.strict&&this.limitCropBox(!0,!0),t&&this.output()},renderImage:function(i){var e,s=this.canvas,o=this.image;o.rotate&&(e=c({width:s.width,height:s.height,degree:o.rotate,aspectRatio:o.aspectRatio},!0)),t.extend(o,e?{width:e.width,height:e.height,left:(s.width-e.width)/2,top:(s.height-e.height)/2}:{width:s.width,height:s.height,left:0,top:0}),this.$clone.css({width:o.width,height:o.height,marginLeft:o.left,marginTop:o.top,transform:p(o)}),i&&this.output()},initCropBox:function(){var i=this.options,e=this.canvas,s=i.aspectRatio,o=pt(i.autoCropArea)||.8,h={width:e.width,height:e.height};s&&(e.height*s>e.width?h.height=h.width/s:h.width=h.height*s),this.cropBox=h,this.limitCropBox(!0,!0),h.width=ot(ht(h.width,h.minWidth),h.maxWidth),h.height=ot(ht(h.height,h.minHeight),h.maxHeight),h.width=ht(h.minWidth,h.width*o),h.height=ht(h.minHeight,h.height*o),h.oldLeft=h.left=e.left+(e.width-h.width)/2,h.oldTop=h.top=e.top+(e.height-h.height)/2,this.initialCropBox=t.extend({},h)},limitCropBox:function(t,i){var e,s,o,h,a=this.options,n=a.strict,r=this.container,p=r.width,c=r.height,d=this.canvas,l=this.cropBox,g=a.aspectRatio;t&&(e=pt(a.minCropBoxWidth)||0,s=pt(a.minCropBoxHeight)||0,e=ot(e,p),s=ot(s,c),o=ot(p,n?d.width:p),h=ot(c,n?d.height:c),g&&(e&&s?s*g>e?s=e/g:e=s*g:e?s=e/g:s&&(e=s*g),h*g>o?h=o/g:o=h*g),l.minWidth=ot(e,o),l.minHeight=ot(s,h),l.maxWidth=o,l.maxHeight=h),i&&(n?(l.minLeft=ht(0,d.left),l.minTop=ht(0,d.top),l.maxLeft=ot(p,d.left+d.width)-l.width,l.maxTop=ot(c,d.top+d.height)-l.height):(l.minLeft=0,l.minTop=0,l.maxLeft=p-l.width,l.maxTop=c-l.height))},renderCropBox:function(){var t=this.options,i=this.container,e=i.width,s=i.height,o=this.cropBox;(o.width>o.maxWidth||o.width<o.minWidth)&&(o.left=o.oldLeft),(o.height>o.maxHeight||o.height<o.minHeight)&&(o.top=o.oldTop),o.width=ot(ht(o.width,o.minWidth),o.maxWidth),o.height=ot(ht(o.height,o.minHeight),o.maxHeight),this.limitCropBox(!1,!0),o.oldLeft=o.left=ot(ht(o.left,o.minLeft),o.maxLeft),o.oldTop=o.top=ot(ht(o.top,o.minTop),o.maxTop),t.movable&&t.cropBoxMovable&&this.$face.data(j,o.width===e&&o.height===s?V:G),this.$cropBox.css({width:o.width,height:o.height,left:o.left,top:o.top}),this.cropped&&t.strict&&this.limitCanvas(!0,!0),this.disabled||this.output()},output:function(){this.preview(),this.complete?this.trigger(E,this.getData()):this.built||this.$element.one(R,t.proxy(function(){this.trigger(E,this.getData())},this))}}),t.extend(ct,{initPreview:function(){var i=n(this.crossOrigin),e=this.url;this.$preview=t(this.options.preview),this.$viewBox.html("<img"+i+' src="'+e+'">'),this.$preview.each(function(){var s=t(this);s.data(S,{width:s.width(),height:s.height(),original:s.html()}),s.html("<img"+i+' src="'+e+'" style="display:block;width:100%;height:auto;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation:0deg!important">')})},resetPreview:function(){this.$preview.each(function(){var i=t(this);i.html(i.data(S).original).removeData(S)})},preview:function(){var i=this.image,e=this.canvas,s=this.cropBox,o=s.width,h=s.height,a=i.width,n=i.height,r=s.left-e.left-i.left,c=s.top-e.top-i.top;this.cropped&&!this.disabled&&(this.$viewBox.find("img").css({width:a,height:n,marginLeft:-r,marginTop:-c,transform:p(i)}),this.$preview.each(function(){var e=t(this),s=e.data(S),d=s.width,l=s.height,g=d,u=l,f=1;o&&(f=d/o,u=h*f),h&&u>l&&(f=l/h,g=o*f,u=l),e.width(g).height(u).find("img").css({width:a*f,height:n*f,marginLeft:-r*f,marginTop:-c*f,transform:p(i)})}))}}),t.extend(ct,{bind:function(){var i=this.options,e=this.$element,s=this.$cropper;t.isFunction(i.cropstart)&&e.on(z,i.cropstart),t.isFunction(i.cropmove)&&e.on(I,i.cropmove),t.isFunction(i.cropend)&&e.on(P,i.cropend),t.isFunction(i.crop)&&e.on(E,i.crop),t.isFunction(i.zoom)&&e.on(F,i.zoom),s.on(D,t.proxy(this.cropStart,this)),i.zoomable&&i.mouseWheelZoom&&s.on(T,t.proxy(this.wheel,this)),i.doubleClickToggle&&s.on(k,t.proxy(this.dblclick,this)),u.on(Y,this._cropMove=o(this.cropMove,this)).on(X,this._cropEnd=o(this.cropEnd,this)),i.responsive&&g.on(L,this._resize=o(this.resize,this))},unbind:function(){var i=this.options,e=this.$element,s=this.$cropper;t.isFunction(i.cropstart)&&e.off(z,i.cropstart),t.isFunction(i.cropmove)&&e.off(I,i.cropmove),t.isFunction(i.cropend)&&e.off(P,i.cropend),t.isFunction(i.crop)&&e.off(E,i.crop),t.isFunction(i.zoom)&&e.off(F,i.zoom),s.off(D,this.cropStart),i.zoomable&&i.mouseWheelZoom&&s.off(T,this.wheel),i.doubleClickToggle&&s.off(k,this.dblclick),u.off(Y,this._cropMove).off(X,this._cropEnd),i.responsive&&g.off(L,this._resize)}}),t.extend(ct,{resize:function(){var i,e,s,o=this.$container,h=this.container;!this.disabled&&h&&(s=o.width()/h.width,(1!==s||o.height()!==h.height)&&(i=this.getCanvasData(),e=this.getCropBoxData(),this.render(),this.setCanvasData(t.each(i,function(t,e){i[t]=e*s})),this.setCropBoxData(t.each(e,function(t,i){e[t]=i*s}))))},dblclick:function(){this.disabled||(this.$dragBox.hasClass(y)?this.setDragMode(V):this.setDragMode(J))},wheel:function(t){var i=t.originalEvent,e=i,s=pt(this.options.wheelZoomRatio)||.1,o=1;this.disabled||(t.preventDefault(),e.deltaY?o=e.deltaY>0?1:-1:e.wheelDelta?o=-e.wheelDelta/120:e.detail&&(o=e.detail>0?1:-1),this.zoom(-o*s,i))},cropStart:function(i){var e,s,o=this.options,h=i.originalEvent,a=h&&h.touches,n=i;if(!this.disabled){if(a){if(e=a.length,e>1){if(!o.zoomable||!o.touchDragZoom||2!==e)return;n=a[1],this.startX2=n.pageX,this.startY2=n.pageY,s=tt}n=a[0]}if(s=s||t(n.target).data(j),O.test(s)){if(this.trigger(z,{originalEvent:h,action:s}).isDefaultPrevented())return;i.preventDefault(),this.action=s,this.cropping=!1,this.startX=n.pageX||h&&h.pageX,this.startY=n.pageY||h&&h.pageY,s===J&&(this.cropping=!0,this.$dragBox.addClass(v))}}},cropMove:function(t){var i,e=this.options,s=t.originalEvent,o=s&&s.touches,h=t,a=this.action;if(!this.disabled){if(o){if(i=o.length,i>1){if(!e.zoomable||!e.touchDragZoom||2!==i)return;h=o[1],this.endX2=h.pageX,this.endY2=h.pageY}h=o[0]}if(a){if(this.trigger(I,{originalEvent:s,action:a}).isDefaultPrevented())return;t.preventDefault(),this.endX=h.pageX||s&&s.pageX,this.endY=h.pageY||s&&s.pageY,this.change(h.shiftKey,a===tt?s:null)}}},cropEnd:function(t){var i=t.originalEvent,e=this.action;this.disabled||e&&(t.preventDefault(),this.cropping&&(this.cropping=!1,this.$dragBox.toggleClass(v,this.cropped&&this.options.modal)),this.action="",this.trigger(P,{originalEvent:i,action:e}))}}),t.extend(ct,{change:function(t,i){var e,s,o=this.options,h=o.aspectRatio,a=this.action,n=this.container,r=this.canvas,p=this.cropBox,c=p.width,d=p.height,l=p.left,g=p.top,u=l+c,f=g+d,m=0,v=0,w=n.width,b=n.height,C=!0;switch(!h&&t&&(h=c&&d?c/d:1),o.strict&&(m=p.minLeft,v=p.minTop,w=m+ot(n.width,r.width),b=v+ot(n.height,r.height)),s={x:this.endX-this.startX,y:this.endY-this.startY},h&&(s.X=s.y*h,s.Y=s.x/h),a){case G:l+=s.x,g+=s.y;break;case A:if(s.x>=0&&(u>=w||h&&(v>=g||f>=b))){C=!1;break}c+=s.x,h&&(d=c/h,g-=s.Y/2),0>c&&(a=N,c=0);break;case Z:if(s.y<=0&&(v>=g||h&&(m>=l||u>=w))){C=!1;break}d-=s.y,g+=s.y,h&&(c=d*h,l+=s.X/2),0>d&&(a=U,d=0);break;case N:if(s.x<=0&&(m>=l||h&&(v>=g||f>=b))){C=!1;break}c-=s.x,l+=s.x,h&&(d=c/h,g+=s.Y/2),0>c&&(a=A,c=0);break;case U:if(s.y>=0&&(f>=b||h&&(m>=l||u>=w))){C=!1;break}d+=s.y,h&&(c=d*h,l-=s.X/2),0>d&&(a=Z,d=0);break;case K:if(h){if(s.y<=0&&(v>=g||u>=w)){C=!1;break}d-=s.y,g+=s.y,c=d*h}else s.x>=0?w>u?c+=s.x:s.y<=0&&v>=g&&(C=!1):c+=s.x,s.y<=0?g>v&&(d-=s.y,g+=s.y):(d-=s.y,g+=s.y);0>c&&0>d?(a=q,d=0,c=0):0>c?(a=Q,c=0):0>d&&(a=_,d=0);break;case Q:if(h){if(s.y<=0&&(v>=g||m>=l)){C=!1;break}d-=s.y,g+=s.y,c=d*h,l+=s.X}else s.x<=0?l>m?(c-=s.x,l+=s.x):s.y<=0&&v>=g&&(C=!1):(c-=s.x,l+=s.x),s.y<=0?g>v&&(d-=s.y,g+=s.y):(d-=s.y,g+=s.y);0>c&&0>d?(a=_,d=0,c=0):0>c?(a=K,c=0):0>d&&(a=q,d=0);break;case q:if(h){if(s.x<=0&&(m>=l||f>=b)){C=!1;break}c-=s.x,l+=s.x,d=c/h}else s.x<=0?l>m?(c-=s.x,l+=s.x):s.y>=0&&f>=b&&(C=!1):(c-=s.x,l+=s.x),s.y>=0?b>f&&(d+=s.y):d+=s.y;0>c&&0>d?(a=K,d=0,c=0):0>c?(a=_,c=0):0>d&&(a=Q,d=0);break;case _:if(h){if(s.x>=0&&(u>=w||f>=b)){C=!1;break}c+=s.x,d=c/h}else s.x>=0?w>u?c+=s.x:s.y>=0&&f>=b&&(C=!1):c+=s.x,s.y>=0?b>f&&(d+=s.y):d+=s.y;0>c&&0>d?(a=Q,d=0,c=0):0>c?(a=q,c=0):0>d&&(a=K,d=0);break;case V:this.move(s.x,s.y),C=!1;break;case tt:this.zoom(function(t,i,e,s){var o=st(t*t+i*i),h=st(e*e+s*s);return(h-o)/o}(at(this.startX-this.startX2),at(this.startY-this.startY2),at(this.endX-this.endX2),at(this.endY-this.endY2)),i),this.startX2=this.endX2,this.startY2=this.endY2,C=!1;break;case J:s.x&&s.y&&(e=this.$cropper.offset(),l=this.startX-e.left,g=this.startY-e.top,c=p.minWidth,d=p.minHeight,s.x>0?s.y>0?a=_:(a=K,g-=d):s.y>0?(a=q,l-=c):(a=Q,l-=c,g-=d),this.cropped||(this.cropped=!0,this.$cropBox.removeClass(x)))}C&&(p.width=c,p.height=d,p.left=l,p.top=g,this.action=a,this.renderCropBox()),this.startX=this.endX,this.startY=this.endY}}),t.extend(ct,{crop:function(){this.built&&!this.disabled&&(this.cropped||(this.cropped=!0,this.limitCropBox(!0,!0),this.options.modal&&this.$dragBox.addClass(v),this.$cropBox.removeClass(x)),this.setCropBoxData(this.initialCropBox))},reset:function(){this.built&&!this.disabled&&(this.image=t.extend({},this.initialImage),this.canvas=t.extend({},this.initialCanvas),this.cropBox=t.extend({},this.initialCropBox),this.renderCanvas(),this.cropped&&this.renderCropBox())},clear:function(){this.cropped&&!this.disabled&&(t.extend(this.cropBox,{left:0,top:0,width:0,height:0}),this.cropped=!1,this.renderCropBox(),this.limitCanvas(!0,!0),this.renderCanvas(),this.$dragBox.removeClass(v),this.$cropBox.addClass(x))},replace:function(t){!this.disabled&&t&&(this.isImg&&(this.replaced=!0,this.$element.attr("src",t)),this.options.data=null,this.load(t))},enable:function(){this.built&&(this.disabled=!1,this.$cropper.removeClass(B))},disable:function(){this.built&&(this.disabled=!0,this.$cropper.addClass(B))},destroy:function(){var t=this.$element;this.ready?(this.isImg&&this.replaced&&t.attr("src",this.originalUrl),this.unbuild(),t.removeClass(x)):this.isImg?t.off(M,this.start):this.$clone&&this.$clone.remove(),t.removeData(m)},move:function(t,s){var o=this.canvas;e(s)&&(s=t),t=pt(t),s=pt(s),this.built&&!this.disabled&&this.options.movable&&(o.left+=i(t)?t:0,o.top+=i(s)?s:0,this.renderCanvas(!0))},zoom:function(t,i){var e,s,o=this.canvas;if(t=pt(t),t&&this.built&&!this.disabled&&this.options.zoomable){if(this.trigger(F,{originalEvent:i,ratio:t}).isDefaultPrevented())return;t=0>t?1/(1-t):1+t,e=o.width*t,s=o.height*t,o.left-=(e-o.width)/2,o.top-=(s-o.height)/2,o.width=e,o.height=s,this.renderCanvas(!0),this.setDragMode(V)}},rotate:function(t){var i=this.image,e=i.rotate||0;t=pt(t)||0,this.built&&!this.disabled&&this.options.rotatable&&(i.rotate=(e+t)%360,this.rotated=!0,this.renderCanvas(!0))},scale:function(t,s){var o=this.image;e(s)&&(s=t),t=pt(t),s=pt(s),this.built&&!this.disabled&&this.options.scalable&&(o.scaleX=i(t)?t:1,o.scaleY=i(s)?s:1,this.renderImage(!0))},getData:function(i){var e,s,o=this.options,h=this.image,a=this.canvas,n=this.cropBox;return this.built&&this.cropped?(s={x:n.left-a.left,y:n.top-a.top,width:n.width,height:n.height},e=h.width/h.naturalWidth,t.each(s,function(t,o){o/=e,s[t]=i?Math.round(o):o})):s={x:0,y:0,width:0,height:0},o.rotatable&&(s.rotate=h.rotate||0),o.scalable&&(s.scaleX=h.scaleX||1,s.scaleY=h.scaleY||1),s},setData:function(e){var s,o,h,a=this.options,n=this.image,r=this.canvas,p={};t.isFunction(e)&&(e=e.call(this.element)),this.built&&!this.disabled&&t.isPlainObject(e)&&(a.rotatable&&i(e.rotate)&&e.rotate!==n.rotate&&(n.rotate=e.rotate,this.rotated=s=!0),a.scalable&&(i(e.scaleX)&&e.scaleX!==n.scaleX&&(n.scaleX=e.scaleX,o=!0),i(e.scaleY)&&e.scaleY!==n.scaleY&&(n.scaleY=e.scaleY,o=!0)),s?this.renderCanvas():o&&this.renderImage(),h=n.width/n.naturalWidth,i(e.x)&&(p.left=e.x*h+r.left),i(e.y)&&(p.top=e.y*h+r.top),i(e.width)&&(p.width=e.width*h),i(e.height)&&(p.height=e.height*h),this.setCropBoxData(p))},getContainerData:function(){return this.built?this.container:{}},getImageData:function(){return this.ready?this.image:{}},getCanvasData:function(){var t,i=this.canvas;return this.built&&(t={left:i.left,top:i.top,width:i.width,height:i.height}),t||{}},setCanvasData:function(e){var s=this.canvas,o=s.aspectRatio;t.isFunction(e)&&(e=e.call(this.$element)),this.built&&!this.disabled&&t.isPlainObject(e)&&(i(e.left)&&(s.left=e.left),i(e.top)&&(s.top=e.top),i(e.width)?(s.width=e.width,s.height=e.width/o):i(e.height)&&(s.height=e.height,s.width=e.height*o),this.renderCanvas(!0))},getCropBoxData:function(){var t,i=this.cropBox;return this.built&&this.cropped&&(t={left:i.left,top:i.top,width:i.width,height:i.height}),t||{}},setCropBoxData:function(e){var s,o,h=this.cropBox,a=this.options.aspectRatio;t.isFunction(e)&&(e=e.call(this.$element)),this.built&&this.cropped&&!this.disabled&&t.isPlainObject(e)&&(i(e.left)&&(h.left=e.left),i(e.top)&&(h.top=e.top),i(e.width)&&e.width!==h.width&&(s=!0,h.width=e.width),i(e.height)&&e.height!==h.height&&(o=!0,h.height=e.height),a&&(s?h.height=h.width/a:o&&(h.width=h.height*a)),this.renderCropBox())},getCroppedCanvas:function(i){var e,s,o,h,a,n,r,p,c,l,g;return this.built&&this.cropped&&et?(t.isPlainObject(i)||(i={}),g=this.getData(),e=g.width,s=g.height,p=e/s,t.isPlainObject(i)&&(a=i.width,n=i.height,a?(n=a/p,r=a/e):n&&(a=n*p,r=n/s)),o=a||e,h=n||s,c=t("<canvas>")[0],c.width=o,c.height=h,l=c.getContext("2d"),i.fillColor&&(l.fillStyle=i.fillColor,l.fillRect(0,0,o,h)),l.drawImage.apply(l,function(){var t,i,o,h,a,n,p=d(this.$clone[0],this.image),c=p.width,l=p.height,u=[p],f=g.x,m=g.y;return-e>=f||f>c?f=t=o=a=0:0>=f?(o=-f,f=0,t=a=ot(c,e+f)):c>=f&&(o=0,t=a=ot(e,c-f)),0>=t||-s>=m||m>l?m=i=h=n=0:0>=m?(h=-m,m=0,i=n=ot(l,s+m)):l>=m&&(h=0,i=n=ot(s,l-m)),u.push(f,m,t,i),r&&(o*=r,h*=r,a*=r,n*=r),a>0&&n>0&&u.push(o,h,a,n),u}.call(this)),c):void 0},setAspectRatio:function(t){var i=this.options;this.disabled||e(t)||(i.aspectRatio=pt(t)||NaN,this.built&&(this.initCropBox(),this.cropped&&this.renderCropBox()))},setDragMode:function(t){var i,e,s=this.options;this.ready&&!this.disabled&&(i=s.dragCrop&&t===J,e=s.movable&&t===V,t=i||e?t:it,this.$dragBox.data(j,t).toggleClass(y,i).toggleClass(C,e),s.cropBoxMovable||this.$face.data(j,t).toggleClass(y,i).toggleClass(C,e))}}),t.extend(l.prototype,ct),l.DEFAULTS={aspectRatio:NaN,data:null,preview:"",strict:!0,responsive:!0,checkImageOrigin:!0,modal:!0,guides:!0,center:!0,highlight:!0,background:!0,autoCrop:!0,autoCropArea:.8,dragCrop:!0,movable:!0,rotatable:!0,scalable:!0,zoomable:!0,mouseWheelZoom:!0,wheelZoomRatio:.1,touchDragZoom:!0,cropBoxMovable:!0,cropBoxResizable:!0,doubleClickToggle:!0,minCanvasWidth:0,minCanvasHeight:0,minCropBoxWidth:0,minCropBoxHeight:0,minContainerWidth:200,minContainerHeight:100,build:null,built:null,cropstart:null,cropmove:null,cropend:null,crop:null,zoom:null},l.setDefaults=function(i){t.extend(l.DEFAULTS,i)},l.TEMPLATE='<div class="cropper-container"><div class="cropper-canvas"></div><div class="cropper-drag-box"></div><div class="cropper-crop-box"><span class="cropper-view-box"></span><span class="cropper-dashed dashed-h"></span><span class="cropper-dashed dashed-v"></span><span class="cropper-center"></span><span class="cropper-face"></span><span class="cropper-line line-e" data-action="e"></span><span class="cropper-line line-n" data-action="n"></span><span class="cropper-line line-w" data-action="w"></span><span class="cropper-line line-s" data-action="s"></span><span class="cropper-point point-e" data-action="e"></span><span class="cropper-point point-n" data-action="n"></span><span class="cropper-point point-w" data-action="w"></span><span class="cropper-point point-s" data-action="s"></span><span class="cropper-point point-ne" data-action="ne"></span><span class="cropper-point point-nw" data-action="nw"></span><span class="cropper-point point-sw" data-action="sw"></span><span class="cropper-point point-se" data-action="se"></span></div></div>',l.other=t.fn.cropper,t.fn.cropper=function(i){var o,h=s(arguments,1);return this.each(function(){var e,s=t(this),a=s.data(m);if(!a){if(/destroy/.test(i))return;s.data(m,a=new l(this,i))}"string"==typeof i&&t.isFunction(e=a[i])&&(o=e.apply(a,h))}),e(o)?this:o},t.fn.cropper.Constructor=l,t.fn.cropper.setDefaults=l.setDefaults,t.fn.cropper.noConflict=function(){return t.fn.cropper=l.other,this}});
\ No newline at end of file |
