| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573 |
- (function (factory) {
- if (typeof define === "function" && define.amd) {
- // AMD. Register as anonymous module.
- define(["jquery"], factory);
- } else if (typeof exports === "object") {
- // Node / CommonJS
- factory(require("jquery"));
- } else {
- // Browser globals.
- factory(jQuery);
- }
- })(function ($) {
-
- "use strict";
-
- var $window = $(window),
- $document = $(document),
- location = window.location,
-
- // Constants
- TRUE = true,
- FALSE = false,
- NULL = null,
- NAN = NaN,
- INFINITY = Infinity,
- STRING_UNDEFINED = "undefined",
- STRING_DIRECTIVE = "directive",
- CROPPER_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
- 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
- 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,
-
- // Functions
- isNumber = function (n) {
- return typeof n === "number";
- },
-
- toArray = function (obj, offset) {
- var args = [];
-
- if (typeof offset === "number") { // It's necessary for IE8
- args.push(offset);
- }
-
- return args.slice.apply(obj, args);
- },
-
- // Custom proxy to avoid jQuery's guid
- proxy = function (fn, context) {
- var args = toArray(arguments, 2);
-
- return function () {
- return fn.apply(context, args.concat(toArray(arguments)));
- };
- },
-
- // 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();
- },
-
- // Others
- sqrt = Math.sqrt,
- min = Math.min,
- max = Math.max,
- abs = Math.abs,
- sin = Math.sin,
- cos = Math.cos,
- num = parseFloat;
-
- Cropper.prototype = {
- constructor: Cropper,
-
- support: {
- canvas: $.isFunction($("<canvas>")[0].getContext)
- },
-
- init: function () {
- var defaults = this.defaults;
-
- $.each(defaults, function (i, n) {
- switch (i) {
- case "aspectRatio":
- defaults[i] = abs(num(n)) || NAN; // 0 -> NaN
- break;
-
- case "autoCropArea":
- defaults[i] = abs(num(n)) || 0.8; // 0 | NaN -> 0.8
- break;
-
- case "minWidth":
- case "minHeight":
- defaults[i] = abs(num(n)) || 0; // NaN -> 0
- break;
-
- case "maxWidth":
- case "maxHeight":
- defaults[i] = abs(num(n)) || INFINITY; // 0 | NaN -> Infinity
- break;
-
- // No default
- }
- });
-
- // Set default image data
- this.image = {
- rotate: 0
- };
-
- this.load();
- },
-
- load: function () {
- var _this = this,
- $this = this.$element,
- element = this.element,
- image = this.image,
- crossOrigin = "",
- $clone,
- url;
-
- if ($this.is("img")) {
- url = $this.prop("src");
- } else if ($this.is("canvas") && this.support.canvas) {
- url = element.toDataURL();
- }
-
- if (!url) {
- return;
- }
-
- // Reset image rotate degree
- if (this.replaced) {
- image.rotate = 0;
- }
-
- if (this.defaults.checkImageOrigin) {
- if ($this.prop("crossOrigin") || this.isCrossOriginURL(url)) {
- crossOrigin = " crossOrigin";
- }
- }
-
- this.$clone = ($clone = $("<img" + crossOrigin + ' src="' + url + '">'));
-
- $clone.one("load", function () {
- image.naturalWidth = this.naturalWidth || $clone.width();
- image.naturalHeight = this.naturalHeight || $clone.height();
- image.aspectRatio = image.naturalWidth / image.naturalHeight;
-
- _this.url = url;
- _this.ready = TRUE;
- _this.build();
- });
-
- // Hide and prepend the clone iamge to the document body (Don't append to).
- $clone.addClass(CLASS_INVISIBLE).prependTo("body");
- },
-
- isCrossOriginURL: function (url) {
- var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);
-
- if ((parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port))) {
- return TRUE;
- }
-
- return FALSE;
- },
-
- build: function () {
- var $this = this.$element,
- defaults = this.defaults,
- buildEvent,
- $cropper;
-
- if (!this.ready) {
- return;
- }
-
- if (this.built) {
- this.unbuild();
- }
-
- $this.one(EVENT_BUILD, defaults.build); // Only trigger once
- buildEvent = $.Event(EVENT_BUILD);
- $this.trigger(buildEvent);
-
- if (buildEvent.isDefaultPrevented()) {
- return;
- }
-
- // Create cropper elements
- this.$cropper = ($cropper = $(Cropper.TEMPLATE));
-
- // Hide the original image
- $this.addClass(CLASS_HIDDEN);
-
- // Show and prepend the clone iamge to the cropper
- this.$clone.removeClass(CLASS_INVISIBLE).prependTo($cropper);
-
- // Save original image for rotation
- if (!this.rotated) {
- this.$original = this.$clone.clone();
-
- // 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);
-
- this.originalImage = $.extend({}, this.image);
- }
-
- this.$container = $this.parent();
- this.$container.append($cropper);
-
- this.$canvas = $cropper.find(".cropper-canvas");
- this.$dragger = $cropper.find(".cropper-dragger");
- this.$viewer = $cropper.find(".cropper-viewer");
-
- defaults.autoCrop ? (this.cropped = TRUE) : this.$dragger.addClass(CLASS_HIDDEN);
- defaults.dragCrop && this.setDragMode("crop");
- 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.addListeners();
- this.initPreview();
-
- this.built = TRUE; // Set `true` before update
- this.update();
- this.replaced = FALSE; // Reset to `false` after update
-
- $this.one(EVENT_BUILT, defaults.built); // Only trigger once
- $this.trigger(EVENT_BUILT);
- },
-
- unbuild: function () {
- if (!this.built) {
- return;
- }
-
- this.built = FALSE;
- this.removeListeners();
-
- this.$preview.empty();
- this.$preview = NULL;
-
- this.$dragger = NULL;
- this.$canvas = NULL;
- this.$container = NULL;
-
- this.$cropper.remove();
- this.$cropper = NULL;
- },
-
- update: function (data) {
- this.initContainer();
- this.initCropper();
- this.initImage();
- this.initDragger();
-
- if (data) {
- this.setData(data, TRUE);
- this.setDragMode("crop");
- } else {
- this.setData(this.defaults.data);
- }
- },
-
- resize: function () {
- clearTimeout(this.resizing);
- this.resizing = setTimeout($.proxy(this.update, this, this.getData()), 200);
- },
-
- 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;
-
- this.$viewer.find("img").css({
- width: width,
- height: height,
- marginLeft: -left,
- marginTop: -top
- });
-
- this.$preview.each(function () {
- var $this = $(this),
- ratio = $this.width() / dragger.width;
-
- $this.find("img").css({
- width: width * ratio,
- height: height * ratio,
- marginLeft: -left * ratio,
- marginTop: -top * ratio
- });
- });
- },
-
- addListeners: function () {
- var defaults = this.defaults;
-
- 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));
-
- if (defaults.zoomable) {
- this.$cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this));
- }
-
- if (defaults.multiple) {
- this.$cropper.on(EVENT_MOUSE_MOVE, $.proxy(this.dragmove, this)).on(EVENT_MOUSE_UP, $.proxy(this.dragend, this));
- } else {
- $document.on(EVENT_MOUSE_MOVE, (this._dragmove = proxy(this.dragmove, this))).on(EVENT_MOUSE_UP, (this._dragend = proxy(this.dragend, this)));
- }
-
- $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this)));
- },
-
- removeListeners: function () {
- var defaults = this.defaults;
-
- 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 (defaults.zoomable) {
- this.$cropper.off(EVENT_WHEEL, this.wheel);
- }
-
- 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);
- }
-
- $window.off(EVENT_RESIZE, this._resize);
- },
-
- initPreview: function () {
- var img = '<img src="' + this.url + '">';
-
- this.$preview = $(this.defaults.preview);
- this.$viewer.html(img);
- this.$preview.html(img).find("img").css("cssText", "min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;");
- },
-
- initContainer: function () {
- var $container = this.$container;
- if($container !== NULL){
- this.container = {
- width: max($container.width(), 300),
- height: max($container.height(), 150)
- };
- }
- },
-
- 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
- };
-
- cropper.top = (container.height - cropper.height) / 2;
- } else {
- cropper = {
- width: container.height * image.aspectRatio,
- height: container.height,
- top: 0
- };
-
- cropper.left = (container.width - cropper.width) / 2;
- }
-
- if ( this.$cropper ) {
- this.$cropper.css({
- width: cropper.width,
- height: cropper.height,
- left: cropper.left,
- top: cropper.top
- });
- }
-
- this.cropper = cropper;
- },
-
- 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
- };
-
- this.defaultImage = $.extend({}, image, defaultImage);
-
- if (image._width !== cropper.width || image._height !== cropper.height) {
- $.extend(image, defaultImage);
- } else {
- image = $.extend({}, defaultImage, image);
-
- // Reset image ratio
- if (this.replaced) {
- image.ratio = defaultImage.ratio;
- }
- }
-
- this.image = image;
- this.renderImage();
- },
-
- renderImage: function (mode) {
- var image = this.image;
-
- if (mode === "zoom") {
- image.left -= (image.width - image.oldWidth) / 2;
- image.top -= (image.height - image.oldHeight) / 2;
- }
-
- 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();
- }
- },
-
- 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,
- dragger;
-
- 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
- };
- }
-
- dragger.minWidth = 0;
- dragger.minHeight = 0;
-
- 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;
- }
-
- 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;
- }
- } 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);
-
- // Center the dragger by default
- dragger.height *= defaults.autoCropArea;
- dragger.width *= defaults.autoCropArea;
- dragger.left = (cropper.width - dragger.width) / 2;
- dragger.top = (cropper.height - dragger.height) / 2;
- dragger.oldLeft = dragger.left;
- dragger.oldTop = dragger.top;
-
- this.defaultDragger = dragger;
- this.dragger = $.extend({}, dragger);
- },
-
- renderDragger: function () {
- var dragger = this.dragger,
- cropper = this.cropper;
-
- 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;
- }
-
- 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;
- }
-
- 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;
-
- // Re-render the dragger
- this.dragger = dragger;
-
- if (!this.disabled) {
- this.defaults.done(this.getData());
- }
-
- this.$dragger.css({
- width: dragger.width,
- height: dragger.height,
- left: dragger.left,
- top: dragger.top
- });
-
- this.preview();
- },
-
- reset: function (deep) {
- if (!this.cropped) {
- return;
- }
-
- if (deep) {
- this.defaults.data = {};
- }
-
- this.image = $.extend({}, this.defaultImage);
- this.renderImage();
- this.dragger = $.extend({}, this.defaultDragger);
- this.setData(this.defaults.data);
- },
-
- clear: function () {
- if (!this.cropped) {
- return;
- }
-
- this.cropped = FALSE;
-
- this.setData({
- x: 0,
- y: 0,
- width: 0,
- height: 0
- });
-
- this.$canvas.removeClass(CLASS_MODAL);
- this.$dragger.addClass(CLASS_HIDDEN);
- },
-
- destroy: function () {
- var $this = this.$element;
-
- if (!this.ready) {
- return;
- }
-
- this.unbuild();
- $this.removeClass(CLASS_HIDDEN).removeData("cropper");
-
- 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 (url && url !== this.url && url !== $this.attr("src")) {
- if (!rotated) {
- this.rotated = FALSE;
- this.replaced = TRUE;
- }
-
- if ($this.is("img")) {
- $this.attr("src", url);
- this.load();
- } else if ($this.is("canvas") && this.support.canvas) {
- context = element.getContext("2d");
-
- $('<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();
- });
- }
- }
- },
-
- setData: function (data, /*INTERNAL*/ once) {
- var cropper = this.cropper,
- dragger = this.dragger,
- image = this.image,
- aspectRatio = this.defaults.aspectRatio;
-
- if (!this.built || typeof data === STRING_UNDEFINED) {
- return;
- }
-
- if (data === NULL || $.isEmptyObject(data)) {
- dragger = $.extend({}, this.defaultDragger);
- }
-
- if ($.isPlainObject(data) && !$.isEmptyObject(data)) {
-
- if (!once) {
- this.defaults.data = data;
- }
-
- data = this.transformData(data);
-
- if (isNumber(data.x) && data.x <= cropper.width - image.left) {
- dragger.left = data.x + image.left;
- }
-
- if (isNumber(data.y) && data.y <= cropper.height - image.top) {
- dragger.top = data.y + image.top;
- }
-
- 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;
- }
-
- if (isNumber(data.height) && data.height <= dragger.maxHeight && data.height >= dragger.minHeight) {
- dragger.height = data.height;
- }
- }
- }
-
- this.dragger = dragger;
- this.renderDragger();
- },
-
- getData: function (rounded) {
- var dragger = this.dragger,
- image = this.image,
- data = {};
-
- if (this.built) {
- data = {
- x: dragger.left - image.left,
- y: dragger.top - image.top,
- width: dragger.width,
- height: dragger.height
- };
-
- data = this.transformData(data, TRUE, rounded);
- }
-
- return data;
- },
-
- transformData: function (data, reversed, rounded) {
- var ratio = this.image.ratio,
- result = {};
-
- $.each(data, function (i, n) {
- n = num(n);
-
- if (REGEXP_OPTIONS.test(i) && !isNaN(n)) {
- result[i] = reversed ? (rounded ? Math.round(n / ratio) : n / ratio) : n * ratio;
- }
- });
-
- return result;
- },
-
- setAspectRatio: function (aspectRatio) {
- var freeRatio = aspectRatio === "auto";
-
- aspectRatio = num(aspectRatio);
-
- if (freeRatio || (!isNaN(aspectRatio) && aspectRatio > 0)) {
- this.defaults.aspectRatio = freeRatio ? NAN : aspectRatio;
-
- if (this.built) {
- this.initDragger();
- this.renderDragger();
- }
- }
- },
-
- getImageData: function () {
- var data = {};
-
- if (this.ready) {
- $.each(this.image, function (name, value) {
- if (REGEXP_PROPERTIES.test(name)) {
- data[name] = value;
- }
- });
- }
-
- return data;
- },
-
- getDataURL: function (options, type, quality) {
- var canvas = $("<canvas>")[0],
- data = this.getData(),
- dataURL = "",
- context;
-
- if (!$.isPlainObject(options)) {
- quality = type;
- type = options;
- options = {};
- }
-
- 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);
- }
-
- return dataURL;
- },
-
- setDragMode: function (mode) {
- var $canvas = this.$canvas,
- defaults = this.defaults,
- cropable = FALSE,
- movable = FALSE;
-
- if (!this.built || this.disabled) {
- return;
- }
-
- switch (mode) {
- case "crop":
- if (defaults.dragCrop) {
- cropable = TRUE;
- $canvas.data(STRING_DIRECTIVE, mode);
- }
-
- break;
-
- case "move":
- movable = TRUE;
- $canvas.data(STRING_DIRECTIVE, mode);
-
- break;
-
- default:
- $canvas.removeData(STRING_DIRECTIVE);
- }
-
- $canvas.toggleClass(CLASS_CROP, cropable).toggleClass(CLASS_MOVE, movable);
- },
-
- enable: function () {
- if (this.built) {
- this.disabled = FALSE;
- this.$cropper.removeClass(CLASS_DISABLED);
- }
- },
-
- disable: function () {
- if (this.built) {
- this.disabled = TRUE;
- this.$cropper.addClass(CLASS_DISABLED);
- }
- },
-
- rotate: function (degree) {
- var image = this.image;
-
- degree = num(degree) || 0;
-
- if (!this.built || degree === 0 || this.disabled || !this.defaults.rotatable || !this.support.canvas) {
- return;
- }
-
- 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);
- },
-
- getRotatedDataURL: function (degree) {
- var canvas = $("<canvas>")[0],
- context = canvas.getContext("2d"),
- arc = degree * Math.PI / 180,
- deg = abs(degree) % 180,
- acuteAngle = deg > 90 ? (180 - deg) : deg,
- acuteAngleArc = acuteAngle * Math.PI / 180,
- originalImage = this.originalImage,
- naturalWidth = originalImage.naturalWidth,
- naturalHeight = originalImage.naturalHeight,
- width = abs(naturalWidth * cos(acuteAngleArc) + naturalHeight * sin(acuteAngleArc)),
- height = abs(naturalWidth * sin(acuteAngleArc) + naturalHeight * cos(acuteAngleArc));
-
- canvas.width = width;
- canvas.height = height;
- context.save();
- context.translate(width / 2, height / 2);
- context.rotate(arc);
- context.drawImage(this.$original[0], -naturalWidth / 2, -naturalHeight / 2, naturalWidth, naturalHeight);
- context.restore();
-
- return canvas.toDataURL();
- },
-
- zoom: function (delta) {
- var image = this.image,
- width,
- height,
- range;
-
- delta = num(delta);
-
- if (!this.built || !delta || this.disabled || !this.defaults.zoomable) {
- return;
- }
-
- width = image.width * (1 + delta);
- height = image.height * (1 + delta);
- range = width / image._width;
-
- if (range > 10) {
- return;
- }
-
- if (range < 1) {
- width = image._width;
- height = image._height;
- }
-
- if (range <= 1) {
- this.setDragMode("crop");
- } else {
- this.setDragMode("move");
- }
-
- image.oldWidth = image.width;
- image.oldHeight = image.height;
-
- image.width = width;
- image.height = height;
- image.ratio = image.width / image.naturalWidth;
-
- this.renderImage("zoom");
- },
-
- dblclick: function () {
- if (this.disabled) {
- return;
- }
-
- if (this.$canvas.hasClass(CLASS_CROP)) {
- this.setDragMode("move");
- } else {
- this.setDragMode("crop");
- }
- },
-
- wheel: function (event) {
- var e = event.originalEvent,
- msDeltaY = 117.25, // IE
- mozDelatY = 5, // Firefox
- webkitDelatY = 166.66665649414062, // Chrome, Opera
- zoomDelta = 0.1, // 10%
- delta;
-
- if (this.disabled) {
- return;
- }
-
- event.preventDefault();
-
- if (e.deltaY) {
- delta = e.deltaY;
- delta = delta % mozDelatY === 0 ? delta / mozDelatY : delta % msDeltaY === 0 ? delta / msDeltaY : delta / webkitDelatY;
- } else {
- delta = e.wheelDelta ? -e.wheelDelta / 120 : (e.detail ? e.detail / 3 : 0);
- }
-
- this.zoom(delta * zoomDelta);
- },
-
- dragstart: function (event) {
- var touches = event.originalEvent.touches,
- e = event,
- directive,
- dragStartEvent,
- touchesLength;
-
- if (this.disabled) {
- return;
- }
-
- if (touches) {
- touchesLength = touches.length;
-
- if (touchesLength > 1) {
- if (this.defaults.zoomable && touchesLength === 2) {
- e = touches[1];
- this.startX2 = e.pageX;
- this.startY2 = e.pageY;
- directive = "zoom";
- } else {
- return;
- }
- }
-
- 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);
-
- if (dragStartEvent.isDefaultPrevented()) {
- return;
- }
-
- this.directive = directive;
- this.cropping = FALSE;
- this.startX = e.pageX;
- this.startY = e.pageY;
-
- if (directive === "crop") {
- this.cropping = TRUE;
- this.$canvas.addClass(CLASS_MODAL);
- }
- }
- },
-
- dragmove: function (event) {
- var touches = event.originalEvent.touches,
- e = event,
- dragMoveEvent,
- touchesLength;
-
- if (this.disabled) {
- return;
- }
-
- if (touches) {
- touchesLength = touches.length;
-
- if (touchesLength > 1) {
- if (this.defaults.zoomable && touchesLength === 2) {
- e = touches[1];
- this.endX2 = e.pageX;
- this.endY2 = e.pageY;
- } else {
- return;
- }
- }
-
- e = touches[0];
- }
-
- if (this.directive) {
- event.preventDefault();
-
- dragMoveEvent = $.Event(EVENT_DRAG_MOVE);
- this.$element.trigger(dragMoveEvent);
-
- if (dragMoveEvent.isDefaultPrevented()) {
- return;
- }
-
- this.endX = e.pageX;
- this.endY = e.pageY;
-
- this.dragging();
- }
- },
-
- dragend: function (event) {
- var dragEndEvent;
-
- if (this.disabled) {
- return;
- }
-
- if (this.directive) {
- 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.directive = "";
- }
- },
-
- 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,
- defaults = this.defaults,
- aspectRatio = defaults.aspectRatio,
- range = {
- x: this.endX - this.startX,
- y: this.endY - this.startY
- },
- offset;
-
- if (aspectRatio) {
- range.X = range.y * aspectRatio;
- range.Y = range.x / aspectRatio;
- }
-
- switch (directive) {
- // Move dragger
- case "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;
- break;
- }
-
- width += range.x;
-
- if (aspectRatio) {
- height = width / aspectRatio;
- top -= range.Y / 2;
- }
-
- if (width < 0) {
- directive = "w";
- width = 0;
- }
-
- break;
-
- case "n":
- if (range.y <= 0 && (top <= 0 || aspectRatio && (left <= 0 || right >= maxWidth))) {
- renderable = FALSE;
- break;
- }
-
- height -= range.y;
- top += range.y;
-
- if (aspectRatio) {
- width = height * aspectRatio;
- left += range.X / 2;
- }
-
- if (height < 0) {
- directive = "s";
- height = 0;
- }
-
- break;
-
- case "w":
- if (range.x <= 0 && (left <= 0 || aspectRatio && (top <= 0 || bottom >= maxHeight))) {
- renderable = FALSE;
- break;
- }
-
- width -= range.x;
- left += range.x;
-
- if (aspectRatio) {
- height = width / aspectRatio;
- top += range.Y / 2;
- }
-
- if (width < 0) {
- directive = "e";
- width = 0;
- }
-
- break;
-
- case "s":
- if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= 0 || right >= maxWidth))) {
- renderable = FALSE;
- break;
- }
-
- height += range.y;
-
- if (aspectRatio) {
- width = height * aspectRatio;
- left -= range.X / 2;
- }
-
- if (height < 0) {
- directive = "n";
- height = 0;
- }
-
- break;
-
- case "ne":
- if (aspectRatio) {
- if (range.y <= 0 && (top <= 0 || right >= maxWidth)) {
- renderable = FALSE;
- break;
- }
-
- height -= range.y;
- top += range.y;
- width = height * aspectRatio;
- } else {
- if (range.x >= 0) {
- if (right < maxWidth) {
- width += range.x;
- } else if (range.y <= 0 && top <= 0) {
- renderable = FALSE;
- }
- } else {
- width += range.x;
- }
-
- if (range.y <= 0) {
- if (top > 0) {
- height -= range.y;
- top += range.y;
- }
- } else {
- height -= range.y;
- top += range.y;
- }
- }
-
- if (height < 0) {
- directive = "sw";
- height = 0;
- width = 0;
- }
-
- break;
-
- case "nw":
- if (aspectRatio) {
- if (range.y <= 0 && (top <= 0 || left <= 0)) {
- renderable = FALSE;
- break;
- }
-
- height -= range.y;
- top += range.y;
- width = height * aspectRatio;
- left += range.X;
- } else {
- if (range.x <= 0) {
- if (left > 0) {
- width -= range.x;
- left += range.x;
- } else if (range.y <= 0 && top <= 0) {
- renderable = FALSE;
- }
- } else {
- width -= range.x;
- left += range.x;
- }
-
- if (range.y <= 0) {
- if (top > 0) {
- height -= range.y;
- top += range.y;
- }
- } else {
- height -= range.y;
- top += range.y;
- }
- }
-
- if (height < 0) {
- directive = "se";
- height = 0;
- width = 0;
- }
-
- break;
-
- case "sw":
- if (aspectRatio) {
- if (range.x <= 0 && (left <= 0 || bottom >= maxHeight)) {
- renderable = FALSE;
- break;
- }
-
- width -= range.x;
- left += range.x;
- height = width / aspectRatio;
- } else {
- if (range.x <= 0) {
- if (left > 0) {
- width -= range.x;
- left += range.x;
- } else if (range.y >= 0 && bottom >= maxHeight) {
- renderable = FALSE;
- }
- } else {
- width -= range.x;
- left += range.x;
- }
-
- if (range.y >= 0) {
- if (bottom < maxHeight) {
- height += range.y;
- }
- } else {
- height += range.y;
- }
- }
-
- if (width < 0) {
- directive = "ne";
- height = 0;
- width = 0;
- }
-
- break;
-
- case "se":
- if (aspectRatio) {
- if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {
- renderable = FALSE;
- break;
- }
-
- width += range.x;
- height = width / aspectRatio;
- } else {
- if (range.x >= 0) {
- if (right < maxWidth) {
- width += range.x;
- } else if (range.y >= 0 && bottom >= maxHeight) {
- renderable = FALSE;
- }
- } else {
- width += range.x;
- }
-
- if (range.y >= 0) {
- if (bottom < maxHeight) {
- height += range.y;
- }
- } else {
- height += range.y;
- }
- }
-
- if (width < 0) {
- directive = "nw";
- height = 0;
- width = 0;
- }
-
- break;
-
- // Move image
- case "move":
- image.left += range.x;
- image.top += range.y;
- this.renderImage("move");
- renderable = FALSE;
-
- break;
-
- // Scale image
- case "zoom":
- if (defaults.zoomable) {
- 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,
- 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;
- }
-
- break;
-
- // Crop image
- case "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;
-
- if (range.x > 0) {
- if (range.y > 0) {
- directive = "se";
- } else {
- directive = "ne";
- top -= height;
- }
- } else {
- if (range.y > 0) {
- directive = "sw";
- left -= width;
- } else {
- directive = "nw";
- left -= width;
- top -= height;
- }
- }
-
- // Show the dragger if is hidden
- if (!this.cropped) {
- this.cropped = TRUE;
- this.$dragger.removeClass(CLASS_HIDDEN);
- }
- }
-
- break;
-
- // No default
- }
-
- if (renderable) {
- dragger.width = width;
- dragger.height = height;
- dragger.left = left;
- dragger.top = top;
- this.directive = directive;
-
- this.renderDragger();
- }
-
- // 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");
-
- /* 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>
- */
-
- Cropper.DEFAULTS = {
- // Basic
- aspectRatio: "auto",
- autoCropArea: 0.8, // 80%
- data: {
- // x: 0,
- // y: 0,
- // width: 300,
- // height: 150
- },
- done: $.noop,
- preview: "",
-
- // Toggles
- multiple: FALSE,
- autoCrop: TRUE,
- dragCrop: TRUE,
- dashed: TRUE,
- modal: TRUE,
- movable: TRUE,
- resizable: TRUE,
- zoomable: TRUE,
- rotatable: TRUE,
- checkImageOrigin: TRUE,
-
- // Dimensions
- minWidth: 0,
- minHeight: 0,
- maxWidth: INFINITY,
- maxHeight: INFINITY,
-
- // Events
- build: NULL,
- built: NULL,
- dragstart: NULL,
- dragmove: NULL,
- dragend: NULL
- };
-
- Cropper.setDefaults = function (options) {
- $.extend(Cropper.DEFAULTS, options);
- };
-
- // Save the other cropper
- Cropper.other = $.fn.cropper;
-
- // Register as jQuery plugin
- $.fn.cropper = function (options) {
- var args = toArray(arguments, 1),
- result;
-
- this.each(function () {
- var $this = $(this),
- data = $this.data("cropper"),
- fn;
-
- if (!data) {
- $this.data("cropper", (data = new Cropper(this, options)));
- }
-
- if (typeof options === "string" && $.isFunction((fn = data[options]))) {
- result = fn.apply(data, args);
- }
- });
-
- return (typeof result !== STRING_UNDEFINED ? result : this);
- };
-
- $.fn.cropper.Constructor = Cropper;
- $.fn.cropper.setDefaults = Cropper.setDefaults;
-
- // No conflict
- $.fn.cropper.noConflict = function () {
- $.fn.cropper = Cropper.other;
- return this;
- };
- });
|