[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/media/vendor/cropperjs/js/ -> cropper.js (source)

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


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer