PageSourceSearch

https://www.imopticas.es/assets/js/cropper.js

js imopticas.es collected 2026-10-04 02:04:09 UTC 138,216 bytes, 3,772 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.