懒羊羊
2023-08-30 1ac2bc1590406d9babec036e154d8d08f34a6aa1
提交 | 用户 | 时间
1ac2bc 1 /*!
2  * Cropper.js v1.5.1
3  * https://fengyuanchen.github.io/cropperjs
4  *
5  * Copyright 2015-present Chen Fengyuan
6  * Released under the MIT license
7  *
8  * Date: 2019-03-10T09:55:53.729Z
9  */
10 (function (global, factory) {
11     if (typeof exports === 'object' && typeof module !== 'undefined') {
12         module.exports = factory();
13     } else if (typeof define === 'function' && define.amd) {
14         define(factory);
15     } else if (window.layui && layui.define) {  // layui加载
16         layui.define(function (exports) {
17             layui.link(layui.cache.base + 'Cropper/Cropper.css');
18             exports('Cropper', factory());
19         });
20     } else {
21         (global = global || self, global.Cropper = factory());
22     }
23 }(this, function () {
24     'use strict';
25
26     function _typeof(obj) {
27         if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
28             _typeof = function (obj) {
29                 return typeof obj;
30             };
31         } else {
32             _typeof = function (obj) {
33                 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
34             };
35         }
36
37         return _typeof(obj);
38     }
39
40     function _classCallCheck(instance, Constructor) {
41         if (!(instance instanceof Constructor)) {
42             throw new TypeError("Cannot call a class as a function");
43         }
44     }
45
46     function _defineProperties(target, props) {
47         for (var i = 0; i < props.length; i++) {
48             var descriptor = props[i];
49             descriptor.enumerable = descriptor.enumerable || false;
50             descriptor.configurable = true;
51             if ("value" in descriptor) descriptor.writable = true;
52             Object.defineProperty(target, descriptor.key, descriptor);
53         }
54     }
55
56     function _createClass(Constructor, protoProps, staticProps) {
57         if (protoProps) _defineProperties(Constructor.prototype, protoProps);
58         if (staticProps) _defineProperties(Constructor, staticProps);
59         return Constructor;
60     }
61
62     function _toConsumableArray(arr) {
63         return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
64     }
65
66     function _arrayWithoutHoles(arr) {
67         if (Array.isArray(arr)) {
68             for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
69
70             return arr2;
71         }
72     }
73
74     function _iterableToArray(iter) {
75         if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
76     }
77
78     function _nonIterableSpread() {
79         throw new TypeError("Invalid attempt to spread non-iterable instance");
80     }
81
82     var IS_BROWSER = typeof window !== 'undefined';
83     var WINDOW = IS_BROWSER ? window : {};
84     var IS_TOUCH_DEVICE = IS_BROWSER ? 'ontouchstart' in WINDOW.document.documentElement : false;
85     var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
86     var NAMESPACE = 'cropper'; // Actions
87
88     var ACTION_ALL = 'all';
89     var ACTION_CROP = 'crop';
90     var ACTION_MOVE = 'move';
91     var ACTION_ZOOM = 'zoom';
92     var ACTION_EAST = 'e';
93     var ACTION_WEST = 'w';
94     var ACTION_SOUTH = 's';
95     var ACTION_NORTH = 'n';
96     var ACTION_NORTH_EAST = 'ne';
97     var ACTION_NORTH_WEST = 'nw';
98     var ACTION_SOUTH_EAST = 'se';
99     var ACTION_SOUTH_WEST = 'sw'; // Classes
100
101     var CLASS_CROP = "".concat(NAMESPACE, "-crop");
102     var CLASS_DISABLED = "".concat(NAMESPACE, "-disabled");
103     var CLASS_HIDDEN = "".concat(NAMESPACE, "-hidden");
104     var CLASS_HIDE = "".concat(NAMESPACE, "-hide");
105     var CLASS_INVISIBLE = "".concat(NAMESPACE, "-invisible");
106     var CLASS_MODAL = "".concat(NAMESPACE, "-modal");
107     var CLASS_MOVE = "".concat(NAMESPACE, "-move"); // Data keys
108
109     var DATA_ACTION = "".concat(NAMESPACE, "Action");
110     var DATA_PREVIEW = "".concat(NAMESPACE, "Preview"); // Drag modes
111
112     var DRAG_MODE_CROP = 'crop';
113     var DRAG_MODE_MOVE = 'move';
114     var DRAG_MODE_NONE = 'none'; // Events
115
116     var EVENT_CROP = 'crop';
117     var EVENT_CROP_END = 'cropend';
118     var EVENT_CROP_MOVE = 'cropmove';
119     var EVENT_CROP_START = 'cropstart';
120     var EVENT_DBLCLICK = 'dblclick';
121     var EVENT_TOUCH_START = IS_TOUCH_DEVICE ? 'touchstart' : 'mousedown';
122     var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? 'touchmove' : 'mousemove';
123     var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? 'touchend touchcancel' : 'mouseup';
124     var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? 'pointerdown' : EVENT_TOUCH_START;
125     var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? 'pointermove' : EVENT_TOUCH_MOVE;
126     var EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' : EVENT_TOUCH_END;
127     var EVENT_READY = 'ready';
128     var EVENT_RESIZE = 'resize';
129     var EVENT_WHEEL = 'wheel';
130     var EVENT_ZOOM = 'zoom'; // Mime types
131
132     var MIME_TYPE_JPEG = 'image/jpeg'; // RegExps
133
134     var REGEXP_ACTIONS = /^e|w|s|n|se|sw|ne|nw|all|crop|move|zoom$/;
135     var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg;base64,/;
136     var REGEXP_TAG_NAME = /^img|canvas$/i; // Misc
137     // Inspired by the default width and height of a canvas element.
138
139     var MIN_CONTAINER_WIDTH = 200;
140     var MIN_CONTAINER_HEIGHT = 100;
141
142     var DEFAULTS = {
143         // Define the view mode of the cropper
144         viewMode: 0,
145         // 0, 1, 2, 3
146         // Define the dragging mode of the cropper
147         dragMode: DRAG_MODE_CROP,
148         // 'crop', 'move' or 'none'
149         // Define the initial aspect ratio of the crop box
150         initialAspectRatio: NaN,
151         // Define the aspect ratio of the crop box
152         aspectRatio: NaN,
153         // An object with the previous cropping result data
154         data: null,
155         // A selector for adding extra containers to preview
156         preview: '',
157         // Re-render the cropper when resize the window
158         responsive: true,
159         // Restore the cropped area after resize the window
160         restore: true,
161         // Check if the current image is a cross-origin image
162         checkCrossOrigin: true,
163         // Check the current image's Exif Orientation information
164         checkOrientation: true,
165         // Show the black modal
166         modal: true,
167         // Show the dashed lines for guiding
168         guides: true,
169         // Show the center indicator for guiding
170         center: true,
171         // Show the white modal to highlight the crop box
172         highlight: true,
173         // Show the grid background
174         background: true,
175         // Enable to crop the image automatically when initialize
176         autoCrop: true,
177         // Define the percentage of automatic cropping area when initializes
178         autoCropArea: 0.8,
179         // Enable to move the image
180         movable: true,
181         // Enable to rotate the image
182         rotatable: true,
183         // Enable to scale the image
184         scalable: true,
185         // Enable to zoom the image
186         zoomable: true,
187         // Enable to zoom the image by dragging touch
188         zoomOnTouch: true,
189         // Enable to zoom the image by wheeling mouse
190         zoomOnWheel: true,
191         // Define zoom ratio when zoom the image by wheeling mouse
192         wheelZoomRatio: 0.1,
193         // Enable to move the crop box
194         cropBoxMovable: true,
195         // Enable to resize the crop box
196         cropBoxResizable: true,
197         // Toggle drag mode between "crop" and "move" when click twice on the cropper
198         toggleDragModeOnDblclick: true,
199         // Size limitation
200         minCanvasWidth: 0,
201         minCanvasHeight: 0,
202         minCropBoxWidth: 0,
203         minCropBoxHeight: 0,
204         minContainerWidth: 200,
205         minContainerHeight: 100,
206         // Shortcuts of events
207         ready: null,
208         cropstart: null,
209         cropmove: null,
210         cropend: null,
211         crop: null,
212         zoom: null
213     };
214
215     var TEMPLATE = '<div class="cropper-container" touch-action="none">' + '<div class="cropper-wrap-box">' + '<div class="cropper-canvas"></div>' + '</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-cropper-action="e"></span>' + '<span class="cropper-line line-n" data-cropper-action="n"></span>' + '<span class="cropper-line line-w" data-cropper-action="w"></span>' + '<span class="cropper-line line-s" data-cropper-action="s"></span>' + '<span class="cropper-point point-e" data-cropper-action="e"></span>' + '<span class="cropper-point point-n" data-cropper-action="n"></span>' + '<span class="cropper-point point-w" data-cropper-action="w"></span>' + '<span class="cropper-point point-s" data-cropper-action="s"></span>' + '<span class="cropper-point point-ne" data-cropper-action="ne"></span>' + '<span class="cropper-point point-nw" data-cropper-action="nw"></span>' + '<span class="cropper-point point-sw" data-cropper-action="sw"></span>' + '<span class="cropper-point point-se" data-cropper-action="se"></span>' + '</div>' + '</div>';
216
217     /**
218      * Check if the given value is not a number.
219      */
220
221     var isNaN = Number.isNaN || WINDOW.isNaN;
222
223     /**
224      * Check if the given value is a number.
225      * @param {*} value - The value to check.
226      * @returns {boolean} Returns `true` if the given value is a number, else `false`.
227      */
228
229     function isNumber(value) {
230         return typeof value === 'number' && !isNaN(value);
231     }
232
233     /**
234      * Check if the given value is a positive number.
235      * @param {*} value - The value to check.
236      * @returns {boolean} Returns `true` if the given value is a positive number, else `false`.
237      */
238
239     var isPositiveNumber = function isPositiveNumber(value) {
240         return value > 0 && value < Infinity;
241     };
242
243     /**
244      * Check if the given value is undefined.
245      * @param {*} value - The value to check.
246      * @returns {boolean} Returns `true` if the given value is undefined, else `false`.
247      */
248
249     function isUndefined(value) {
250         return typeof value === 'undefined';
251     }
252
253     /**
254      * Check if the given value is an object.
255      * @param {*} value - The value to check.
256      * @returns {boolean} Returns `true` if the given value is an object, else `false`.
257      */
258
259     function isObject(value) {
260         return _typeof(value) === 'object' && value !== null;
261     }
262
263     var hasOwnProperty = Object.prototype.hasOwnProperty;
264
265     /**
266      * Check if the given value is a plain object.
267      * @param {*} value - The value to check.
268      * @returns {boolean} Returns `true` if the given value is a plain object, else `false`.
269      */
270
271     function isPlainObject(value) {
272         if (!isObject(value)) {
273             return false;
274         }
275
276         try {
277             var _constructor = value.constructor;
278             var prototype = _constructor.prototype;
279             return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf');
280         } catch (error) {
281             return false;
282         }
283     }
284
285     /**
286      * Check if the given value is a function.
287      * @param {*} value - The value to check.
288      * @returns {boolean} Returns `true` if the given value is a function, else `false`.
289      */
290
291     function isFunction(value) {
292         return typeof value === 'function';
293     }
294
295     var slice = Array.prototype.slice;
296
297     /**
298      * Convert array-like or iterable object to an array.
299      * @param {*} value - The value to convert.
300      * @returns {Array} Returns a new array.
301      */
302
303     function toArray(value) {
304         return Array.from ? Array.from(value) : slice.call(value);
305     }
306
307     /**
308      * Iterate the given data.
309      * @param {*} data - The data to iterate.
310      * @param {Function} callback - The process function for each element.
311      * @returns {*} The original data.
312      */
313
314     function forEach(data, callback) {
315         if (data && isFunction(callback)) {
316             if (Array.isArray(data) || isNumber(data.length)
317             /* array-like */
318             ) {
319                 toArray(data).forEach(function (value, key) {
320                     callback.call(data, value, key, data);
321                 });
322             } else if (isObject(data)) {
323                 Object.keys(data).forEach(function (key) {
324                     callback.call(data, data[key], key, data);
325                 });
326             }
327         }
328
329         return data;
330     }
331
332     /**
333      * Extend the given object.
334      * @param {*} target - The target object to extend.
335      * @param {*} args - The rest objects for merging to the target object.
336      * @returns {Object} The extended object.
337      */
338
339     var assign = Object.assign || function assign(target) {
340         for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
341             args[_key - 1] = arguments[_key];
342         }
343
344         if (isObject(target) && args.length > 0) {
345             args.forEach(function (arg) {
346                 if (isObject(arg)) {
347                     Object.keys(arg).forEach(function (key) {
348                         target[key] = arg[key];
349                     });
350                 }
351             });
352         }
353
354         return target;
355     };
356     var REGEXP_DECIMALS = /\.\d*(?:0|9){12}\d*$/;
357
358     /**
359      * Normalize decimal number.
360      * Check out {@link http://0.30000000000000004.com/}
361      * @param {number} value - The value to normalize.
362      * @param {number} [times=100000000000] - The times for normalizing.
363      * @returns {number} Returns the normalized number.
364      */
365
366     function normalizeDecimalNumber(value) {
367         var times = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100000000000;
368         return REGEXP_DECIMALS.test(value) ? Math.round(value * times) / times : value;
369     }
370
371     var REGEXP_SUFFIX = /^width|height|left|top|marginLeft|marginTop$/;
372
373     /**
374      * Apply styles to the given element.
375      * @param {Element} element - The target element.
376      * @param {Object} styles - The styles for applying.
377      */
378
379     function setStyle(element, styles) {
380         var style = element.style;
381         forEach(styles, function (value, property) {
382             if (REGEXP_SUFFIX.test(property) && isNumber(value)) {
383                 value = "".concat(value, "px");
384             }
385
386             style[property] = value;
387         });
388     }
389
390     /**
391      * Check if the given element has a special class.
392      * @param {Element} element - The element to check.
393      * @param {string} value - The class to search.
394      * @returns {boolean} Returns `true` if the special class was found.
395      */
396
397     function hasClass(element, value) {
398         return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1;
399     }
400
401     /**
402      * Add classes to the given element.
403      * @param {Element} element - The target element.
404      * @param {string} value - The classes to be added.
405      */
406
407     function addClass(element, value) {
408         if (!value) {
409             return;
410         }
411
412         if (isNumber(element.length)) {
413             forEach(element, function (elem) {
414                 addClass(elem, value);
415             });
416             return;
417         }
418
419         if (element.classList) {
420             element.classList.add(value);
421             return;
422         }
423
424         var className = element.className.trim();
425
426         if (!className) {
427             element.className = value;
428         } else if (className.indexOf(value) < 0) {
429             element.className = "".concat(className, " ").concat(value);
430         }
431     }
432
433     /**
434      * Remove classes from the given element.
435      * @param {Element} element - The target element.
436      * @param {string} value - The classes to be removed.
437      */
438
439     function removeClass(element, value) {
440         if (!value) {
441             return;
442         }
443
444         if (isNumber(element.length)) {
445             forEach(element, function (elem) {
446                 removeClass(elem, value);
447             });
448             return;
449         }
450
451         if (element.classList) {
452             element.classList.remove(value);
453             return;
454         }
455
456         if (element.className.indexOf(value) >= 0) {
457             element.className = element.className.replace(value, '');
458         }
459     }
460
461     /**
462      * Add or remove classes from the given element.
463      * @param {Element} element - The target element.
464      * @param {string} value - The classes to be toggled.
465      * @param {boolean} added - Add only.
466      */
467
468     function toggleClass(element, value, added) {
469         if (!value) {
470             return;
471         }
472
473         if (isNumber(element.length)) {
474             forEach(element, function (elem) {
475                 toggleClass(elem, value, added);
476             });
477             return;
478         } // IE10-11 doesn't support the second parameter of `classList.toggle`
479
480
481         if (added) {
482             addClass(element, value);
483         } else {
484             removeClass(element, value);
485         }
486     }
487
488     var REGEXP_CAMEL_CASE = /([a-z\d])([A-Z])/g;
489
490     /**
491      * Transform the given string from camelCase to kebab-case
492      * @param {string} value - The value to transform.
493      * @returns {string} The transformed value.
494      */
495
496     function toParamCase(value) {
497         return value.replace(REGEXP_CAMEL_CASE, '$1-$2').toLowerCase();
498     }
499
500     /**
501      * Get data from the given element.
502      * @param {Element} element - The target element.
503      * @param {string} name - The data key to get.
504      * @returns {string} The data value.
505      */
506
507     function getData(element, name) {
508         if (isObject(element[name])) {
509             return element[name];
510         }
511
512         if (element.dataset) {
513             return element.dataset[name];
514         }
515
516         return element.getAttribute("data-".concat(toParamCase(name)));
517     }
518
519     /**
520      * Set data to the given element.
521      * @param {Element} element - The target element.
522      * @param {string} name - The data key to set.
523      * @param {string} data - The data value.
524      */
525
526     function setData(element, name, data) {
527         if (isObject(data)) {
528             element[name] = data;
529         } else if (element.dataset) {
530             element.dataset[name] = data;
531         } else {
532             element.setAttribute("data-".concat(toParamCase(name)), data);
533         }
534     }
535
536     /**
537      * Remove data from the given element.
538      * @param {Element} element - The target element.
539      * @param {string} name - The data key to remove.
540      */
541
542     function removeData(element, name) {
543         if (isObject(element[name])) {
544             try {
545                 delete element[name];
546             } catch (error) {
547                 element[name] = undefined;
548             }
549         } else if (element.dataset) {
550             // #128 Safari not allows to delete dataset property
551             try {
552                 delete element.dataset[name];
553             } catch (error) {
554                 element.dataset[name] = undefined;
555             }
556         } else {
557             element.removeAttribute("data-".concat(toParamCase(name)));
558         }
559     }
560
561     var REGEXP_SPACES = /\s\s*/;
562
563     var onceSupported = function () {
564         var supported = false;
565
566         if (IS_BROWSER) {
567             var once = false;
568
569             var listener = function listener() {
570             };
571
572             var options = Object.defineProperty({}, 'once', {
573                 get: function get() {
574                     supported = true;
575                     return once;
576                 },
577
578                 /**
579                  * This setter can fix a `TypeError` in strict mode
580                  * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only}
581                  * @param {boolean} value - The value to set
582                  */
583                 set: function set(value) {
584                     once = value;
585                 }
586             });
587             WINDOW.addEventListener('test', listener, options);
588             WINDOW.removeEventListener('test', listener, options);
589         }
590
591         return supported;
592     }();
593
594     /**
595      * Remove event listener from the target element.
596      * @param {Element} element - The event target.
597      * @param {string} type - The event type(s).
598      * @param {Function} listener - The event listener.
599      * @param {Object} options - The event options.
600      */
601
602
603     function removeListener(element, type, listener) {
604         var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
605         var handler = listener;
606         type.trim().split(REGEXP_SPACES).forEach(function (event) {
607             if (!onceSupported) {
608                 var listeners = element.listeners;
609
610                 if (listeners && listeners[event] && listeners[event][listener]) {
611                     handler = listeners[event][listener];
612                     delete listeners[event][listener];
613
614                     if (Object.keys(listeners[event]).length === 0) {
615                         delete listeners[event];
616                     }
617
618                     if (Object.keys(listeners).length === 0) {
619                         delete element.listeners;
620                     }
621                 }
622             }
623
624             element.removeEventListener(event, handler, options);
625         });
626     }
627
628     /**
629      * Add event listener to the target element.
630      * @param {Element} element - The event target.
631      * @param {string} type - The event type(s).
632      * @param {Function} listener - The event listener.
633      * @param {Object} options - The event options.
634      */
635
636     function addListener(element, type, listener) {
637         var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
638         var _handler = listener;
639         type.trim().split(REGEXP_SPACES).forEach(function (event) {
640             if (options.once && !onceSupported) {
641                 var _element$listeners = element.listeners,
642                     listeners = _element$listeners === void 0 ? {} : _element$listeners;
643
644                 _handler = function handler() {
645                     delete listeners[event][listener];
646                     element.removeEventListener(event, _handler, options);
647
648                     for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
649                         args[_key2] = arguments[_key2];
650                     }
651
652                     listener.apply(element, args);
653                 };
654
655                 if (!listeners[event]) {
656                     listeners[event] = {};
657                 }
658
659                 if (listeners[event][listener]) {
660                     element.removeEventListener(event, listeners[event][listener], options);
661                 }
662
663                 listeners[event][listener] = _handler;
664                 element.listeners = listeners;
665             }
666
667             element.addEventListener(event, _handler, options);
668         });
669     }
670
671     /**
672      * Dispatch event on the target element.
673      * @param {Element} element - The event target.
674      * @param {string} type - The event type(s).
675      * @param {Object} data - The additional event data.
676      * @returns {boolean} Indicate if the event is default prevented or not.
677      */
678
679     function dispatchEvent(element, type, data) {
680         var event; // Event and CustomEvent on IE9-11 are global objects, not constructors
681
682         if (isFunction(Event) && isFunction(CustomEvent)) {
683             event = new CustomEvent(type, {
684                 detail: data,
685                 bubbles: true,
686                 cancelable: true
687             });
688         } else {
689             event = document.createEvent('CustomEvent');
690             event.initCustomEvent(type, true, true, data);
691         }
692
693         return element.dispatchEvent(event);
694     }
695
696     /**
697      * Get the offset base on the document.
698      * @param {Element} element - The target element.
699      * @returns {Object} The offset data.
700      */
701
702     function getOffset(element) {
703         var box = element.getBoundingClientRect();
704         return {
705             left: box.left + (window.pageXOffset - document.documentElement.clientLeft),
706             top: box.top + (window.pageYOffset - document.documentElement.clientTop)
707         };
708     }
709
710     var location = WINDOW.location;
711     var REGEXP_ORIGINS = /^(\w+:)\/\/([^:/?#]*):?(\d*)/i;
712
713     /**
714      * Check if the given URL is a cross origin URL.
715      * @param {string} url - The target URL.
716      * @returns {boolean} Returns `true` if the given URL is a cross origin URL, else `false`.
717      */
718
719     function isCrossOriginURL(url) {
720         var parts = url.match(REGEXP_ORIGINS);
721         return parts !== null && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port);
722     }
723
724     /**
725      * Add timestamp to the given URL.
726      * @param {string} url - The target URL.
727      * @returns {string} The result URL.
728      */
729
730     function addTimestamp(url) {
731         var timestamp = "timestamp=".concat(new Date().getTime());
732         return url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp;
733     }
734
735     /**
736      * Get transforms base on the given object.
737      * @param {Object} obj - The target object.
738      * @returns {string} A string contains transform values.
739      */
740
741     function getTransforms(_ref) {
742         var rotate = _ref.rotate,
743             scaleX = _ref.scaleX,
744             scaleY = _ref.scaleY,
745             translateX = _ref.translateX,
746             translateY = _ref.translateY;
747         var values = [];
748
749         if (isNumber(translateX) && translateX !== 0) {
750             values.push("translateX(".concat(translateX, "px)"));
751         }
752
753         if (isNumber(translateY) && translateY !== 0) {
754             values.push("translateY(".concat(translateY, "px)"));
755         } // Rotate should come first before scale to match orientation transform
756
757
758         if (isNumber(rotate) && rotate !== 0) {
759             values.push("rotate(".concat(rotate, "deg)"));
760         }
761
762         if (isNumber(scaleX) && scaleX !== 1) {
763             values.push("scaleX(".concat(scaleX, ")"));
764         }
765
766         if (isNumber(scaleY) && scaleY !== 1) {
767             values.push("scaleY(".concat(scaleY, ")"));
768         }
769
770         var transform = values.length ? values.join(' ') : 'none';
771         return {
772             WebkitTransform: transform,
773             msTransform: transform,
774             transform: transform
775         };
776     }
777
778     /**
779      * Get the max ratio of a group of pointers.
780      * @param {string} pointers - The target pointers.
781      * @returns {number} The result ratio.
782      */
783
784     function getMaxZoomRatio(pointers) {
785         var pointers2 = assign({}, pointers);
786         var ratios = [];
787         forEach(pointers, function (pointer, pointerId) {
788             delete pointers2[pointerId];
789             forEach(pointers2, function (pointer2) {
790                 var x1 = Math.abs(pointer.startX - pointer2.startX);
791                 var y1 = Math.abs(pointer.startY - pointer2.startY);
792                 var x2 = Math.abs(pointer.endX - pointer2.endX);
793                 var y2 = Math.abs(pointer.endY - pointer2.endY);
794                 var z1 = Math.sqrt(x1 * x1 + y1 * y1);
795                 var z2 = Math.sqrt(x2 * x2 + y2 * y2);
796                 var ratio = (z2 - z1) / z1;
797                 ratios.push(ratio);
798             });
799         });
800         ratios.sort(function (a, b) {
801             return Math.abs(a) < Math.abs(b);
802         });
803         return ratios[0];
804     }
805
806     /**
807      * Get a pointer from an event object.
808      * @param {Object} event - The target event object.
809      * @param {boolean} endOnly - Indicates if only returns the end point coordinate or not.
810      * @returns {Object} The result pointer contains start and/or end point coordinates.
811      */
812
813     function getPointer(_ref2, endOnly) {
814         var pageX = _ref2.pageX,
815             pageY = _ref2.pageY;
816         var end = {
817             endX: pageX,
818             endY: pageY
819         };
820         return endOnly ? end : assign({
821             startX: pageX,
822             startY: pageY
823         }, end);
824     }
825
826     /**
827      * Get the center point coordinate of a group of pointers.
828      * @param {Object} pointers - The target pointers.
829      * @returns {Object} The center point coordinate.
830      */
831
832     function getPointersCenter(pointers) {
833         var pageX = 0;
834         var pageY = 0;
835         var count = 0;
836         forEach(pointers, function (_ref3) {
837             var startX = _ref3.startX,
838                 startY = _ref3.startY;
839             pageX += startX;
840             pageY += startY;
841             count += 1;
842         });
843         pageX /= count;
844         pageY /= count;
845         return {
846             pageX: pageX,
847             pageY: pageY
848         };
849     }
850
851     /**
852      * Get the max sizes in a rectangle under the given aspect ratio.
853      * @param {Object} data - The original sizes.
854      * @param {string} [type='contain'] - The adjust type.
855      * @returns {Object} The result sizes.
856      */
857
858     function getAdjustedSizes(_ref4) // or 'cover'
859     {
860         var aspectRatio = _ref4.aspectRatio,
861             height = _ref4.height,
862             width = _ref4.width;
863         var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'contain';
864         var isValidWidth = isPositiveNumber(width);
865         var isValidHeight = isPositiveNumber(height);
866
867         if (isValidWidth && isValidHeight) {
868             var adjustedWidth = height * aspectRatio;
869
870             if (type === 'contain' && adjustedWidth > width || type === 'cover' && adjustedWidth < width) {
871                 height = width / aspectRatio;
872             } else {
873                 width = height * aspectRatio;
874             }
875         } else if (isValidWidth) {
876             height = width / aspectRatio;
877         } else if (isValidHeight) {
878             width = height * aspectRatio;
879         }
880
881         return {
882             width: width,
883             height: height
884         };
885     }
886
887     /**
888      * Get the new sizes of a rectangle after rotated.
889      * @param {Object} data - The original sizes.
890      * @returns {Object} The result sizes.
891      */
892
893     function getRotatedSizes(_ref5) {
894         var width = _ref5.width,
895             height = _ref5.height,
896             degree = _ref5.degree;
897         degree = Math.abs(degree) % 180;
898
899         if (degree === 90) {
900             return {
901                 width: height,
902                 height: width
903             };
904         }
905
906         var arc = degree % 90 * Math.PI / 180;
907         var sinArc = Math.sin(arc);
908         var cosArc = Math.cos(arc);
909         var newWidth = width * cosArc + height * sinArc;
910         var newHeight = width * sinArc + height * cosArc;
911         return degree > 90 ? {
912             width: newHeight,
913             height: newWidth
914         } : {
915             width: newWidth,
916             height: newHeight
917         };
918     }
919
920     /**
921      * Get a canvas which drew the given image.
922      * @param {HTMLImageElement} image - The image for drawing.
923      * @param {Object} imageData - The image data.
924      * @param {Object} canvasData - The canvas data.
925      * @param {Object} options - The options.
926      * @returns {HTMLCanvasElement} The result canvas.
927      */
928
929     function getSourceCanvas(image, _ref6, _ref7, _ref8) {
930         var imageAspectRatio = _ref6.aspectRatio,
931             imageNaturalWidth = _ref6.naturalWidth,
932             imageNaturalHeight = _ref6.naturalHeight,
933             _ref6$rotate = _ref6.rotate,
934             rotate = _ref6$rotate === void 0 ? 0 : _ref6$rotate,
935             _ref6$scaleX = _ref6.scaleX,
936             scaleX = _ref6$scaleX === void 0 ? 1 : _ref6$scaleX,
937             _ref6$scaleY = _ref6.scaleY,
938             scaleY = _ref6$scaleY === void 0 ? 1 : _ref6$scaleY;
939         var aspectRatio = _ref7.aspectRatio,
940             naturalWidth = _ref7.naturalWidth,
941             naturalHeight = _ref7.naturalHeight;
942         var _ref8$fillColor = _ref8.fillColor,
943             fillColor = _ref8$fillColor === void 0 ? 'transparent' : _ref8$fillColor,
944             _ref8$imageSmoothingE = _ref8.imageSmoothingEnabled,
945             imageSmoothingEnabled = _ref8$imageSmoothingE === void 0 ? true : _ref8$imageSmoothingE,
946             _ref8$imageSmoothingQ = _ref8.imageSmoothingQuality,
947             imageSmoothingQuality = _ref8$imageSmoothingQ === void 0 ? 'low' : _ref8$imageSmoothingQ,
948             _ref8$maxWidth = _ref8.maxWidth,
949             maxWidth = _ref8$maxWidth === void 0 ? Infinity : _ref8$maxWidth,
950             _ref8$maxHeight = _ref8.maxHeight,
951             maxHeight = _ref8$maxHeight === void 0 ? Infinity : _ref8$maxHeight,
952             _ref8$minWidth = _ref8.minWidth,
953             minWidth = _ref8$minWidth === void 0 ? 0 : _ref8$minWidth,
954             _ref8$minHeight = _ref8.minHeight,
955             minHeight = _ref8$minHeight === void 0 ? 0 : _ref8$minHeight;
956         var canvas = document.createElement('canvas');
957         var context = canvas.getContext('2d');
958         var maxSizes = getAdjustedSizes({
959             aspectRatio: aspectRatio,
960             width: maxWidth,
961             height: maxHeight
962         });
963         var minSizes = getAdjustedSizes({
964             aspectRatio: aspectRatio,
965             width: minWidth,
966             height: minHeight
967         }, 'cover');
968         var width = Math.min(maxSizes.width, Math.max(minSizes.width, naturalWidth));
969         var height = Math.min(maxSizes.height, Math.max(minSizes.height, naturalHeight)); // Note: should always use image's natural sizes for drawing as
970         // imageData.naturalWidth === canvasData.naturalHeight when rotate % 180 === 90
971
972         var destMaxSizes = getAdjustedSizes({
973             aspectRatio: imageAspectRatio,
974             width: maxWidth,
975             height: maxHeight
976         });
977         var destMinSizes = getAdjustedSizes({
978             aspectRatio: imageAspectRatio,
979             width: minWidth,
980             height: minHeight
981         }, 'cover');
982         var destWidth = Math.min(destMaxSizes.width, Math.max(destMinSizes.width, imageNaturalWidth));
983         var destHeight = Math.min(destMaxSizes.height, Math.max(destMinSizes.height, imageNaturalHeight));
984         var params = [-destWidth / 2, -destHeight / 2, destWidth, destHeight];
985         canvas.width = normalizeDecimalNumber(width);
986         canvas.height = normalizeDecimalNumber(height);
987         context.fillStyle = fillColor;
988         context.fillRect(0, 0, width, height);
989         context.save();
990         context.translate(width / 2, height / 2);
991         context.rotate(rotate * Math.PI / 180);
992         context.scale(scaleX, scaleY);
993         context.imageSmoothingEnabled = imageSmoothingEnabled;
994         context.imageSmoothingQuality = imageSmoothingQuality;
995         context.drawImage.apply(context, [image].concat(_toConsumableArray(params.map(function (param) {
996             return Math.floor(normalizeDecimalNumber(param));
997         }))));
998         context.restore();
999         return canvas;
1000     }
1001
1002     var fromCharCode = String.fromCharCode;
1003
1004     /**
1005      * Get string from char code in data view.
1006      * @param {DataView} dataView - The data view for read.
1007      * @param {number} start - The start index.
1008      * @param {number} length - The read length.
1009      * @returns {string} The read result.
1010      */
1011
1012     function getStringFromCharCode(dataView, start, length) {
1013         var str = '';
1014         length += start;
1015
1016         for (var i = start; i < length; i += 1) {
1017             str += fromCharCode(dataView.getUint8(i));
1018         }
1019
1020         return str;
1021     }
1022
1023     var REGEXP_DATA_URL_HEAD = /^data:.*,/;
1024
1025     /**
1026      * Transform Data URL to array buffer.
1027      * @param {string} dataURL - The Data URL to transform.
1028      * @returns {ArrayBuffer} The result array buffer.
1029      */
1030
1031     function dataURLToArrayBuffer(dataURL) {
1032         var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, '');
1033         var binary = atob(base64);
1034         var arrayBuffer = new ArrayBuffer(binary.length);
1035         var uint8 = new Uint8Array(arrayBuffer);
1036         forEach(uint8, function (value, i) {
1037             uint8[i] = binary.charCodeAt(i);
1038         });
1039         return arrayBuffer;
1040     }
1041
1042     /**
1043      * Transform array buffer to Data URL.
1044      * @param {ArrayBuffer} arrayBuffer - The array buffer to transform.
1045      * @param {string} mimeType - The mime type of the Data URL.
1046      * @returns {string} The result Data URL.
1047      */
1048
1049     function arrayBufferToDataURL(arrayBuffer, mimeType) {
1050         var chunks = []; // Chunk Typed Array for better performance (#435)
1051
1052         var chunkSize = 8192;
1053         var uint8 = new Uint8Array(arrayBuffer);
1054
1055         while (uint8.length > 0) {
1056             // XXX: Babel's `toConsumableArray` helper will throw error in IE or Safari 9
1057             // eslint-disable-next-line prefer-spread
1058             chunks.push(fromCharCode.apply(null, toArray(uint8.subarray(0, chunkSize))));
1059             uint8 = uint8.subarray(chunkSize);
1060         }
1061
1062         return "data:".concat(mimeType, ";base64,").concat(btoa(chunks.join('')));
1063     }
1064
1065     /**
1066      * Get orientation value from given array buffer.
1067      * @param {ArrayBuffer} arrayBuffer - The array buffer to read.
1068      * @returns {number} The read orientation value.
1069      */
1070
1071     function resetAndGetOrientation(arrayBuffer) {
1072         var dataView = new DataView(arrayBuffer);
1073         var orientation; // Ignores range error when the image does not have correct Exif information
1074
1075         try {
1076             var littleEndian;
1077             var app1Start;
1078             var ifdStart; // Only handle JPEG image (start by 0xFFD8)
1079
1080             if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
1081                 var length = dataView.byteLength;
1082                 var offset = 2;
1083
1084                 while (offset + 1 < length) {
1085                     if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
1086                         app1Start = offset;
1087                         break;
1088                     }
1089
1090                     offset += 1;
1091                 }
1092             }
1093
1094             if (app1Start) {
1095                 var exifIDCode = app1Start + 4;
1096                 var tiffOffset = app1Start + 10;
1097
1098                 if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
1099                     var endianness = dataView.getUint16(tiffOffset);
1100                     littleEndian = endianness === 0x4949;
1101
1102                     if (littleEndian || endianness === 0x4D4D
1103                     /* bigEndian */
1104                     ) {
1105                         if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
1106                             var firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
1107
1108                             if (firstIFDOffset >= 0x00000008) {
1109                                 ifdStart = tiffOffset + firstIFDOffset;
1110                             }
1111                         }
1112                     }
1113                 }
1114             }
1115
1116             if (ifdStart) {
1117                 var _length = dataView.getUint16(ifdStart, littleEndian);
1118
1119                 var _offset;
1120
1121                 var i;
1122
1123                 for (i = 0; i < _length; i += 1) {
1124                     _offset = ifdStart + i * 12 + 2;
1125
1126                     if (dataView.getUint16(_offset, littleEndian) === 0x0112
1127                     /* Orientation */
1128                     ) {
1129                         // 8 is the offset of the current tag's value
1130                         _offset += 8; // Get the original orientation value
1131
1132                         orientation = dataView.getUint16(_offset, littleEndian); // Override the orientation with its default value
1133
1134                         dataView.setUint16(_offset, 1, littleEndian);
1135                         break;
1136                     }
1137                 }
1138             }
1139         } catch (error) {
1140             orientation = 1;
1141         }
1142
1143         return orientation;
1144     }
1145
1146     /**
1147      * Parse Exif Orientation value.
1148      * @param {number} orientation - The orientation to parse.
1149      * @returns {Object} The parsed result.
1150      */
1151
1152     function parseOrientation(orientation) {
1153         var rotate = 0;
1154         var scaleX = 1;
1155         var scaleY = 1;
1156
1157         switch (orientation) {
1158             // Flip horizontal
1159             case 2:
1160                 scaleX = -1;
1161                 break;
1162             // Rotate left 180°
1163
1164             case 3:
1165                 rotate = -180;
1166                 break;
1167             // Flip vertical
1168
1169             case 4:
1170                 scaleY = -1;
1171                 break;
1172             // Flip vertical and rotate right 90°
1173
1174             case 5:
1175                 rotate = 90;
1176                 scaleY = -1;
1177                 break;
1178             // Rotate right 90°
1179
1180             case 6:
1181                 rotate = 90;
1182                 break;
1183             // Flip horizontal and rotate right 90°
1184
1185             case 7:
1186                 rotate = 90;
1187                 scaleX = -1;
1188                 break;
1189             // Rotate left 90°
1190
1191             case 8:
1192                 rotate = -90;
1193                 break;
1194
1195             default:
1196         }
1197
1198         return {
1199             rotate: rotate,
1200             scaleX: scaleX,
1201             scaleY: scaleY
1202         };
1203     }
1204
1205     var render = {
1206         render: function render() {
1207             this.initContainer();
1208             this.initCanvas();
1209             this.initCropBox();
1210             this.renderCanvas();
1211
1212             if (this.cropped) {
1213                 this.renderCropBox();
1214             }
1215         },
1216         initContainer: function initContainer() {
1217             var element = this.element,
1218                 options = this.options,
1219                 container = this.container,
1220                 cropper = this.cropper;
1221             addClass(cropper, CLASS_HIDDEN);
1222             removeClass(element, CLASS_HIDDEN);
1223             var containerData = {
1224                 width: Math.max(container.offsetWidth, Number(options.minContainerWidth) || 200),
1225                 height: Math.max(container.offsetHeight, Number(options.minContainerHeight) || 100)
1226             };
1227             this.containerData = containerData;
1228             setStyle(cropper, {
1229                 width: containerData.width,
1230                 height: containerData.height
1231             });
1232             addClass(element, CLASS_HIDDEN);
1233             removeClass(cropper, CLASS_HIDDEN);
1234         },
1235         // Canvas (image wrapper)
1236         initCanvas: function initCanvas() {
1237             var containerData = this.containerData,
1238                 imageData = this.imageData;
1239             var viewMode = this.options.viewMode;
1240             var rotated = Math.abs(imageData.rotate) % 180 === 90;
1241             var naturalWidth = rotated ? imageData.naturalHeight : imageData.naturalWidth;
1242             var naturalHeight = rotated ? imageData.naturalWidth : imageData.naturalHeight;
1243             var aspectRatio = naturalWidth / naturalHeight;
1244             var canvasWidth = containerData.width;
1245             var canvasHeight = containerData.height;
1246
1247             if (containerData.height * aspectRatio > containerData.width) {
1248                 if (viewMode === 3) {
1249                     canvasWidth = containerData.height * aspectRatio;
1250                 } else {
1251                     canvasHeight = containerData.width / aspectRatio;
1252                 }
1253             } else if (viewMode === 3) {
1254                 canvasHeight = containerData.width / aspectRatio;
1255             } else {
1256                 canvasWidth = containerData.height * aspectRatio;
1257             }
1258
1259             var canvasData = {
1260                 aspectRatio: aspectRatio,
1261                 naturalWidth: naturalWidth,
1262                 naturalHeight: naturalHeight,
1263                 width: canvasWidth,
1264                 height: canvasHeight
1265             };
1266             canvasData.left = (containerData.width - canvasWidth) / 2;
1267             canvasData.top = (containerData.height - canvasHeight) / 2;
1268             canvasData.oldLeft = canvasData.left;
1269             canvasData.oldTop = canvasData.top;
1270             this.canvasData = canvasData;
1271             this.limited = viewMode === 1 || viewMode === 2;
1272             this.limitCanvas(true, true);
1273             this.initialImageData = assign({}, imageData);
1274             this.initialCanvasData = assign({}, canvasData);
1275         },
1276         limitCanvas: function limitCanvas(sizeLimited, positionLimited) {
1277             var options = this.options,
1278                 containerData = this.containerData,
1279                 canvasData = this.canvasData,
1280                 cropBoxData = this.cropBoxData;
1281             var viewMode = options.viewMode;
1282             var aspectRatio = canvasData.aspectRatio;
1283             var cropped = this.cropped && cropBoxData;
1284
1285             if (sizeLimited) {
1286                 var minCanvasWidth = Number(options.minCanvasWidth) || 0;
1287                 var minCanvasHeight = Number(options.minCanvasHeight) || 0;
1288
1289                 if (viewMode > 1) {
1290                     minCanvasWidth = Math.max(minCanvasWidth, containerData.width);
1291                     minCanvasHeight = Math.max(minCanvasHeight, containerData.height);
1292
1293                     if (viewMode === 3) {
1294                         if (minCanvasHeight * aspectRatio > minCanvasWidth) {
1295                             minCanvasWidth = minCanvasHeight * aspectRatio;
1296                         } else {
1297                             minCanvasHeight = minCanvasWidth / aspectRatio;
1298                         }
1299                     }
1300                 } else if (viewMode > 0) {
1301                     if (minCanvasWidth) {
1302                         minCanvasWidth = Math.max(minCanvasWidth, cropped ? cropBoxData.width : 0);
1303                     } else if (minCanvasHeight) {
1304                         minCanvasHeight = Math.max(minCanvasHeight, cropped ? cropBoxData.height : 0);
1305                     } else if (cropped) {
1306                         minCanvasWidth = cropBoxData.width;
1307                         minCanvasHeight = cropBoxData.height;
1308
1309                         if (minCanvasHeight * aspectRatio > minCanvasWidth) {
1310                             minCanvasWidth = minCanvasHeight * aspectRatio;
1311                         } else {
1312                             minCanvasHeight = minCanvasWidth / aspectRatio;
1313                         }
1314                     }
1315                 }
1316
1317                 var _getAdjustedSizes = getAdjustedSizes({
1318                     aspectRatio: aspectRatio,
1319                     width: minCanvasWidth,
1320                     height: minCanvasHeight
1321                 });
1322
1323                 minCanvasWidth = _getAdjustedSizes.width;
1324                 minCanvasHeight = _getAdjustedSizes.height;
1325                 canvasData.minWidth = minCanvasWidth;
1326                 canvasData.minHeight = minCanvasHeight;
1327                 canvasData.maxWidth = Infinity;
1328                 canvasData.maxHeight = Infinity;
1329             }
1330
1331             if (positionLimited) {
1332                 if (viewMode > (cropped ? 0 : 1)) {
1333                     var newCanvasLeft = containerData.width - canvasData.width;
1334                     var newCanvasTop = containerData.height - canvasData.height;
1335                     canvasData.minLeft = Math.min(0, newCanvasLeft);
1336                     canvasData.minTop = Math.min(0, newCanvasTop);
1337                     canvasData.maxLeft = Math.max(0, newCanvasLeft);
1338                     canvasData.maxTop = Math.max(0, newCanvasTop);
1339
1340                     if (cropped && this.limited) {
1341                         canvasData.minLeft = Math.min(cropBoxData.left, cropBoxData.left + (cropBoxData.width - canvasData.width));
1342                         canvasData.minTop = Math.min(cropBoxData.top, cropBoxData.top + (cropBoxData.height - canvasData.height));
1343                         canvasData.maxLeft = cropBoxData.left;
1344                         canvasData.maxTop = cropBoxData.top;
1345
1346                         if (viewMode === 2) {
1347                             if (canvasData.width >= containerData.width) {
1348                                 canvasData.minLeft = Math.min(0, newCanvasLeft);
1349                                 canvasData.maxLeft = Math.max(0, newCanvasLeft);
1350                             }
1351
1352                             if (canvasData.height >= containerData.height) {
1353                                 canvasData.minTop = Math.min(0, newCanvasTop);
1354                                 canvasData.maxTop = Math.max(0, newCanvasTop);
1355                             }
1356                         }
1357                     }
1358                 } else {
1359                     canvasData.minLeft = -canvasData.width;
1360                     canvasData.minTop = -canvasData.height;
1361                     canvasData.maxLeft = containerData.width;
1362                     canvasData.maxTop = containerData.height;
1363                 }
1364             }
1365         },
1366         renderCanvas: function renderCanvas(changed, transformed) {
1367             var canvasData = this.canvasData,
1368                 imageData = this.imageData;
1369
1370             if (transformed) {
1371                 var _getRotatedSizes = getRotatedSizes({
1372                         width: imageData.naturalWidth * Math.abs(imageData.scaleX || 1),
1373                         height: imageData.naturalHeight * Math.abs(imageData.scaleY || 1),
1374                         degree: imageData.rotate || 0
1375                     }),
1376                     naturalWidth = _getRotatedSizes.width,
1377                     naturalHeight = _getRotatedSizes.height;
1378
1379                 var width = canvasData.width * (naturalWidth / canvasData.naturalWidth);
1380                 var height = canvasData.height * (naturalHeight / canvasData.naturalHeight);
1381                 canvasData.left -= (width - canvasData.width) / 2;
1382                 canvasData.top -= (height - canvasData.height) / 2;
1383                 canvasData.width = width;
1384                 canvasData.height = height;
1385                 canvasData.aspectRatio = naturalWidth / naturalHeight;
1386                 canvasData.naturalWidth = naturalWidth;
1387                 canvasData.naturalHeight = naturalHeight;
1388                 this.limitCanvas(true, false);
1389             }
1390
1391             if (canvasData.width > canvasData.maxWidth || canvasData.width < canvasData.minWidth) {
1392                 canvasData.left = canvasData.oldLeft;
1393             }
1394
1395             if (canvasData.height > canvasData.maxHeight || canvasData.height < canvasData.minHeight) {
1396                 canvasData.top = canvasData.oldTop;
1397             }
1398
1399             canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth);
1400             canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight);
1401             this.limitCanvas(false, true);
1402             canvasData.left = Math.min(Math.max(canvasData.left, canvasData.minLeft), canvasData.maxLeft);
1403             canvasData.top = Math.min(Math.max(canvasData.top, canvasData.minTop), canvasData.maxTop);
1404             canvasData.oldLeft = canvasData.left;
1405             canvasData.oldTop = canvasData.top;
1406             setStyle(this.canvas, assign({
1407                 width: canvasData.width,
1408                 height: canvasData.height
1409             }, getTransforms({
1410                 translateX: canvasData.left,
1411                 translateY: canvasData.top
1412             })));
1413             this.renderImage(changed);
1414
1415             if (this.cropped && this.limited) {
1416                 this.limitCropBox(true, true);
1417             }
1418         },
1419         renderImage: function renderImage(changed) {
1420             var canvasData = this.canvasData,
1421                 imageData = this.imageData;
1422             var width = imageData.naturalWidth * (canvasData.width / canvasData.naturalWidth);
1423             var height = imageData.naturalHeight * (canvasData.height / canvasData.naturalHeight);
1424             assign(imageData, {
1425                 width: width,
1426                 height: height,
1427                 left: (canvasData.width - width) / 2,
1428                 top: (canvasData.height - height) / 2
1429             });
1430             setStyle(this.image, assign({
1431                 width: imageData.width,
1432                 height: imageData.height
1433             }, getTransforms(assign({
1434                 translateX: imageData.left,
1435                 translateY: imageData.top
1436             }, imageData))));
1437
1438             if (changed) {
1439                 this.output();
1440             }
1441         },
1442         initCropBox: function initCropBox() {
1443             var options = this.options,
1444                 canvasData = this.canvasData;
1445             var aspectRatio = options.aspectRatio || options.initialAspectRatio;
1446             var autoCropArea = Number(options.autoCropArea) || 0.8;
1447             var cropBoxData = {
1448                 width: canvasData.width,
1449                 height: canvasData.height
1450             };
1451
1452             if (aspectRatio) {
1453                 if (canvasData.height * aspectRatio > canvasData.width) {
1454                     cropBoxData.height = cropBoxData.width / aspectRatio;
1455                 } else {
1456                     cropBoxData.width = cropBoxData.height * aspectRatio;
1457                 }
1458             }
1459
1460             this.cropBoxData = cropBoxData;
1461             this.limitCropBox(true, true); // Initialize auto crop area
1462
1463             cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth);
1464             cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); // The width/height of auto crop area must large than "minWidth/Height"
1465
1466             cropBoxData.width = Math.max(cropBoxData.minWidth, cropBoxData.width * autoCropArea);
1467             cropBoxData.height = Math.max(cropBoxData.minHeight, cropBoxData.height * autoCropArea);
1468             cropBoxData.left = canvasData.left + (canvasData.width - cropBoxData.width) / 2;
1469             cropBoxData.top = canvasData.top + (canvasData.height - cropBoxData.height) / 2;
1470             cropBoxData.oldLeft = cropBoxData.left;
1471             cropBoxData.oldTop = cropBoxData.top;
1472             this.initialCropBoxData = assign({}, cropBoxData);
1473         },
1474         limitCropBox: function limitCropBox(sizeLimited, positionLimited) {
1475             var options = this.options,
1476                 containerData = this.containerData,
1477                 canvasData = this.canvasData,
1478                 cropBoxData = this.cropBoxData,
1479                 limited = this.limited;
1480             var aspectRatio = options.aspectRatio;
1481
1482             if (sizeLimited) {
1483                 var minCropBoxWidth = Number(options.minCropBoxWidth) || 0;
1484                 var minCropBoxHeight = Number(options.minCropBoxHeight) || 0;
1485                 var maxCropBoxWidth = limited ? Math.min(containerData.width, canvasData.width, canvasData.width + canvasData.left, containerData.width - canvasData.left) : containerData.width;
1486                 var maxCropBoxHeight = limited ? Math.min(containerData.height, canvasData.height, canvasData.height + canvasData.top, containerData.height - canvasData.top) : containerData.height; // The min/maxCropBoxWidth/Height must be less than container's width/height
1487
1488                 minCropBoxWidth = Math.min(minCropBoxWidth, containerData.width);
1489                 minCropBoxHeight = Math.min(minCropBoxHeight, containerData.height);
1490
1491                 if (aspectRatio) {
1492                     if (minCropBoxWidth && minCropBoxHeight) {
1493                         if (minCropBoxHeight * aspectRatio > minCropBoxWidth) {
1494                             minCropBoxHeight = minCropBoxWidth / aspectRatio;
1495                         } else {
1496                             minCropBoxWidth = minCropBoxHeight * aspectRatio;
1497                         }
1498                     } else if (minCropBoxWidth) {
1499                         minCropBoxHeight = minCropBoxWidth / aspectRatio;
1500                     } else if (minCropBoxHeight) {
1501                         minCropBoxWidth = minCropBoxHeight * aspectRatio;
1502                     }
1503
1504                     if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) {
1505                         maxCropBoxHeight = maxCropBoxWidth / aspectRatio;
1506                     } else {
1507                         maxCropBoxWidth = maxCropBoxHeight * aspectRatio;
1508                     }
1509                 } // The minWidth/Height must be less than maxWidth/Height
1510
1511
1512                 cropBoxData.minWidth = Math.min(minCropBoxWidth, maxCropBoxWidth);
1513                 cropBoxData.minHeight = Math.min(minCropBoxHeight, maxCropBoxHeight);
1514                 cropBoxData.maxWidth = maxCropBoxWidth;
1515                 cropBoxData.maxHeight = maxCropBoxHeight;
1516             }
1517
1518             if (positionLimited) {
1519                 if (limited) {
1520                     cropBoxData.minLeft = Math.max(0, canvasData.left);
1521                     cropBoxData.minTop = Math.max(0, canvasData.top);
1522                     cropBoxData.maxLeft = Math.min(containerData.width, canvasData.left + canvasData.width) - cropBoxData.width;
1523                     cropBoxData.maxTop = Math.min(containerData.height, canvasData.top + canvasData.height) - cropBoxData.height;
1524                 } else {
1525                     cropBoxData.minLeft = 0;
1526                     cropBoxData.minTop = 0;
1527                     cropBoxData.maxLeft = containerData.width - cropBoxData.width;
1528                     cropBoxData.maxTop = containerData.height - cropBoxData.height;
1529                 }
1530             }
1531         },
1532         renderCropBox: function renderCropBox() {
1533             var options = this.options,
1534                 containerData = this.containerData,
1535                 cropBoxData = this.cropBoxData;
1536
1537             if (cropBoxData.width > cropBoxData.maxWidth || cropBoxData.width < cropBoxData.minWidth) {
1538                 cropBoxData.left = cropBoxData.oldLeft;
1539             }
1540
1541             if (cropBoxData.height > cropBoxData.maxHeight || cropBoxData.height < cropBoxData.minHeight) {
1542                 cropBoxData.top = cropBoxData.oldTop;
1543             }
1544
1545             cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth);
1546             cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight);
1547             this.limitCropBox(false, true);
1548             cropBoxData.left = Math.min(Math.max(cropBoxData.left, cropBoxData.minLeft), cropBoxData.maxLeft);
1549             cropBoxData.top = Math.min(Math.max(cropBoxData.top, cropBoxData.minTop), cropBoxData.maxTop);
1550             cropBoxData.oldLeft = cropBoxData.left;
1551             cropBoxData.oldTop = cropBoxData.top;
1552
1553             if (options.movable && options.cropBoxMovable) {
1554                 // Turn to move the canvas when the crop box is equal to the container
1555                 setData(this.face, DATA_ACTION, cropBoxData.width >= containerData.width && cropBoxData.height >= containerData.height ? ACTION_MOVE : ACTION_ALL);
1556             }
1557
1558             setStyle(this.cropBox, assign({
1559                 width: cropBoxData.width,
1560                 height: cropBoxData.height
1561             }, getTransforms({
1562                 translateX: cropBoxData.left,
1563                 translateY: cropBoxData.top
1564             })));
1565
1566             if (this.cropped && this.limited) {
1567                 this.limitCanvas(true, true);
1568             }
1569
1570             if (!this.disabled) {
1571                 this.output();
1572             }
1573         },
1574         output: function output() {
1575             this.preview();
1576             dispatchEvent(this.element, EVENT_CROP, this.getData());
1577         }
1578     };
1579
1580     var preview = {
1581         initPreview: function initPreview() {
1582             var crossOrigin = this.crossOrigin;
1583             var preview = this.options.preview;
1584             var url = crossOrigin ? this.crossOriginUrl : this.url;
1585             var image = document.createElement('img');
1586
1587             if (crossOrigin) {
1588                 image.crossOrigin = crossOrigin;
1589             }
1590
1591             image.src = url;
1592             this.viewBox.appendChild(image);
1593             this.viewBoxImage = image;
1594
1595             if (!preview) {
1596                 return;
1597             }
1598
1599             var previews = preview;
1600
1601             if (typeof preview === 'string') {
1602                 previews = this.element.ownerDocument.querySelectorAll(preview);
1603             } else if (preview.querySelector) {
1604                 previews = [preview];
1605             }
1606
1607             this.previews = previews;
1608             forEach(previews, function (el) {
1609                 var img = document.createElement('img'); // Save the original size for recover
1610
1611                 setData(el, DATA_PREVIEW, {
1612                     width: el.offsetWidth,
1613                     height: el.offsetHeight,
1614                     html: el.innerHTML
1615                 });
1616
1617                 if (crossOrigin) {
1618                     img.crossOrigin = crossOrigin;
1619                 }
1620
1621                 img.src = url;
1622                 /**
1623                  * Override img element styles
1624                  * Add `display:block` to avoid margin top issue
1625                  * Add `height:auto` to override `height` attribute on IE8
1626                  * (Occur only when margin-top <= -height)
1627                  */
1628
1629                 img.style.cssText = '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;"';
1630                 el.innerHTML = '';
1631                 el.appendChild(img);
1632             });
1633         },
1634         resetPreview: function resetPreview() {
1635             forEach(this.previews, function (element) {
1636                 var data = getData(element, DATA_PREVIEW);
1637                 setStyle(element, {
1638                     width: data.width,
1639                     height: data.height
1640                 });
1641                 element.innerHTML = data.html;
1642                 removeData(element, DATA_PREVIEW);
1643             });
1644         },
1645         preview: function preview() {
1646             var imageData = this.imageData,
1647                 canvasData = this.canvasData,
1648                 cropBoxData = this.cropBoxData;
1649             var cropBoxWidth = cropBoxData.width,
1650                 cropBoxHeight = cropBoxData.height;
1651             var width = imageData.width,
1652                 height = imageData.height;
1653             var left = cropBoxData.left - canvasData.left - imageData.left;
1654             var top = cropBoxData.top - canvasData.top - imageData.top;
1655
1656             if (!this.cropped || this.disabled) {
1657                 return;
1658             }
1659
1660             setStyle(this.viewBoxImage, assign({
1661                 width: width,
1662                 height: height
1663             }, getTransforms(assign({
1664                 translateX: -left,
1665                 translateY: -top
1666             }, imageData))));
1667             forEach(this.previews, function (element) {
1668                 var data = getData(element, DATA_PREVIEW);
1669                 var originalWidth = data.width;
1670                 var originalHeight = data.height;
1671                 var newWidth = originalWidth;
1672                 var newHeight = originalHeight;
1673                 var ratio = 1;
1674
1675                 if (cropBoxWidth) {
1676                     ratio = originalWidth / cropBoxWidth;
1677                     newHeight = cropBoxHeight * ratio;
1678                 }
1679
1680                 if (cropBoxHeight && newHeight > originalHeight) {
1681                     ratio = originalHeight / cropBoxHeight;
1682                     newWidth = cropBoxWidth * ratio;
1683                     newHeight = originalHeight;
1684                 }
1685
1686                 setStyle(element, {
1687                     width: newWidth,
1688                     height: newHeight
1689                 });
1690                 setStyle(element.getElementsByTagName('img')[0], assign({
1691                     width: width * ratio,
1692                     height: height * ratio
1693                 }, getTransforms(assign({
1694                     translateX: -left * ratio,
1695                     translateY: -top * ratio
1696                 }, imageData))));
1697             });
1698         }
1699     };
1700
1701     var events = {
1702         bind: function bind() {
1703             var element = this.element,
1704                 options = this.options,
1705                 cropper = this.cropper;
1706
1707             if (isFunction(options.cropstart)) {
1708                 addListener(element, EVENT_CROP_START, options.cropstart);
1709             }
1710
1711             if (isFunction(options.cropmove)) {
1712                 addListener(element, EVENT_CROP_MOVE, options.cropmove);
1713             }
1714
1715             if (isFunction(options.cropend)) {
1716                 addListener(element, EVENT_CROP_END, options.cropend);
1717             }
1718
1719             if (isFunction(options.crop)) {
1720                 addListener(element, EVENT_CROP, options.crop);
1721             }
1722
1723             if (isFunction(options.zoom)) {
1724                 addListener(element, EVENT_ZOOM, options.zoom);
1725             }
1726
1727             addListener(cropper, EVENT_POINTER_DOWN, this.onCropStart = this.cropStart.bind(this));
1728
1729             if (options.zoomable && options.zoomOnWheel) {
1730                 addListener(cropper, EVENT_WHEEL, this.onWheel = this.wheel.bind(this), {
1731                     passive: false,
1732                     capture: true
1733                 });
1734             }
1735
1736             if (options.toggleDragModeOnDblclick) {
1737                 addListener(cropper, EVENT_DBLCLICK, this.onDblclick = this.dblclick.bind(this));
1738             }
1739
1740             addListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove = this.cropMove.bind(this));
1741             addListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd = this.cropEnd.bind(this));
1742
1743             if (options.responsive) {
1744                 addListener(window, EVENT_RESIZE, this.onResize = this.resize.bind(this));
1745             }
1746         },
1747         unbind: function unbind() {
1748             var element = this.element,
1749                 options = this.options,
1750                 cropper = this.cropper;
1751
1752             if (isFunction(options.cropstart)) {
1753                 removeListener(element, EVENT_CROP_START, options.cropstart);
1754             }
1755
1756             if (isFunction(options.cropmove)) {
1757                 removeListener(element, EVENT_CROP_MOVE, options.cropmove);
1758             }
1759
1760             if (isFunction(options.cropend)) {
1761                 removeListener(element, EVENT_CROP_END, options.cropend);
1762             }
1763
1764             if (isFunction(options.crop)) {
1765                 removeListener(element, EVENT_CROP, options.crop);
1766             }
1767
1768             if (isFunction(options.zoom)) {
1769                 removeListener(element, EVENT_ZOOM, options.zoom);
1770             }
1771
1772             removeListener(cropper, EVENT_POINTER_DOWN, this.onCropStart);
1773
1774             if (options.zoomable && options.zoomOnWheel) {
1775                 removeListener(cropper, EVENT_WHEEL, this.onWheel, {
1776                     passive: false,
1777                     capture: true
1778                 });
1779             }
1780
1781             if (options.toggleDragModeOnDblclick) {
1782                 removeListener(cropper, EVENT_DBLCLICK, this.onDblclick);
1783             }
1784
1785             removeListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove);
1786             removeListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd);
1787
1788             if (options.responsive) {
1789                 removeListener(window, EVENT_RESIZE, this.onResize);
1790             }
1791         }
1792     };
1793
1794     var handlers = {
1795         resize: function resize() {
1796             var options = this.options,
1797                 container = this.container,
1798                 containerData = this.containerData;
1799             var minContainerWidth = Number(options.minContainerWidth) || MIN_CONTAINER_WIDTH;
1800             var minContainerHeight = Number(options.minContainerHeight) || MIN_CONTAINER_HEIGHT;
1801
1802             if (this.disabled || containerData.width <= minContainerWidth || containerData.height <= minContainerHeight) {
1803                 return;
1804             }
1805
1806             var ratio = container.offsetWidth / containerData.width; // Resize when width changed or height changed
1807
1808             if (ratio !== 1 || container.offsetHeight !== containerData.height) {
1809                 var canvasData;
1810                 var cropBoxData;
1811
1812                 if (options.restore) {
1813                     canvasData = this.getCanvasData();
1814                     cropBoxData = this.getCropBoxData();
1815                 }
1816
1817                 this.render();
1818
1819                 if (options.restore) {
1820                     this.setCanvasData(forEach(canvasData, function (n, i) {
1821                         canvasData[i] = n * ratio;
1822                     }));
1823                     this.setCropBoxData(forEach(cropBoxData, function (n, i) {
1824                         cropBoxData[i] = n * ratio;
1825                     }));
1826                 }
1827             }
1828         },
1829         dblclick: function dblclick() {
1830             if (this.disabled || this.options.dragMode === DRAG_MODE_NONE) {
1831                 return;
1832             }
1833
1834             this.setDragMode(hasClass(this.dragBox, CLASS_CROP) ? DRAG_MODE_MOVE : DRAG_MODE_CROP);
1835         },
1836         wheel: function wheel(event) {
1837             var _this = this;
1838
1839             var ratio = Number(this.options.wheelZoomRatio) || 0.1;
1840             var delta = 1;
1841
1842             if (this.disabled) {
1843                 return;
1844             }
1845
1846             event.preventDefault(); // Limit wheel speed to prevent zoom too fast (#21)
1847
1848             if (this.wheeling) {
1849                 return;
1850             }
1851
1852             this.wheeling = true;
1853             setTimeout(function () {
1854                 _this.wheeling = false;
1855             }, 50);
1856
1857             if (event.deltaY) {
1858                 delta = event.deltaY > 0 ? 1 : -1;
1859             } else if (event.wheelDelta) {
1860                 delta = -event.wheelDelta / 120;
1861             } else if (event.detail) {
1862                 delta = event.detail > 0 ? 1 : -1;
1863             }
1864
1865             this.zoom(-delta * ratio, event);
1866         },
1867         cropStart: function cropStart(event) {
1868             var buttons = event.buttons,
1869                 button = event.button;
1870
1871             if (this.disabled // No primary button (Usually the left button)
1872                 // Note that touch events have no `buttons` or `button` property
1873                 || isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 // Open context menu
1874                 || event.ctrlKey) {
1875                 return;
1876             }
1877
1878             var options = this.options,
1879                 pointers = this.pointers;
1880             var action;
1881
1882             if (event.changedTouches) {
1883                 // Handle touch event
1884                 forEach(event.changedTouches, function (touch) {
1885                     pointers[touch.identifier] = getPointer(touch);
1886                 });
1887             } else {
1888                 // Handle mouse event and pointer event
1889                 pointers[event.pointerId || 0] = getPointer(event);
1890             }
1891
1892             if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) {
1893                 action = ACTION_ZOOM;
1894             } else {
1895                 action = getData(event.target, DATA_ACTION);
1896             }
1897
1898             if (!REGEXP_ACTIONS.test(action)) {
1899                 return;
1900             }
1901
1902             if (dispatchEvent(this.element, EVENT_CROP_START, {
1903                 originalEvent: event,
1904                 action: action
1905             }) === false) {
1906                 return;
1907             } // This line is required for preventing page zooming in iOS browsers
1908
1909
1910             event.preventDefault();
1911             this.action = action;
1912             this.cropping = false;
1913
1914             if (action === ACTION_CROP) {
1915                 this.cropping = true;
1916                 addClass(this.dragBox, CLASS_MODAL);
1917             }
1918         },
1919         cropMove: function cropMove(event) {
1920             var action = this.action;
1921
1922             if (this.disabled || !action) {
1923                 return;
1924             }
1925
1926             var pointers = this.pointers;
1927             event.preventDefault();
1928
1929             if (dispatchEvent(this.element, EVENT_CROP_MOVE, {
1930                 originalEvent: event,
1931                 action: action
1932             }) === false) {
1933                 return;
1934             }
1935
1936             if (event.changedTouches) {
1937                 forEach(event.changedTouches, function (touch) {
1938                     // The first parameter should not be undefined (#432)
1939                     assign(pointers[touch.identifier] || {}, getPointer(touch, true));
1940                 });
1941             } else {
1942                 assign(pointers[event.pointerId || 0] || {}, getPointer(event, true));
1943             }
1944
1945             this.change(event);
1946         },
1947         cropEnd: function cropEnd(event) {
1948             if (this.disabled) {
1949                 return;
1950             }
1951
1952             var action = this.action,
1953                 pointers = this.pointers;
1954
1955             if (event.changedTouches) {
1956                 forEach(event.changedTouches, function (touch) {
1957                     delete pointers[touch.identifier];
1958                 });
1959             } else {
1960                 delete pointers[event.pointerId || 0];
1961             }
1962
1963             if (!action) {
1964                 return;
1965             }
1966
1967             event.preventDefault();
1968
1969             if (!Object.keys(pointers).length) {
1970                 this.action = '';
1971             }
1972
1973             if (this.cropping) {
1974                 this.cropping = false;
1975                 toggleClass(this.dragBox, CLASS_MODAL, this.cropped && this.options.modal);
1976             }
1977
1978             dispatchEvent(this.element, EVENT_CROP_END, {
1979                 originalEvent: event,
1980                 action: action
1981             });
1982         }
1983     };
1984
1985     var change = {
1986         change: function change(event) {
1987             var options = this.options,
1988                 canvasData = this.canvasData,
1989                 containerData = this.containerData,
1990                 cropBoxData = this.cropBoxData,
1991                 pointers = this.pointers;
1992             var action = this.action;
1993             var aspectRatio = options.aspectRatio;
1994             var left = cropBoxData.left,
1995                 top = cropBoxData.top,
1996                 width = cropBoxData.width,
1997                 height = cropBoxData.height;
1998             var right = left + width;
1999             var bottom = top + height;
2000             var minLeft = 0;
2001             var minTop = 0;
2002             var maxWidth = containerData.width;
2003             var maxHeight = containerData.height;
2004             var renderable = true;
2005             var offset; // Locking aspect ratio in "free mode" by holding shift key
2006
2007             if (!aspectRatio && event.shiftKey) {
2008                 aspectRatio = width && height ? width / height : 1;
2009             }
2010
2011             if (this.limited) {
2012                 minLeft = cropBoxData.minLeft;
2013                 minTop = cropBoxData.minTop;
2014                 maxWidth = minLeft + Math.min(containerData.width, canvasData.width, canvasData.left + canvasData.width);
2015                 maxHeight = minTop + Math.min(containerData.height, canvasData.height, canvasData.top + canvasData.height);
2016             }
2017
2018             var pointer = pointers[Object.keys(pointers)[0]];
2019             var range = {
2020                 x: pointer.endX - pointer.startX,
2021                 y: pointer.endY - pointer.startY
2022             };
2023
2024             var check = function check(side) {
2025                 switch (side) {
2026                     case ACTION_EAST:
2027                         if (right + range.x > maxWidth) {
2028                             range.x = maxWidth - right;
2029                         }
2030
2031                         break;
2032
2033                     case ACTION_WEST:
2034                         if (left + range.x < minLeft) {
2035                             range.x = minLeft - left;
2036                         }
2037
2038                         break;
2039
2040                     case ACTION_NORTH:
2041                         if (top + range.y < minTop) {
2042                             range.y = minTop - top;
2043                         }
2044
2045                         break;
2046
2047                     case ACTION_SOUTH:
2048                         if (bottom + range.y > maxHeight) {
2049                             range.y = maxHeight - bottom;
2050                         }
2051
2052                         break;
2053
2054                     default:
2055                 }
2056             };
2057
2058             switch (action) {
2059                 // Move crop box
2060                 case ACTION_ALL:
2061                     left += range.x;
2062                     top += range.y;
2063                     break;
2064                 // Resize crop box
2065
2066                 case ACTION_EAST:
2067                     if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) {
2068                         renderable = false;
2069                         break;
2070                     }
2071
2072                     check(ACTION_EAST);
2073                     width += range.x;
2074
2075                     if (width < 0) {
2076                         action = ACTION_WEST;
2077                         width = -width;
2078                         left -= width;
2079                     }
2080
2081                     if (aspectRatio) {
2082                         height = width / aspectRatio;
2083                         top += (cropBoxData.height - height) / 2;
2084                     }
2085
2086                     break;
2087
2088                 case ACTION_NORTH:
2089                     if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) {
2090                         renderable = false;
2091                         break;
2092                     }
2093
2094                     check(ACTION_NORTH);
2095                     height -= range.y;
2096                     top += range.y;
2097
2098                     if (height < 0) {
2099                         action = ACTION_SOUTH;
2100                         height = -height;
2101                         top -= height;
2102                     }
2103
2104                     if (aspectRatio) {
2105                         width = height * aspectRatio;
2106                         left += (cropBoxData.width - width) / 2;
2107                     }
2108
2109                     break;
2110
2111                 case ACTION_WEST:
2112                     if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) {
2113                         renderable = false;
2114                         break;
2115                     }
2116
2117                     check(ACTION_WEST);
2118                     width -= range.x;
2119                     left += range.x;
2120
2121                     if (width < 0) {
2122                         action = ACTION_EAST;
2123                         width = -width;
2124                         left -= width;
2125                     }
2126
2127                     if (aspectRatio) {
2128                         height = width / aspectRatio;
2129                         top += (cropBoxData.height - height) / 2;
2130                     }
2131
2132                     break;
2133
2134                 case ACTION_SOUTH:
2135                     if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) {
2136                         renderable = false;
2137                         break;
2138                     }
2139
2140                     check(ACTION_SOUTH);
2141                     height += range.y;
2142
2143                     if (height < 0) {
2144                         action = ACTION_NORTH;
2145                         height = -height;
2146                         top -= height;
2147                     }
2148
2149                     if (aspectRatio) {
2150                         width = height * aspectRatio;
2151                         left += (cropBoxData.width - width) / 2;
2152                     }
2153
2154                     break;
2155
2156                 case ACTION_NORTH_EAST:
2157                     if (aspectRatio) {
2158                         if (range.y <= 0 && (top <= minTop || right >= maxWidth)) {
2159                             renderable = false;
2160                             break;
2161                         }
2162
2163                         check(ACTION_NORTH);
2164                         height -= range.y;
2165                         top += range.y;
2166                         width = height * aspectRatio;
2167                     } else {
2168                         check(ACTION_NORTH);
2169                         check(ACTION_EAST);
2170
2171                         if (range.x >= 0) {
2172                             if (right < maxWidth) {
2173                                 width += range.x;
2174                             } else if (range.y <= 0 && top <= minTop) {
2175                                 renderable = false;
2176                             }
2177                         } else {
2178                             width += range.x;
2179                         }
2180
2181                         if (range.y <= 0) {
2182                             if (top > minTop) {
2183                                 height -= range.y;
2184                                 top += range.y;
2185                             }
2186                         } else {
2187                             height -= range.y;
2188                             top += range.y;
2189                         }
2190                     }
2191
2192                     if (width < 0 && height < 0) {
2193                         action = ACTION_SOUTH_WEST;
2194                         height = -height;
2195                         width = -width;
2196                         top -= height;
2197                         left -= width;
2198                     } else if (width < 0) {
2199                         action = ACTION_NORTH_WEST;
2200                         width = -width;
2201                         left -= width;
2202                     } else if (height < 0) {
2203                         action = ACTION_SOUTH_EAST;
2204                         height = -height;
2205                         top -= height;
2206                     }
2207
2208                     break;
2209
2210                 case ACTION_NORTH_WEST:
2211                     if (aspectRatio) {
2212                         if (range.y <= 0 && (top <= minTop || left <= minLeft)) {
2213                             renderable = false;
2214                             break;
2215                         }
2216
2217                         check(ACTION_NORTH);
2218                         height -= range.y;
2219                         top += range.y;
2220                         width = height * aspectRatio;
2221                         left += cropBoxData.width - width;
2222                     } else {
2223                         check(ACTION_NORTH);
2224                         check(ACTION_WEST);
2225
2226                         if (range.x <= 0) {
2227                             if (left > minLeft) {
2228                                 width -= range.x;
2229                                 left += range.x;
2230                             } else if (range.y <= 0 && top <= minTop) {
2231                                 renderable = false;
2232                             }
2233                         } else {
2234                             width -= range.x;
2235                             left += range.x;
2236                         }
2237
2238                         if (range.y <= 0) {
2239                             if (top > minTop) {
2240                                 height -= range.y;
2241                                 top += range.y;
2242                             }
2243                         } else {
2244                             height -= range.y;
2245                             top += range.y;
2246                         }
2247                     }
2248
2249                     if (width < 0 && height < 0) {
2250                         action = ACTION_SOUTH_EAST;
2251                         height = -height;
2252                         width = -width;
2253                         top -= height;
2254                         left -= width;
2255                     } else if (width < 0) {
2256                         action = ACTION_NORTH_EAST;
2257                         width = -width;
2258                         left -= width;
2259                     } else if (height < 0) {
2260                         action = ACTION_SOUTH_WEST;
2261                         height = -height;
2262                         top -= height;
2263                     }
2264
2265                     break;
2266
2267                 case ACTION_SOUTH_WEST:
2268                     if (aspectRatio) {
2269                         if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) {
2270                             renderable = false;
2271                             break;
2272                         }
2273
2274                         check(ACTION_WEST);
2275                         width -= range.x;
2276                         left += range.x;
2277                         height = width / aspectRatio;
2278                     } else {
2279                         check(ACTION_SOUTH);
2280                         check(ACTION_WEST);
2281
2282                         if (range.x <= 0) {
2283                             if (left > minLeft) {
2284                                 width -= range.x;
2285                                 left += range.x;
2286                             } else if (range.y >= 0 && bottom >= maxHeight) {
2287                                 renderable = false;
2288                             }
2289                         } else {
2290                             width -= range.x;
2291                             left += range.x;
2292                         }
2293
2294                         if (range.y >= 0) {
2295                             if (bottom < maxHeight) {
2296                                 height += range.y;
2297                             }
2298                         } else {
2299                             height += range.y;
2300                         }
2301                     }
2302
2303                     if (width < 0 && height < 0) {
2304                         action = ACTION_NORTH_EAST;
2305                         height = -height;
2306                         width = -width;
2307                         top -= height;
2308                         left -= width;
2309                     } else if (width < 0) {
2310                         action = ACTION_SOUTH_EAST;
2311                         width = -width;
2312                         left -= width;
2313                     } else if (height < 0) {
2314                         action = ACTION_NORTH_WEST;
2315                         height = -height;
2316                         top -= height;
2317                     }
2318
2319                     break;
2320
2321                 case ACTION_SOUTH_EAST:
2322                     if (aspectRatio) {
2323                         if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {
2324                             renderable = false;
2325                             break;
2326                         }
2327
2328                         check(ACTION_EAST);
2329                         width += range.x;
2330                         height = width / aspectRatio;
2331                     } else {
2332                         check(ACTION_SOUTH);
2333                         check(ACTION_EAST);
2334
2335                         if (range.x >= 0) {
2336                             if (right < maxWidth) {
2337                                 width += range.x;
2338                             } else if (range.y >= 0 && bottom >= maxHeight) {
2339                                 renderable = false;
2340                             }
2341                         } else {
2342                             width += range.x;
2343                         }
2344
2345                         if (range.y >= 0) {
2346                             if (bottom < maxHeight) {
2347                                 height += range.y;
2348                             }
2349                         } else {
2350                             height += range.y;
2351                         }
2352                     }
2353
2354                     if (width < 0 && height < 0) {
2355                         action = ACTION_NORTH_WEST;
2356                         height = -height;
2357                         width = -width;
2358                         top -= height;
2359                         left -= width;
2360                     } else if (width < 0) {
2361                         action = ACTION_SOUTH_WEST;
2362                         width = -width;
2363                         left -= width;
2364                     } else if (height < 0) {
2365                         action = ACTION_NORTH_EAST;
2366                         height = -height;
2367                         top -= height;
2368                     }
2369
2370                     break;
2371                 // Move canvas
2372
2373                 case ACTION_MOVE:
2374                     this.move(range.x, range.y);
2375                     renderable = false;
2376                     break;
2377                 // Zoom canvas
2378
2379                 case ACTION_ZOOM:
2380                     this.zoom(getMaxZoomRatio(pointers), event);
2381                     renderable = false;
2382                     break;
2383                 // Create crop box
2384
2385                 case ACTION_CROP:
2386                     if (!range.x || !range.y) {
2387                         renderable = false;
2388                         break;
2389                     }
2390
2391                     offset = getOffset(this.cropper);
2392                     left = pointer.startX - offset.left;
2393                     top = pointer.startY - offset.top;
2394                     width = cropBoxData.minWidth;
2395                     height = cropBoxData.minHeight;
2396
2397                     if (range.x > 0) {
2398                         action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST;
2399                     } else if (range.x < 0) {
2400                         left -= width;
2401                         action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST;
2402                     }
2403
2404                     if (range.y < 0) {
2405                         top -= height;
2406                     } // Show the crop box if is hidden
2407
2408
2409                     if (!this.cropped) {
2410                         removeClass(this.cropBox, CLASS_HIDDEN);
2411                         this.cropped = true;
2412
2413                         if (this.limited) {
2414                             this.limitCropBox(true, true);
2415                         }
2416                     }
2417
2418                     break;
2419
2420                 default:
2421             }
2422
2423             if (renderable) {
2424                 cropBoxData.width = width;
2425                 cropBoxData.height = height;
2426                 cropBoxData.left = left;
2427                 cropBoxData.top = top;
2428                 this.action = action;
2429                 this.renderCropBox();
2430             } // Override
2431
2432
2433             forEach(pointers, function (p) {
2434                 p.startX = p.endX;
2435                 p.startY = p.endY;
2436             });
2437         }
2438     };
2439
2440     var methods = {
2441         // Show the crop box manually
2442         crop: function crop() {
2443             if (this.ready && !this.cropped && !this.disabled) {
2444                 this.cropped = true;
2445                 this.limitCropBox(true, true);
2446
2447                 if (this.options.modal) {
2448                     addClass(this.dragBox, CLASS_MODAL);
2449                 }
2450
2451                 removeClass(this.cropBox, CLASS_HIDDEN);
2452                 this.setCropBoxData(this.initialCropBoxData);
2453             }
2454
2455             return this;
2456         },
2457         // Reset the image and crop box to their initial states
2458         reset: function reset() {
2459             if (this.ready && !this.disabled) {
2460                 this.imageData = assign({}, this.initialImageData);
2461                 this.canvasData = assign({}, this.initialCanvasData);
2462                 this.cropBoxData = assign({}, this.initialCropBoxData);
2463                 this.renderCanvas();
2464
2465                 if (this.cropped) {
2466                     this.renderCropBox();
2467                 }
2468             }
2469
2470             return this;
2471         },
2472         // Clear the crop box
2473         clear: function clear() {
2474             if (this.cropped && !this.disabled) {
2475                 assign(this.cropBoxData, {
2476                     left: 0,
2477                     top: 0,
2478                     width: 0,
2479                     height: 0
2480                 });
2481                 this.cropped = false;
2482                 this.renderCropBox();
2483                 this.limitCanvas(true, true); // Render canvas after crop box rendered
2484
2485                 this.renderCanvas();
2486                 removeClass(this.dragBox, CLASS_MODAL);
2487                 addClass(this.cropBox, CLASS_HIDDEN);
2488             }
2489
2490             return this;
2491         },
2492
2493         /**
2494          * Replace the image's src and rebuild the cropper
2495          * @param {string} url - The new URL.
2496          * @param {boolean} [hasSameSize] - Indicate if the new image has the same size as the old one.
2497          * @returns {Cropper} this
2498          */
2499         replace: function replace(url) {
2500             var hasSameSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2501
2502             if (!this.disabled && url) {
2503                 if (this.isImg) {
2504                     this.element.src = url;
2505                 }
2506
2507                 if (hasSameSize) {
2508                     this.url = url;
2509                     this.image.src = url;
2510
2511                     if (this.ready) {
2512                         this.viewBoxImage.src = url;
2513                         forEach(this.previews, function (element) {
2514                             element.getElementsByTagName('img')[0].src = url;
2515                         });
2516                     }
2517                 } else {
2518                     if (this.isImg) {
2519                         this.replaced = true;
2520                     }
2521
2522                     this.options.data = null;
2523                     this.uncreate();
2524                     this.load(url);
2525                 }
2526             }
2527
2528             return this;
2529         },
2530         // Enable (unfreeze) the cropper
2531         enable: function enable() {
2532             if (this.ready && this.disabled) {
2533                 this.disabled = false;
2534                 removeClass(this.cropper, CLASS_DISABLED);
2535             }
2536
2537             return this;
2538         },
2539         // Disable (freeze) the cropper
2540         disable: function disable() {
2541             if (this.ready && !this.disabled) {
2542                 this.disabled = true;
2543                 addClass(this.cropper, CLASS_DISABLED);
2544             }
2545
2546             return this;
2547         },
2548
2549         /**
2550          * Destroy the cropper and remove the instance from the image
2551          * @returns {Cropper} this
2552          */
2553         destroy: function destroy() {
2554             var element = this.element;
2555
2556             if (!element[NAMESPACE]) {
2557                 return this;
2558             }
2559
2560             element[NAMESPACE] = undefined;
2561
2562             if (this.isImg && this.replaced) {
2563                 element.src = this.originalUrl;
2564             }
2565
2566             this.uncreate();
2567             return this;
2568         },
2569
2570         /**
2571          * Move the canvas with relative offsets
2572          * @param {number} offsetX - The relative offset distance on the x-axis.
2573          * @param {number} [offsetY=offsetX] - The relative offset distance on the y-axis.
2574          * @returns {Cropper} this
2575          */
2576         move: function move(offsetX) {
2577             var offsetY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : offsetX;
2578             var _this$canvasData = this.canvasData,
2579                 left = _this$canvasData.left,
2580                 top = _this$canvasData.top;
2581             return this.moveTo(isUndefined(offsetX) ? offsetX : left + Number(offsetX), isUndefined(offsetY) ? offsetY : top + Number(offsetY));
2582         },
2583
2584         /**
2585          * Move the canvas to an absolute point
2586          * @param {number} x - The x-axis coordinate.
2587          * @param {number} [y=x] - The y-axis coordinate.
2588          * @returns {Cropper} this
2589          */
2590         moveTo: function moveTo(x) {
2591             var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
2592             var canvasData = this.canvasData;
2593             var changed = false;
2594             x = Number(x);
2595             y = Number(y);
2596
2597             if (this.ready && !this.disabled && this.options.movable) {
2598                 if (isNumber(x)) {
2599                     canvasData.left = x;
2600                     changed = true;
2601                 }
2602
2603                 if (isNumber(y)) {
2604                     canvasData.top = y;
2605                     changed = true;
2606                 }
2607
2608                 if (changed) {
2609                     this.renderCanvas(true);
2610                 }
2611             }
2612
2613             return this;
2614         },
2615
2616         /**
2617          * Zoom the canvas with a relative ratio
2618          * @param {number} ratio - The target ratio.
2619          * @param {Event} _originalEvent - The original event if any.
2620          * @returns {Cropper} this
2621          */
2622         zoom: function zoom(ratio, _originalEvent) {
2623             var canvasData = this.canvasData;
2624             ratio = Number(ratio);
2625
2626             if (ratio < 0) {
2627                 ratio = 1 / (1 - ratio);
2628             } else {
2629                 ratio = 1 + ratio;
2630             }
2631
2632             return this.zoomTo(canvasData.width * ratio / canvasData.naturalWidth, null, _originalEvent);
2633         },
2634
2635         /**
2636          * Zoom the canvas to an absolute ratio
2637          * @param {number} ratio - The target ratio.
2638          * @param {Object} pivot - The zoom pivot point coordinate.
2639          * @param {Event} _originalEvent - The original event if any.
2640          * @returns {Cropper} this
2641          */
2642         zoomTo: function zoomTo(ratio, pivot, _originalEvent) {
2643             var options = this.options,
2644                 canvasData = this.canvasData;
2645             var width = canvasData.width,
2646                 height = canvasData.height,
2647                 naturalWidth = canvasData.naturalWidth,
2648                 naturalHeight = canvasData.naturalHeight;
2649             ratio = Number(ratio);
2650
2651             if (ratio >= 0 && this.ready && !this.disabled && options.zoomable) {
2652                 var newWidth = naturalWidth * ratio;
2653                 var newHeight = naturalHeight * ratio;
2654
2655                 if (dispatchEvent(this.element, EVENT_ZOOM, {
2656                     ratio: ratio,
2657                     oldRatio: width / naturalWidth,
2658                     originalEvent: _originalEvent
2659                 }) === false) {
2660                     return this;
2661                 }
2662
2663                 if (_originalEvent) {
2664                     var pointers = this.pointers;
2665                     var offset = getOffset(this.cropper);
2666                     var center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : {
2667                         pageX: _originalEvent.pageX,
2668                         pageY: _originalEvent.pageY
2669                     }; // Zoom from the triggering point of the event
2670
2671                     canvasData.left -= (newWidth - width) * ((center.pageX - offset.left - canvasData.left) / width);
2672                     canvasData.top -= (newHeight - height) * ((center.pageY - offset.top - canvasData.top) / height);
2673                 } else if (isPlainObject(pivot) && isNumber(pivot.x) && isNumber(pivot.y)) {
2674                     canvasData.left -= (newWidth - width) * ((pivot.x - canvasData.left) / width);
2675                     canvasData.top -= (newHeight - height) * ((pivot.y - canvasData.top) / height);
2676                 } else {
2677                     // Zoom from the center of the canvas
2678                     canvasData.left -= (newWidth - width) / 2;
2679                     canvasData.top -= (newHeight - height) / 2;
2680                 }
2681
2682                 canvasData.width = newWidth;
2683                 canvasData.height = newHeight;
2684                 this.renderCanvas(true);
2685             }
2686
2687             return this;
2688         },
2689
2690         /**
2691          * Rotate the canvas with a relative degree
2692          * @param {number} degree - The rotate degree.
2693          * @returns {Cropper} this
2694          */
2695         rotate: function rotate(degree) {
2696             return this.rotateTo((this.imageData.rotate || 0) + Number(degree));
2697         },
2698
2699         /**
2700          * Rotate the canvas to an absolute degree
2701          * @param {number} degree - The rotate degree.
2702          * @returns {Cropper} this
2703          */
2704         rotateTo: function rotateTo(degree) {
2705             degree = Number(degree);
2706
2707             if (isNumber(degree) && this.ready && !this.disabled && this.options.rotatable) {
2708                 this.imageData.rotate = degree % 360;
2709                 this.renderCanvas(true, true);
2710             }
2711
2712             return this;
2713         },
2714
2715         /**
2716          * Scale the image on the x-axis.
2717          * @param {number} scaleX - The scale ratio on the x-axis.
2718          * @returns {Cropper} this
2719          */
2720         scaleX: function scaleX(_scaleX) {
2721             var scaleY = this.imageData.scaleY;
2722             return this.scale(_scaleX, isNumber(scaleY) ? scaleY : 1);
2723         },
2724
2725         /**
2726          * Scale the image on the y-axis.
2727          * @param {number} scaleY - The scale ratio on the y-axis.
2728          * @returns {Cropper} this
2729          */
2730         scaleY: function scaleY(_scaleY) {
2731             var scaleX = this.imageData.scaleX;
2732             return this.scale(isNumber(scaleX) ? scaleX : 1, _scaleY);
2733         },
2734
2735         /**
2736          * Scale the image
2737          * @param {number} scaleX - The scale ratio on the x-axis.
2738          * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis.
2739          * @returns {Cropper} this
2740          */
2741         scale: function scale(scaleX) {
2742             var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX;
2743             var imageData = this.imageData;
2744             var transformed = false;
2745             scaleX = Number(scaleX);
2746             scaleY = Number(scaleY);
2747
2748             if (this.ready && !this.disabled && this.options.scalable) {
2749                 if (isNumber(scaleX)) {
2750                     imageData.scaleX = scaleX;
2751                     transformed = true;
2752                 }
2753
2754                 if (isNumber(scaleY)) {
2755                     imageData.scaleY = scaleY;
2756                     transformed = true;
2757                 }
2758
2759                 if (transformed) {
2760                     this.renderCanvas(true, true);
2761                 }
2762             }
2763
2764             return this;
2765         },
2766
2767         /**
2768          * Get the cropped area position and size data (base on the original image)
2769          * @param {boolean} [rounded=false] - Indicate if round the data values or not.
2770          * @returns {Object} The result cropped data.
2771          */
2772         getData: function getData() {
2773             var rounded = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
2774             var options = this.options,
2775                 imageData = this.imageData,
2776                 canvasData = this.canvasData,
2777                 cropBoxData = this.cropBoxData;
2778             var data;
2779
2780             if (this.ready && this.cropped) {
2781                 data = {
2782                     x: cropBoxData.left - canvasData.left,
2783                     y: cropBoxData.top - canvasData.top,
2784                     width: cropBoxData.width,
2785                     height: cropBoxData.height
2786                 };
2787                 var ratio = imageData.width / imageData.naturalWidth;
2788                 forEach(data, function (n, i) {
2789                     data[i] = n / ratio;
2790                 });
2791
2792                 if (rounded) {
2793                     // In case rounding off leads to extra 1px in right or bottom border
2794                     // we should round the top-left corner and the dimension (#343).
2795                     var bottom = Math.round(data.y + data.height);
2796                     var right = Math.round(data.x + data.width);
2797                     data.x = Math.round(data.x);
2798                     data.y = Math.round(data.y);
2799                     data.width = right - data.x;
2800                     data.height = bottom - data.y;
2801                 }
2802             } else {
2803                 data = {
2804                     x: 0,
2805                     y: 0,
2806                     width: 0,
2807                     height: 0
2808                 };
2809             }
2810
2811             if (options.rotatable) {
2812                 data.rotate = imageData.rotate || 0;
2813             }
2814
2815             if (options.scalable) {
2816                 data.scaleX = imageData.scaleX || 1;
2817                 data.scaleY = imageData.scaleY || 1;
2818             }
2819
2820             return data;
2821         },
2822
2823         /**
2824          * Set the cropped area position and size with new data
2825          * @param {Object} data - The new data.
2826          * @returns {Cropper} this
2827          */
2828         setData: function setData(data) {
2829             var options = this.options,
2830                 imageData = this.imageData,
2831                 canvasData = this.canvasData;
2832             var cropBoxData = {};
2833
2834             if (this.ready && !this.disabled && isPlainObject(data)) {
2835                 var transformed = false;
2836
2837                 if (options.rotatable) {
2838                     if (isNumber(data.rotate) && data.rotate !== imageData.rotate) {
2839                         imageData.rotate = data.rotate;
2840                         transformed = true;
2841                     }
2842                 }
2843
2844                 if (options.scalable) {
2845                     if (isNumber(data.scaleX) && data.scaleX !== imageData.scaleX) {
2846                         imageData.scaleX = data.scaleX;
2847                         transformed = true;
2848                     }
2849
2850                     if (isNumber(data.scaleY) && data.scaleY !== imageData.scaleY) {
2851                         imageData.scaleY = data.scaleY;
2852                         transformed = true;
2853                     }
2854                 }
2855
2856                 if (transformed) {
2857                     this.renderCanvas(true, true);
2858                 }
2859
2860                 var ratio = imageData.width / imageData.naturalWidth;
2861
2862                 if (isNumber(data.x)) {
2863                     cropBoxData.left = data.x * ratio + canvasData.left;
2864                 }
2865
2866                 if (isNumber(data.y)) {
2867                     cropBoxData.top = data.y * ratio + canvasData.top;
2868                 }
2869
2870                 if (isNumber(data.width)) {
2871                     cropBoxData.width = data.width * ratio;
2872                 }
2873
2874                 if (isNumber(data.height)) {
2875                     cropBoxData.height = data.height * ratio;
2876                 }
2877
2878                 this.setCropBoxData(cropBoxData);
2879             }
2880
2881             return this;
2882         },
2883
2884         /**
2885          * Get the container size data.
2886          * @returns {Object} The result container data.
2887          */
2888         getContainerData: function getContainerData() {
2889             return this.ready ? assign({}, this.containerData) : {};
2890         },
2891
2892         /**
2893          * Get the image position and size data.
2894          * @returns {Object} The result image data.
2895          */
2896         getImageData: function getImageData() {
2897             return this.sized ? assign({}, this.imageData) : {};
2898         },
2899
2900         /**
2901          * Get the canvas position and size data.
2902          * @returns {Object} The result canvas data.
2903          */
2904         getCanvasData: function getCanvasData() {
2905             var canvasData = this.canvasData;
2906             var data = {};
2907
2908             if (this.ready) {
2909                 forEach(['left', 'top', 'width', 'height', 'naturalWidth', 'naturalHeight'], function (n) {
2910                     data[n] = canvasData[n];
2911                 });
2912             }
2913
2914             return data;
2915         },
2916
2917         /**
2918          * Set the canvas position and size with new data.
2919          * @param {Object} data - The new canvas data.
2920          * @returns {Cropper} this
2921          */
2922         setCanvasData: function setCanvasData(data) {
2923             var canvasData = this.canvasData;
2924             var aspectRatio = canvasData.aspectRatio;
2925
2926             if (this.ready && !this.disabled && isPlainObject(data)) {
2927                 if (isNumber(data.left)) {
2928                     canvasData.left = data.left;
2929                 }
2930
2931                 if (isNumber(data.top)) {
2932                     canvasData.top = data.top;
2933                 }
2934
2935                 if (isNumber(data.width)) {
2936                     canvasData.width = data.width;
2937                     canvasData.height = data.width / aspectRatio;
2938                 } else if (isNumber(data.height)) {
2939                     canvasData.height = data.height;
2940                     canvasData.width = data.height * aspectRatio;
2941                 }
2942
2943                 this.renderCanvas(true);
2944             }
2945
2946             return this;
2947         },
2948
2949         /**
2950          * Get the crop box position and size data.
2951          * @returns {Object} The result crop box data.
2952          */
2953         getCropBoxData: function getCropBoxData() {
2954             var cropBoxData = this.cropBoxData;
2955             var data;
2956
2957             if (this.ready && this.cropped) {
2958                 data = {
2959                     left: cropBoxData.left,
2960                     top: cropBoxData.top,
2961                     width: cropBoxData.width,
2962                     height: cropBoxData.height
2963                 };
2964             }
2965
2966             return data || {};
2967         },
2968
2969         /**
2970          * Set the crop box position and size with new data.
2971          * @param {Object} data - The new crop box data.
2972          * @returns {Cropper} this
2973          */
2974         setCropBoxData: function setCropBoxData(data) {
2975             var cropBoxData = this.cropBoxData;
2976             var aspectRatio = this.options.aspectRatio;
2977             var widthChanged;
2978             var heightChanged;
2979
2980             if (this.ready && this.cropped && !this.disabled && isPlainObject(data)) {
2981                 if (isNumber(data.left)) {
2982                     cropBoxData.left = data.left;
2983                 }
2984
2985                 if (isNumber(data.top)) {
2986                     cropBoxData.top = data.top;
2987                 }
2988
2989                 if (isNumber(data.width) && data.width !== cropBoxData.width) {
2990                     widthChanged = true;
2991                     cropBoxData.width = data.width;
2992                 }
2993
2994                 if (isNumber(data.height) && data.height !== cropBoxData.height) {
2995                     heightChanged = true;
2996                     cropBoxData.height = data.height;
2997                 }
2998
2999                 if (aspectRatio) {
3000                     if (widthChanged) {
3001                         cropBoxData.height = cropBoxData.width / aspectRatio;
3002                     } else if (heightChanged) {
3003                         cropBoxData.width = cropBoxData.height * aspectRatio;
3004                     }
3005                 }
3006
3007                 this.renderCropBox();
3008             }
3009
3010             return this;
3011         },
3012
3013         /**
3014          * Get a canvas drawn the cropped image.
3015          * @param {Object} [options={}] - The config options.
3016          * @returns {HTMLCanvasElement} - The result canvas.
3017          */
3018         getCroppedCanvas: function getCroppedCanvas() {
3019             var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
3020
3021             if (!this.ready || !window.HTMLCanvasElement) {
3022                 return null;
3023             }
3024
3025             var canvasData = this.canvasData;
3026             var source = getSourceCanvas(this.image, this.imageData, canvasData, options); // Returns the source canvas if it is not cropped.
3027
3028             if (!this.cropped) {
3029                 return source;
3030             }
3031
3032             var _this$getData = this.getData(),
3033                 initialX = _this$getData.x,
3034                 initialY = _this$getData.y,
3035                 initialWidth = _this$getData.width,
3036                 initialHeight = _this$getData.height;
3037
3038             var ratio = source.width / Math.floor(canvasData.naturalWidth);
3039
3040             if (ratio !== 1) {
3041                 initialX *= ratio;
3042                 initialY *= ratio;
3043                 initialWidth *= ratio;
3044                 initialHeight *= ratio;
3045             }
3046
3047             var aspectRatio = initialWidth / initialHeight;
3048             var maxSizes = getAdjustedSizes({
3049                 aspectRatio: aspectRatio,
3050                 width: options.maxWidth || Infinity,
3051                 height: options.maxHeight || Infinity
3052             });
3053             var minSizes = getAdjustedSizes({
3054                 aspectRatio: aspectRatio,
3055                 width: options.minWidth || 0,
3056                 height: options.minHeight || 0
3057             }, 'cover');
3058
3059             var _getAdjustedSizes = getAdjustedSizes({
3060                     aspectRatio: aspectRatio,
3061                     width: options.width || (ratio !== 1 ? source.width : initialWidth),
3062                     height: options.height || (ratio !== 1 ? source.height : initialHeight)
3063                 }),
3064                 width = _getAdjustedSizes.width,
3065                 height = _getAdjustedSizes.height;
3066
3067             width = Math.min(maxSizes.width, Math.max(minSizes.width, width));
3068             height = Math.min(maxSizes.height, Math.max(minSizes.height, height));
3069             var canvas = document.createElement('canvas');
3070             var context = canvas.getContext('2d');
3071             canvas.width = normalizeDecimalNumber(width);
3072             canvas.height = normalizeDecimalNumber(height);
3073             context.fillStyle = options.fillColor || 'transparent';
3074             context.fillRect(0, 0, width, height);
3075             var _options$imageSmoothi = options.imageSmoothingEnabled,
3076                 imageSmoothingEnabled = _options$imageSmoothi === void 0 ? true : _options$imageSmoothi,
3077                 imageSmoothingQuality = options.imageSmoothingQuality;
3078             context.imageSmoothingEnabled = imageSmoothingEnabled;
3079
3080             if (imageSmoothingQuality) {
3081                 context.imageSmoothingQuality = imageSmoothingQuality;
3082             } // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage
3083
3084
3085             var sourceWidth = source.width;
3086             var sourceHeight = source.height; // Source canvas parameters
3087
3088             var srcX = initialX;
3089             var srcY = initialY;
3090             var srcWidth;
3091             var srcHeight; // Destination canvas parameters
3092
3093             var dstX;
3094             var dstY;
3095             var dstWidth;
3096             var dstHeight;
3097
3098             if (srcX <= -initialWidth || srcX > sourceWidth) {
3099                 srcX = 0;
3100                 srcWidth = 0;
3101                 dstX = 0;
3102                 dstWidth = 0;
3103             } else if (srcX <= 0) {
3104                 dstX = -srcX;
3105                 srcX = 0;
3106                 srcWidth = Math.min(sourceWidth, initialWidth + srcX);
3107                 dstWidth = srcWidth;
3108             } else if (srcX <= sourceWidth) {
3109                 dstX = 0;
3110                 srcWidth = Math.min(initialWidth, sourceWidth - srcX);
3111                 dstWidth = srcWidth;
3112             }
3113
3114             if (srcWidth <= 0 || srcY <= -initialHeight || srcY > sourceHeight) {
3115                 srcY = 0;
3116                 srcHeight = 0;
3117                 dstY = 0;
3118                 dstHeight = 0;
3119             } else if (srcY <= 0) {
3120                 dstY = -srcY;
3121                 srcY = 0;
3122                 srcHeight = Math.min(sourceHeight, initialHeight + srcY);
3123                 dstHeight = srcHeight;
3124             } else if (srcY <= sourceHeight) {
3125                 dstY = 0;
3126                 srcHeight = Math.min(initialHeight, sourceHeight - srcY);
3127                 dstHeight = srcHeight;
3128             }
3129
3130             var params = [srcX, srcY, srcWidth, srcHeight]; // Avoid "IndexSizeError"
3131
3132             if (dstWidth > 0 && dstHeight > 0) {
3133                 var scale = width / initialWidth;
3134                 params.push(dstX * scale, dstY * scale, dstWidth * scale, dstHeight * scale);
3135             } // All the numerical parameters should be integer for `drawImage`
3136             // https://github.com/fengyuanchen/cropper/issues/476
3137
3138
3139             context.drawImage.apply(context, [source].concat(_toConsumableArray(params.map(function (param) {
3140                 return Math.floor(normalizeDecimalNumber(param));
3141             }))));
3142             return canvas;
3143         },
3144
3145         /**
3146          * Change the aspect ratio of the crop box.
3147          * @param {number} aspectRatio - The new aspect ratio.
3148          * @returns {Cropper} this
3149          */
3150         setAspectRatio: function setAspectRatio(aspectRatio) {
3151             var options = this.options;
3152
3153             if (!this.disabled && !isUndefined(aspectRatio)) {
3154                 // 0 -> NaN
3155                 options.aspectRatio = Math.max(0, aspectRatio) || NaN;
3156
3157                 if (this.ready) {
3158                     this.initCropBox();
3159
3160                     if (this.cropped) {
3161                         this.renderCropBox();
3162                     }
3163                 }
3164             }
3165
3166             return this;
3167         },
3168
3169         /**
3170          * Change the drag mode.
3171          * @param {string} mode - The new drag mode.
3172          * @returns {Cropper} this
3173          */
3174         setDragMode: function setDragMode(mode) {
3175             var options = this.options,
3176                 dragBox = this.dragBox,
3177                 face = this.face;
3178
3179             if (this.ready && !this.disabled) {
3180                 var croppable = mode === DRAG_MODE_CROP;
3181                 var movable = options.movable && mode === DRAG_MODE_MOVE;
3182                 mode = croppable || movable ? mode : DRAG_MODE_NONE;
3183                 options.dragMode = mode;
3184                 setData(dragBox, DATA_ACTION, mode);
3185                 toggleClass(dragBox, CLASS_CROP, croppable);
3186                 toggleClass(dragBox, CLASS_MOVE, movable);
3187
3188                 if (!options.cropBoxMovable) {
3189                     // Sync drag mode to crop box when it is not movable
3190                     setData(face, DATA_ACTION, mode);
3191                     toggleClass(face, CLASS_CROP, croppable);
3192                     toggleClass(face, CLASS_MOVE, movable);
3193                 }
3194             }
3195
3196             return this;
3197         }
3198     };
3199
3200     var AnotherCropper = WINDOW.Cropper;
3201
3202     var Cropper =
3203         /*#__PURE__*/
3204         function () {
3205             /**
3206              * Create a new Cropper.
3207              * @param {Element} element - The target element for cropping.
3208              * @param {Object} [options={}] - The configuration options.
3209              */
3210             function Cropper(element) {
3211                 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
3212
3213                 _classCallCheck(this, Cropper);
3214
3215                 if (!element || !REGEXP_TAG_NAME.test(element.tagName)) {
3216                     throw new Error('The first argument is required and must be an <img> or <canvas> element.');
3217                 }
3218
3219                 this.element = element;
3220                 this.options = assign({}, DEFAULTS, isPlainObject(options) && options);
3221                 this.cropped = false;
3222                 this.disabled = false;
3223                 this.pointers = {};
3224                 this.ready = false;
3225                 this.reloading = false;
3226                 this.replaced = false;
3227                 this.sized = false;
3228                 this.sizing = false;
3229                 this.init();
3230             }
3231
3232             _createClass(Cropper, [{
3233                 key: "init",
3234                 value: function init() {
3235                     var element = this.element;
3236                     var tagName = element.tagName.toLowerCase();
3237                     var url;
3238
3239                     if (element[NAMESPACE]) {
3240                         return;
3241                     }
3242
3243                     element[NAMESPACE] = this;
3244
3245                     if (tagName === 'img') {
3246                         this.isImg = true; // e.g.: "img/picture.jpg"
3247
3248                         url = element.getAttribute('src') || '';
3249                         this.originalUrl = url; // Stop when it's a blank image
3250
3251                         if (!url) {
3252                             return;
3253                         } // e.g.: "http://example.com/img/picture.jpg"
3254
3255
3256                         url = element.src;
3257                     } else if (tagName === 'canvas' && window.HTMLCanvasElement) {
3258                         url = element.toDataURL();
3259                     }
3260
3261                     this.load(url);
3262                 }
3263             }, {
3264                 key: "load",
3265                 value: function load(url) {
3266                     var _this = this;
3267
3268                     if (!url) {
3269                         return;
3270                     }
3271
3272                     this.url = url;
3273                     this.imageData = {};
3274                     var element = this.element,
3275                         options = this.options;
3276
3277                     if (!options.rotatable && !options.scalable) {
3278                         options.checkOrientation = false;
3279                     } // Only IE10+ supports Typed Arrays
3280
3281
3282                     if (!options.checkOrientation || !window.ArrayBuffer) {
3283                         this.clone();
3284                         return;
3285                     } // Read ArrayBuffer from Data URL of JPEG images directly for better performance.
3286
3287
3288                     if (REGEXP_DATA_URL_JPEG.test(url)) {
3289                         this.read(dataURLToArrayBuffer(url));
3290                         return;
3291                     }
3292
3293                     var xhr = new XMLHttpRequest();
3294                     var clone = this.clone.bind(this);
3295                     this.reloading = true;
3296                     this.xhr = xhr; // 1. Cross origin requests are only supported for protocol schemes:
3297                     // http, https, data, chrome, chrome-extension.
3298                     // 2. Access to XMLHttpRequest from a Data URL will be blocked by CORS policy
3299                     // in some browsers as IE11 and Safari.
3300
3301                     xhr.onabort = clone;
3302                     xhr.onerror = clone;
3303                     xhr.ontimeout = clone;
3304
3305                     xhr.onprogress = function () {
3306                         if (xhr.getResponseHeader('content-type') !== MIME_TYPE_JPEG) {
3307                             xhr.abort();
3308                         }
3309                     };
3310
3311                     xhr.onload = function () {
3312                         _this.read(xhr.response);
3313                     };
3314
3315                     xhr.onloadend = function () {
3316                         _this.reloading = false;
3317                         _this.xhr = null;
3318                     }; // Bust cache when there is a "crossOrigin" property to avoid browser cache error
3319
3320
3321                     if (options.checkCrossOrigin && isCrossOriginURL(url) && element.crossOrigin) {
3322                         url = addTimestamp(url);
3323                     }
3324
3325                     xhr.open('GET', url);
3326                     xhr.responseType = 'arraybuffer';
3327                     xhr.withCredentials = element.crossOrigin === 'use-credentials';
3328                     xhr.send();
3329                 }
3330             }, {
3331                 key: "read",
3332                 value: function read(arrayBuffer) {
3333                     var options = this.options,
3334                         imageData = this.imageData; // Reset the orientation value to its default value 1
3335                     // as some iOS browsers will render image with its orientation
3336
3337                     var orientation = resetAndGetOrientation(arrayBuffer);
3338                     var rotate = 0;
3339                     var scaleX = 1;
3340                     var scaleY = 1;
3341
3342                     if (orientation > 1) {
3343                         // Generate a new URL which has the default orientation value
3344                         this.url = arrayBufferToDataURL(arrayBuffer, MIME_TYPE_JPEG);
3345
3346                         var _parseOrientation = parseOrientation(orientation);
3347
3348                         rotate = _parseOrientation.rotate;
3349                         scaleX = _parseOrientation.scaleX;
3350                         scaleY = _parseOrientation.scaleY;
3351                     }
3352
3353                     if (options.rotatable) {
3354                         imageData.rotate = rotate;
3355                     }
3356
3357                     if (options.scalable) {
3358                         imageData.scaleX = scaleX;
3359                         imageData.scaleY = scaleY;
3360                     }
3361
3362                     this.clone();
3363                 }
3364             }, {
3365                 key: "clone",
3366                 value: function clone() {
3367                     var element = this.element,
3368                         url = this.url;
3369                     var crossOrigin;
3370                     var crossOriginUrl;
3371
3372                     if (this.options.checkCrossOrigin && isCrossOriginURL(url)) {
3373                         crossOrigin = element.crossOrigin;
3374
3375                         if (crossOrigin) {
3376                             crossOriginUrl = url;
3377                         } else {
3378                             crossOrigin = 'anonymous'; // Bust cache when there is not a "crossOrigin" property
3379
3380                             crossOriginUrl = addTimestamp(url);
3381                         }
3382                     }
3383
3384                     this.crossOrigin = crossOrigin;
3385                     this.crossOriginUrl = crossOriginUrl;
3386                     var image = document.createElement('img');
3387
3388                     if (crossOrigin) {
3389                         image.crossOrigin = crossOrigin;
3390                     }
3391
3392                     image.src = crossOriginUrl || url;
3393                     this.image = image;
3394                     image.onload = this.start.bind(this);
3395                     image.onerror = this.stop.bind(this);
3396                     addClass(image, CLASS_HIDE);
3397                     element.parentNode.insertBefore(image, element.nextSibling);
3398                 }
3399             }, {
3400                 key: "start",
3401                 value: function start() {
3402                     var _this2 = this;
3403
3404                     var image = this.isImg ? this.element : this.image;
3405                     image.onload = null;
3406                     image.onerror = null;
3407                     this.sizing = true;
3408                     var IS_SAFARI = WINDOW.navigator && /^(?:.(?!chrome|android))*safari/i.test(WINDOW.navigator.userAgent);
3409
3410                     var done = function done(naturalWidth, naturalHeight) {
3411                         assign(_this2.imageData, {
3412                             naturalWidth: naturalWidth,
3413                             naturalHeight: naturalHeight,
3414                             aspectRatio: naturalWidth / naturalHeight
3415                         });
3416                         _this2.sizing = false;
3417                         _this2.sized = true;
3418
3419                         _this2.build();
3420                     }; // Modern browsers (except Safari)
3421
3422
3423                     if (image.naturalWidth && !IS_SAFARI) {
3424                         done(image.naturalWidth, image.naturalHeight);
3425                         return;
3426                     }
3427
3428                     var sizingImage = document.createElement('img');
3429                     var body = document.body || document.documentElement;
3430                     this.sizingImage = sizingImage;
3431
3432                     sizingImage.onload = function () {
3433                         done(sizingImage.width, sizingImage.height);
3434
3435                         if (!IS_SAFARI) {
3436                             body.removeChild(sizingImage);
3437                         }
3438                     };
3439
3440                     sizingImage.src = image.src; // iOS Safari will convert the image automatically
3441                     // with its orientation once append it into DOM (#279)
3442
3443                     if (!IS_SAFARI) {
3444                         sizingImage.style.cssText = 'left:0;' + 'max-height:none!important;' + 'max-width:none!important;' + 'min-height:0!important;' + 'min-width:0!important;' + 'opacity:0;' + 'position:absolute;' + 'top:0;' + 'z-index:-1;';
3445                         body.appendChild(sizingImage);
3446                     }
3447                 }
3448             }, {
3449                 key: "stop",
3450                 value: function stop() {
3451                     var image = this.image;
3452                     image.onload = null;
3453                     image.onerror = null;
3454                     image.parentNode.removeChild(image);
3455                     this.image = null;
3456                 }
3457             }, {
3458                 key: "build",
3459                 value: function build() {
3460                     if (!this.sized || this.ready) {
3461                         return;
3462                     }
3463
3464                     var element = this.element,
3465                         options = this.options,
3466                         image = this.image; // Create cropper elements
3467
3468                     var container = element.parentNode;
3469                     var template = document.createElement('div');
3470                     template.innerHTML = TEMPLATE;
3471                     var cropper = template.querySelector(".".concat(NAMESPACE, "-container"));
3472                     var canvas = cropper.querySelector(".".concat(NAMESPACE, "-canvas"));
3473                     var dragBox = cropper.querySelector(".".concat(NAMESPACE, "-drag-box"));
3474                     var cropBox = cropper.querySelector(".".concat(NAMESPACE, "-crop-box"));
3475                     var face = cropBox.querySelector(".".concat(NAMESPACE, "-face"));
3476                     this.container = container;
3477                     this.cropper = cropper;
3478                     this.canvas = canvas;
3479                     this.dragBox = dragBox;
3480                     this.cropBox = cropBox;
3481                     this.viewBox = cropper.querySelector(".".concat(NAMESPACE, "-view-box"));
3482                     this.face = face;
3483                     canvas.appendChild(image); // Hide the original image
3484
3485                     addClass(element, CLASS_HIDDEN); // Inserts the cropper after to the current image
3486
3487                     container.insertBefore(cropper, element.nextSibling); // Show the image if is hidden
3488
3489                     if (!this.isImg) {
3490                         removeClass(image, CLASS_HIDE);
3491                     }
3492
3493                     this.initPreview();
3494                     this.bind();
3495                     options.initialAspectRatio = Math.max(0, options.initialAspectRatio) || NaN;
3496                     options.aspectRatio = Math.max(0, options.aspectRatio) || NaN;
3497                     options.viewMode = Math.max(0, Math.min(3, Math.round(options.viewMode))) || 0;
3498                     addClass(cropBox, CLASS_HIDDEN);
3499
3500                     if (!options.guides) {
3501                         addClass(cropBox.getElementsByClassName("".concat(NAMESPACE, "-dashed")), CLASS_HIDDEN);
3502                     }
3503
3504                     if (!options.center) {
3505                         addClass(cropBox.getElementsByClassName("".concat(NAMESPACE, "-center")), CLASS_HIDDEN);
3506                     }
3507
3508                     if (options.background) {
3509                         addClass(cropper, "".concat(NAMESPACE, "-bg"));
3510                     }
3511
3512                     if (!options.highlight) {
3513                         addClass(face, CLASS_INVISIBLE);
3514                     }
3515
3516                     if (options.cropBoxMovable) {
3517                         addClass(face, CLASS_MOVE);
3518                         setData(face, DATA_ACTION, ACTION_ALL);
3519                     }
3520
3521                     if (!options.cropBoxResizable) {
3522                         addClass(cropBox.getElementsByClassName("".concat(NAMESPACE, "-line")), CLASS_HIDDEN);
3523                         addClass(cropBox.getElementsByClassName("".concat(NAMESPACE, "-point")), CLASS_HIDDEN);
3524                     }
3525
3526                     this.render();
3527                     this.ready = true;
3528                     this.setDragMode(options.dragMode);
3529
3530                     if (options.autoCrop) {
3531                         this.crop();
3532                     }
3533
3534                     this.setData(options.data);
3535
3536                     if (isFunction(options.ready)) {
3537                         addListener(element, EVENT_READY, options.ready, {
3538                             once: true
3539                         });
3540                     }
3541
3542                     dispatchEvent(element, EVENT_READY);
3543                 }
3544             }, {
3545                 key: "unbuild",
3546                 value: function unbuild() {
3547                     if (!this.ready) {
3548                         return;
3549                     }
3550
3551                     this.ready = false;
3552                     this.unbind();
3553                     this.resetPreview();
3554                     this.cropper.parentNode.removeChild(this.cropper);
3555                     removeClass(this.element, CLASS_HIDDEN);
3556                 }
3557             }, {
3558                 key: "uncreate",
3559                 value: function uncreate() {
3560                     if (this.ready) {
3561                         this.unbuild();
3562                         this.ready = false;
3563                         this.cropped = false;
3564                     } else if (this.sizing) {
3565                         this.sizingImage.onload = null;
3566                         this.sizing = false;
3567                         this.sized = false;
3568                     } else if (this.reloading) {
3569                         this.xhr.onabort = null;
3570                         this.xhr.abort();
3571                     } else if (this.image) {
3572                         this.stop();
3573                     }
3574                 }
3575                 /**
3576                  * Get the no conflict cropper class.
3577                  * @returns {Cropper} The cropper class.
3578                  */
3579
3580             }], [{
3581                 key: "noConflict",
3582                 value: function noConflict() {
3583                     window.Cropper = AnotherCropper;
3584                     return Cropper;
3585                 }
3586                 /**
3587                  * Change the default options.
3588                  * @param {Object} options - The new default options.
3589                  */
3590
3591             }, {
3592                 key: "setDefaults",
3593                 value: function setDefaults(options) {
3594                     assign(DEFAULTS, isPlainObject(options) && options);
3595                 }
3596             }]);
3597
3598             return Cropper;
3599         }();
3600
3601     assign(Cropper.prototype, render, preview, events, handlers, change, methods);
3602
3603     return Cropper;
3604
3605 }));