diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c85e7701..aa6e5b417 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog +## 1.0.0-rc.1 (Apr 30, 2017) + +- Change the `main` field value from `dist/cropper.js` (UMD) to `dist/cropper.common.js` (CommonJS). +- Added `module` and `browser` fields to `package.json`. + + ## 1.0.0-rc (Mar 25, 2017) - Fixed the bug of touch zoom (#161). diff --git a/README.md b/README.md index ed9e65645..9e5539d15 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,12 @@ ``` dist/ -├── cropper.css ( 5 KB) -├── cropper.min.css ( 4 KB) -├── cropper.js (90 KB) -└── cropper.min.js (33 KB) +├── cropper.css ( 5 KB) +├── cropper.min.css ( 4 KB) +├── cropper.js (90 KB, UMD) +├── cropper.min.js (33 KB, UMD, compressed) +├── cropper.common.js (90 KB, CommonJS) +└── cropper.esm.js (90 KB, ES Module) ``` diff --git a/dist/cropper.common.js b/dist/cropper.common.js new file mode 100644 index 000000000..7e4b4d615 --- /dev/null +++ b/dist/cropper.common.js @@ -0,0 +1,3560 @@ +/*! + * Cropper.js v1.0.0-rc.1 + * https://github.com/fengyuanchen/cropperjs + * + * Copyright (c) 2017 Fengyuan Chen + * Released under the MIT license + * + * Date: 2017-04-30T03:26:33.550Z + */ + +'use strict'; + +var DEFAULTS = { + // Define the view mode of the cropper + viewMode: 0, // 0, 1, 2, 3 + + // Define the dragging mode of the cropper + dragMode: 'crop', // 'crop', 'move' or 'none' + + // Define the aspect ratio of the crop box + aspectRatio: NaN, + + // An object with the previous cropping result data + data: null, + + // A selector for adding extra containers to preview + preview: '', + + // Re-render the cropper when resize the window + responsive: true, + + // Restore the cropped area after resize the window + restore: true, + + // Check if the current image is a cross-origin image + checkCrossOrigin: true, + + // Check the current image's Exif Orientation information + checkOrientation: true, + + // Show the black modal + modal: true, + + // Show the dashed lines for guiding + guides: true, + + // Show the center indicator for guiding + center: true, + + // Show the white modal to highlight the crop box + highlight: true, + + // Show the grid background + background: true, + + // Enable to crop the image automatically when initialize + autoCrop: true, + + // Define the percentage of automatic cropping area when initializes + autoCropArea: 0.8, + + // Enable to move the image + movable: true, + + // Enable to rotate the image + rotatable: true, + + // Enable to scale the image + scalable: true, + + // Enable to zoom the image + zoomable: true, + + // Enable to zoom the image by dragging touch + zoomOnTouch: true, + + // Enable to zoom the image by wheeling mouse + zoomOnWheel: true, + + // Define zoom ratio when zoom the image by wheeling mouse + wheelZoomRatio: 0.1, + + // Enable to move the crop box + cropBoxMovable: true, + + // Enable to resize the crop box + cropBoxResizable: true, + + // Toggle drag mode between "crop" and "move" when click twice on the cropper + toggleDragModeOnDblclick: true, + + // Size limitation + minCanvasWidth: 0, + minCanvasHeight: 0, + minCropBoxWidth: 0, + minCropBoxHeight: 0, + minContainerWidth: 200, + minContainerHeight: 100, + + // Shortcuts of events + ready: null, + cropstart: null, + cropmove: null, + cropend: null, + crop: null, + zoom: null +}; + +var TEMPLATE = '
' + '
' + '
' + '
' + '
' + '
' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
' + '
'; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; +}; + + + + + + + + + + + +var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +}; + +var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +}(); + + + + + + + +var get = function get(object, property, receiver) { + if (object === null) object = Function.prototype; + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent === null) { + return undefined; + } else { + return get(parent, property, receiver); + } + } else if ("value" in desc) { + return desc.value; + } else { + var getter = desc.get; + + if (getter === undefined) { + return undefined; + } + + return getter.call(receiver); + } +}; + + + + + + + + + + + + + + + + + +var set = function set(object, property, value, receiver) { + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent !== null) { + set(parent, property, value, receiver); + } + } else if ("value" in desc && desc.writable) { + desc.value = value; + } else { + var setter = desc.set; + + if (setter !== undefined) { + setter.call(receiver, value); + } + } + + return value; +}; + + + + + + + + + + + + + + + +var toConsumableArray = function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } else { + return Array.from(arr); + } +}; + +// RegExps +var REGEXP_DATA_URL_HEAD = /^data:.*,/; +var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g; +var REGEXP_ORIGINS = /^(https?:)\/\/([^:/?#]+):?(\d*)/i; +var REGEXP_SPACES = /\s+/; +var REGEXP_SUFFIX = /^(width|height|left|top|marginLeft|marginTop)$/; +var REGEXP_TRIM = /^\s+(.*)\s+$/; +var REGEXP_USERAGENT = /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i; + +// Utilities +var navigator = typeof window !== 'undefined' ? window.navigator : null; +var IS_SAFARI_OR_UIWEBVIEW = navigator && REGEXP_USERAGENT.test(navigator.userAgent); +var objectProto = Object.prototype; +var toString = objectProto.toString; +var hasOwnProperty = objectProto.hasOwnProperty; +var slice = Array.prototype.slice; +var fromCharCode = String.fromCharCode; + +function typeOf(obj) { + return toString.call(obj).slice(8, -1).toLowerCase(); +} + +function isNumber(num) { + return typeof num === 'number' && !isNaN(num); +} + +function isUndefined(obj) { + return typeof obj === 'undefined'; +} + +function isObject(obj) { + return (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' && obj !== null; +} + +function isPlainObject(obj) { + if (!isObject(obj)) { + return false; + } + + try { + var _constructor = obj.constructor; + var prototype = _constructor.prototype; + + return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf'); + } catch (e) { + return false; + } +} + +function isFunction(fn) { + return typeOf(fn) === 'function'; +} + +function isArray(arr) { + return Array.isArray ? Array.isArray(arr) : typeOf(arr) === 'array'; +} + + + +function trim(str) { + if (typeof str === 'string') { + str = str.trim ? str.trim() : str.replace(REGEXP_TRIM, '$1'); + } + + return str; +} + +function each(obj, callback) { + if (obj && isFunction(callback)) { + var i = void 0; + + if (isArray(obj) || isNumber(obj.length) /* array-like */) { + var length = obj.length; + + for (i = 0; i < length; i++) { + if (callback.call(obj, obj[i], i, obj) === false) { + break; + } + } + } else if (isObject(obj)) { + Object.keys(obj).forEach(function (key) { + callback.call(obj, obj[key], key, obj); + }); + } + } + + return obj; +} + +function extend(obj) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (isObject(obj) && args.length > 0) { + if (Object.assign) { + return Object.assign.apply(Object, [obj].concat(args)); + } + + args.forEach(function (arg) { + if (isObject(arg)) { + Object.keys(arg).forEach(function (key) { + obj[key] = arg[key]; + }); + } + }); + } + + return obj; +} + +function proxy(fn, context) { + for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { + args[_key2 - 2] = arguments[_key2]; + } + + return function () { + for (var _len3 = arguments.length, args2 = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args2[_key3] = arguments[_key3]; + } + + return fn.apply(context, args.concat(args2)); + }; +} + +function setStyle(element, styles) { + var style = element.style; + + each(styles, function (value, property) { + if (REGEXP_SUFFIX.test(property) && isNumber(value)) { + value += 'px'; + } + + style[property] = value; + }); +} + +function hasClass(element, value) { + return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1; +} + +function addClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + addClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.add(value); + return; + } + + var className = trim(element.className); + + if (!className) { + element.className = value; + } else if (className.indexOf(value) < 0) { + element.className = className + ' ' + value; + } +} + +function removeClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + removeClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.remove(value); + return; + } + + if (element.className.indexOf(value) >= 0) { + element.className = element.className.replace(value, ''); + } +} + +function toggleClass(element, value, added) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + toggleClass(elem, value, added); + }); + return; + } + + // IE10-11 doesn't support the second parameter of `classList.toggle` + if (added) { + addClass(element, value); + } else { + removeClass(element, value); + } +} + +function hyphenate(str) { + return str.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase(); +} + +function getData$1(element, name) { + if (isObject(element[name])) { + return element[name]; + } else if (element.dataset) { + return element.dataset[name]; + } + + return element.getAttribute('data-' + hyphenate(name)); +} + +function setData$1(element, name, data) { + if (isObject(data)) { + element[name] = data; + } else if (element.dataset) { + element.dataset[name] = data; + } else { + element.setAttribute('data-' + hyphenate(name), data); + } +} + +function removeData(element, name) { + if (isObject(element[name])) { + delete element[name]; + } else if (element.dataset) { + // #128 Safari not allows to delete dataset property + try { + delete element.dataset[name]; + } catch (e) { + element.dataset[name] = null; + } + } else { + element.removeAttribute('data-' + hyphenate(name)); + } +} + +function removeListener(element, type, handler) { + var types = trim(type).split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, function (t) { + removeListener(element, t, handler); + }); + return; + } + + if (element.removeEventListener) { + element.removeEventListener(type, handler, false); + } else if (element.detachEvent) { + element.detachEvent('on' + type, handler); + } +} + +function addListener(element, type, _handler, once) { + var types = trim(type).split(REGEXP_SPACES); + var originalHandler = _handler; + + if (types.length > 1) { + each(types, function (t) { + addListener(element, t, _handler); + }); + return; + } + + if (once) { + _handler = function handler() { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + removeListener(element, type, _handler); + + return originalHandler.apply(element, args); + }; + } + + if (element.addEventListener) { + element.addEventListener(type, _handler, false); + } else if (element.attachEvent) { + element.attachEvent('on' + type, _handler); + } +} + +function dispatchEvent(element, type, data) { + if (element.dispatchEvent) { + var event = void 0; + + // Event and CustomEvent on IE9-11 are global objects, not constructors + if (isFunction(Event) && isFunction(CustomEvent)) { + if (isUndefined(data)) { + event = new Event(type, { + bubbles: true, + cancelable: true + }); + } else { + event = new CustomEvent(type, { + detail: data, + bubbles: true, + cancelable: true + }); + } + } else if (isUndefined(data)) { + event = document.createEvent('Event'); + event.initEvent(type, true, true); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(type, true, true, data); + } + + // IE9+ + return element.dispatchEvent(event); + } else if (element.fireEvent) { + // IE6-10 (native events only) + return element.fireEvent('on' + type); + } + + return true; +} + +function getEvent(event) { + var e = event || window.event; + + // Fix target property (IE8) + if (!e.target) { + e.target = e.srcElement || document; + } + + if (!isNumber(e.pageX) && isNumber(e.clientX)) { + var eventDoc = event.target.ownerDocument || document; + var doc = eventDoc.documentElement; + var body = eventDoc.body; + + e.pageX = e.clientX + ((doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0)); + e.pageY = e.clientY + ((doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0)); + } + + return e; +} + +function getOffset(element) { + var doc = document.documentElement; + var box = element.getBoundingClientRect(); + + return { + left: box.left + ((window.scrollX || doc && doc.scrollLeft || 0) - (doc && doc.clientLeft || 0)), + top: box.top + ((window.scrollY || doc && doc.scrollTop || 0) - (doc && doc.clientTop || 0)) + }; +} + +function getByTag(element, tagName) { + return element.getElementsByTagName(tagName); +} + +function getByClass(element, className) { + return element.getElementsByClassName ? element.getElementsByClassName(className) : element.querySelectorAll('.' + className); +} + +function createElement(tagName) { + return document.createElement(tagName); +} + +function appendChild(element, elem) { + element.appendChild(elem); +} + +function removeChild(element) { + if (element.parentNode) { + element.parentNode.removeChild(element); + } +} + +function empty(element) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} + +function isCrossOriginURL(url) { + var parts = url.match(REGEXP_ORIGINS); + + return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port); +} + +function addTimestamp(url) { + var timestamp = 'timestamp=' + new Date().getTime(); + + return url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp; +} + +function getImageSize(image, callback) { + // Modern browsers (ignore Safari) + if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) { + callback(image.naturalWidth, image.naturalHeight); + return; + } + + // IE8: Don't use `new Image()` here + var newImage = createElement('img'); + + newImage.onload = function load() { + callback(this.width, this.height); + }; + + newImage.src = image.src; +} + +function getTransforms(data) { + var transforms = []; + var translateX = data.translateX; + var translateY = data.translateY; + var rotate = data.rotate; + var scaleX = data.scaleX; + var scaleY = data.scaleY; + + if (isNumber(translateX) && translateX !== 0) { + transforms.push('translateX(' + translateX + 'px)'); + } + + if (isNumber(translateY) && translateY !== 0) { + transforms.push('translateY(' + translateY + 'px)'); + } + + // Rotate should come first before scale to match orientation transform + if (isNumber(rotate) && rotate !== 0) { + transforms.push('rotate(' + rotate + 'deg)'); + } + + if (isNumber(scaleX) && scaleX !== 1) { + transforms.push('scaleX(' + scaleX + ')'); + } + + if (isNumber(scaleY) && scaleY !== 1) { + transforms.push('scaleY(' + scaleY + ')'); + } + + var transform = transforms.length ? transforms.join(' ') : 'none'; + + return { + WebkitTransform: transform, + msTransform: transform, + transform: transform + }; +} + +function getRotatedSizes(data, reversed) { + var deg = Math.abs(data.degree) % 180; + var arc = (deg > 90 ? 180 - deg : deg) * Math.PI / 180; + var sinArc = Math.sin(arc); + var cosArc = Math.cos(arc); + var width = data.width; + var height = data.height; + var aspectRatio = data.aspectRatio; + var newWidth = void 0; + var newHeight = void 0; + + if (!reversed) { + newWidth = width * cosArc + height * sinArc; + newHeight = width * sinArc + height * cosArc; + } else { + newWidth = width / (cosArc + sinArc / aspectRatio); + newHeight = newWidth / aspectRatio; + } + + return { + width: newWidth, + height: newHeight + }; +} + +function getSourceCanvas(image, data) { + var canvas = createElement('canvas'); + var context = canvas.getContext('2d'); + var dstX = 0; + var dstY = 0; + var dstWidth = data.naturalWidth; + var dstHeight = data.naturalHeight; + var rotate = data.rotate; + var scaleX = data.scaleX; + var scaleY = data.scaleY; + var scalable = isNumber(scaleX) && isNumber(scaleY) && (scaleX !== 1 || scaleY !== 1); + var rotatable = isNumber(rotate) && rotate !== 0; + var advanced = rotatable || scalable; + var canvasWidth = dstWidth * Math.abs(scaleX || 1); + var canvasHeight = dstHeight * Math.abs(scaleY || 1); + var translateX = void 0; + var translateY = void 0; + var rotated = void 0; + + if (scalable) { + translateX = canvasWidth / 2; + translateY = canvasHeight / 2; + } + + if (rotatable) { + rotated = getRotatedSizes({ + width: canvasWidth, + height: canvasHeight, + degree: rotate + }); + + canvasWidth = rotated.width; + canvasHeight = rotated.height; + translateX = canvasWidth / 2; + translateY = canvasHeight / 2; + } + + canvas.width = canvasWidth; + canvas.height = canvasHeight; + + if (advanced) { + dstX = -dstWidth / 2; + dstY = -dstHeight / 2; + + context.save(); + context.translate(translateX, translateY); + } + + // Rotate should come first before scale as in the "getTransform" function + if (rotatable) { + context.rotate(rotate * Math.PI / 180); + } + + if (scalable) { + context.scale(scaleX, scaleY); + } + + context.drawImage(image, Math.floor(dstX), Math.floor(dstY), Math.floor(dstWidth), Math.floor(dstHeight)); + + if (advanced) { + context.restore(); + } + + return canvas; +} + +function getStringFromCharCode(dataView, start, length) { + var str = ''; + var i = start; + + for (length += start; i < length; i++) { + str += fromCharCode(dataView.getUint8(i)); + } + + return str; +} + +function getOrientation(arrayBuffer) { + var dataView = new DataView(arrayBuffer); + var length = dataView.byteLength; + var orientation = void 0; + var exifIDCode = void 0; + var tiffOffset = void 0; + var firstIFDOffset = void 0; + var littleEndian = void 0; + var endianness = void 0; + var app1Start = void 0; + var ifdStart = void 0; + var offset = void 0; + var i = void 0; + + // Only handle JPEG image (start by 0xFFD8) + if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) { + offset = 2; + + while (offset < length) { + if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) { + app1Start = offset; + break; + } + + offset++; + } + } + + if (app1Start) { + exifIDCode = app1Start + 4; + tiffOffset = app1Start + 10; + + if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') { + endianness = dataView.getUint16(tiffOffset); + littleEndian = endianness === 0x4949; + + if (littleEndian || endianness === 0x4D4D /* bigEndian */) { + if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) { + firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian); + + if (firstIFDOffset >= 0x00000008) { + ifdStart = tiffOffset + firstIFDOffset; + } + } + } + } + } + + if (ifdStart) { + length = dataView.getUint16(ifdStart, littleEndian); + + for (i = 0; i < length; i++) { + offset = ifdStart + i * 12 + 2; + + if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) { + // 8 is the offset of the current tag's value + offset += 8; + + // Get the original orientation value + orientation = dataView.getUint16(offset, littleEndian); + + // Override the orientation with its default value for Safari + if (IS_SAFARI_OR_UIWEBVIEW) { + dataView.setUint16(offset, 1, littleEndian); + } + + break; + } + } + } + + return orientation; +} + +function dataURLToArrayBuffer(dataURL) { + var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, ''); + var binary = atob(base64); + var length = binary.length; + var arrayBuffer = new ArrayBuffer(length); + var dataView = new Uint8Array(arrayBuffer); + var i = void 0; + + for (i = 0; i < length; i++) { + dataView[i] = binary.charCodeAt(i); + } + + return arrayBuffer; +} + +// Only available for JPEG image +function arrayBufferToDataURL(arrayBuffer) { + var dataView = new Uint8Array(arrayBuffer); + var length = dataView.length; + var base64 = ''; + var i = void 0; + + for (i = 0; i < length; i++) { + base64 += fromCharCode(dataView[i]); + } + + return 'data:image/jpeg;base64,' + btoa(base64); +} + +var render$1 = { + render: function render() { + var self = this; + + self.initContainer(); + self.initCanvas(); + self.initCropBox(); + + self.renderCanvas(); + + if (self.cropped) { + self.renderCropBox(); + } + }, + initContainer: function initContainer() { + var self = this; + var options = self.options; + var element = self.element; + var container = self.container; + var cropper = self.cropper; + var hidden = 'cropper-hidden'; + var containerData = void 0; + + addClass(cropper, hidden); + removeClass(element, hidden); + + self.containerData = containerData = { + width: Math.max(container.offsetWidth, Number(options.minContainerWidth) || 200), + height: Math.max(container.offsetHeight, Number(options.minContainerHeight) || 100) + }; + + setStyle(cropper, { + width: containerData.width, + height: containerData.height + }); + + addClass(element, hidden); + removeClass(cropper, hidden); + }, + + + // Canvas (image wrapper) + initCanvas: function initCanvas() { + var self = this; + var viewMode = self.options.viewMode; + var containerData = self.containerData; + var imageData = self.imageData; + var rotated = Math.abs(imageData.rotate) === 90; + var naturalWidth = rotated ? imageData.naturalHeight : imageData.naturalWidth; + var naturalHeight = rotated ? imageData.naturalWidth : imageData.naturalHeight; + var aspectRatio = naturalWidth / naturalHeight; + var canvasWidth = containerData.width; + var canvasHeight = containerData.height; + + if (containerData.height * aspectRatio > containerData.width) { + if (viewMode === 3) { + canvasWidth = containerData.height * aspectRatio; + } else { + canvasHeight = containerData.width / aspectRatio; + } + } else if (viewMode === 3) { + canvasHeight = containerData.width / aspectRatio; + } else { + canvasWidth = containerData.height * aspectRatio; + } + + var canvasData = { + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + aspectRatio: aspectRatio, + width: canvasWidth, + height: canvasHeight + }; + + canvasData.oldLeft = canvasData.left = (containerData.width - canvasWidth) / 2; + canvasData.oldTop = canvasData.top = (containerData.height - canvasHeight) / 2; + + self.canvasData = canvasData; + self.limited = viewMode === 1 || viewMode === 2; + self.limitCanvas(true, true); + self.initialImageData = extend({}, imageData); + self.initialCanvasData = extend({}, canvasData); + }, + limitCanvas: function limitCanvas(sizeLimited, positionLimited) { + var self = this; + var options = self.options; + var viewMode = options.viewMode; + var containerData = self.containerData; + var canvasData = self.canvasData; + var aspectRatio = canvasData.aspectRatio; + var cropBoxData = self.cropBoxData; + var cropped = self.cropped && cropBoxData; + + if (sizeLimited) { + var minCanvasWidth = Number(options.minCanvasWidth) || 0; + var minCanvasHeight = Number(options.minCanvasHeight) || 0; + + if (viewMode > 1) { + minCanvasWidth = Math.max(minCanvasWidth, containerData.width); + minCanvasHeight = Math.max(minCanvasHeight, containerData.height); + + if (viewMode === 3) { + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } else if (viewMode > 0) { + if (minCanvasWidth) { + minCanvasWidth = Math.max(minCanvasWidth, cropped ? cropBoxData.width : 0); + } else if (minCanvasHeight) { + minCanvasHeight = Math.max(minCanvasHeight, cropped ? cropBoxData.height : 0); + } else if (cropped) { + minCanvasWidth = cropBoxData.width; + minCanvasHeight = cropBoxData.height; + + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } + + if (minCanvasWidth && minCanvasHeight) { + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasHeight = minCanvasWidth / aspectRatio; + } else { + minCanvasWidth = minCanvasHeight * aspectRatio; + } + } else if (minCanvasWidth) { + minCanvasHeight = minCanvasWidth / aspectRatio; + } else if (minCanvasHeight) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } + + canvasData.minWidth = minCanvasWidth; + canvasData.minHeight = minCanvasHeight; + canvasData.maxWidth = Infinity; + canvasData.maxHeight = Infinity; + } + + if (positionLimited) { + if (viewMode) { + var newCanvasLeft = containerData.width - canvasData.width; + var newCanvasTop = containerData.height - canvasData.height; + + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + canvasData.maxTop = Math.max(0, newCanvasTop); + + if (cropped && self.limited) { + canvasData.minLeft = Math.min(cropBoxData.left, cropBoxData.left + (cropBoxData.width - canvasData.width)); + canvasData.minTop = Math.min(cropBoxData.top, cropBoxData.top + (cropBoxData.height - canvasData.height)); + canvasData.maxLeft = cropBoxData.left; + canvasData.maxTop = cropBoxData.top; + + if (viewMode === 2) { + if (canvasData.width >= containerData.width) { + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + } + + if (canvasData.height >= containerData.height) { + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxTop = Math.max(0, newCanvasTop); + } + } + } + } else { + canvasData.minLeft = -canvasData.width; + canvasData.minTop = -canvasData.height; + canvasData.maxLeft = containerData.width; + canvasData.maxTop = containerData.height; + } + } + }, + renderCanvas: function renderCanvas(changed) { + var self = this; + var canvasData = self.canvasData; + var imageData = self.imageData; + var rotate = imageData.rotate; + + if (self.rotated) { + self.rotated = false; + + // Computes rotated sizes with image sizes + var rotatedData = getRotatedSizes({ + width: imageData.width, + height: imageData.height, + degree: rotate + }); + var aspectRatio = rotatedData.width / rotatedData.height; + var isSquareImage = imageData.aspectRatio === 1; + + if (isSquareImage || aspectRatio !== canvasData.aspectRatio) { + canvasData.left -= (rotatedData.width - canvasData.width) / 2; + canvasData.top -= (rotatedData.height - canvasData.height) / 2; + canvasData.width = rotatedData.width; + canvasData.height = rotatedData.height; + canvasData.aspectRatio = aspectRatio; + canvasData.naturalWidth = imageData.naturalWidth; + canvasData.naturalHeight = imageData.naturalHeight; + + // Computes rotated sizes with natural image sizes + if (isSquareImage && rotate % 90 || rotate % 180) { + var rotatedData2 = getRotatedSizes({ + width: imageData.naturalWidth, + height: imageData.naturalHeight, + degree: rotate + }); + + canvasData.naturalWidth = rotatedData2.width; + canvasData.naturalHeight = rotatedData2.height; + } + + self.limitCanvas(true, false); + } + } + + if (canvasData.width > canvasData.maxWidth || canvasData.width < canvasData.minWidth) { + canvasData.left = canvasData.oldLeft; + } + + if (canvasData.height > canvasData.maxHeight || canvasData.height < canvasData.minHeight) { + canvasData.top = canvasData.oldTop; + } + + canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth); + canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight); + + self.limitCanvas(false, true); + + canvasData.oldLeft = canvasData.left = Math.min(Math.max(canvasData.left, canvasData.minLeft), canvasData.maxLeft); + canvasData.oldTop = canvasData.top = Math.min(Math.max(canvasData.top, canvasData.minTop), canvasData.maxTop); + + setStyle(self.canvas, extend({ + width: canvasData.width, + height: canvasData.height + }, getTransforms({ + translateX: canvasData.left, + translateY: canvasData.top + }))); + + self.renderImage(); + + if (self.cropped && self.limited) { + self.limitCropBox(true, true); + } + + if (changed) { + self.output(); + } + }, + renderImage: function renderImage(changed) { + var self = this; + var canvasData = self.canvasData; + var imageData = self.imageData; + var newImageData = void 0; + var reversedData = void 0; + var reversedWidth = void 0; + var reversedHeight = void 0; + + if (imageData.rotate) { + reversedData = getRotatedSizes({ + width: canvasData.width, + height: canvasData.height, + degree: imageData.rotate, + aspectRatio: imageData.aspectRatio + }, true); + + reversedWidth = reversedData.width; + reversedHeight = reversedData.height; + + newImageData = { + width: reversedWidth, + height: reversedHeight, + left: (canvasData.width - reversedWidth) / 2, + top: (canvasData.height - reversedHeight) / 2 + }; + } + + extend(imageData, newImageData || { + width: canvasData.width, + height: canvasData.height, + left: 0, + top: 0 + }); + + setStyle(self.image, extend({ + width: imageData.width, + height: imageData.height + }, getTransforms(extend({ + translateX: imageData.left, + translateY: imageData.top + }, imageData)))); + + if (changed) { + self.output(); + } + }, + initCropBox: function initCropBox() { + var self = this; + var options = self.options; + var aspectRatio = options.aspectRatio; + var autoCropArea = Number(options.autoCropArea) || 0.8; + var canvasData = self.canvasData; + var cropBoxData = { + width: canvasData.width, + height: canvasData.height + }; + + if (aspectRatio) { + if (canvasData.height * aspectRatio > canvasData.width) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + self.cropBoxData = cropBoxData; + self.limitCropBox(true, true); + + // Initialize auto crop area + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + // The width/height of auto crop area must large than "minWidth/Height" + cropBoxData.width = Math.max(cropBoxData.minWidth, cropBoxData.width * autoCropArea); + cropBoxData.height = Math.max(cropBoxData.minHeight, cropBoxData.height * autoCropArea); + cropBoxData.oldLeft = cropBoxData.left = canvasData.left + (canvasData.width - cropBoxData.width) / 2; + cropBoxData.oldTop = cropBoxData.top = canvasData.top + (canvasData.height - cropBoxData.height) / 2; + + self.initialCropBoxData = extend({}, cropBoxData); + }, + limitCropBox: function limitCropBox(sizeLimited, positionLimited) { + var self = this; + var options = self.options; + var aspectRatio = options.aspectRatio; + var containerData = self.containerData; + var canvasData = self.canvasData; + var cropBoxData = self.cropBoxData; + var limited = self.limited; + + if (sizeLimited) { + var minCropBoxWidth = Number(options.minCropBoxWidth) || 0; + var minCropBoxHeight = Number(options.minCropBoxHeight) || 0; + var maxCropBoxWidth = Math.min(containerData.width, limited ? canvasData.width : containerData.width); + var maxCropBoxHeight = Math.min(containerData.height, limited ? canvasData.height : containerData.height); + + // The min/maxCropBoxWidth/Height must be less than containerWidth/Height + minCropBoxWidth = Math.min(minCropBoxWidth, containerData.width); + minCropBoxHeight = Math.min(minCropBoxHeight, containerData.height); + + if (aspectRatio) { + if (minCropBoxWidth && minCropBoxHeight) { + if (minCropBoxHeight * aspectRatio > minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + } else if (minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else if (minCropBoxHeight) { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + + if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) { + maxCropBoxHeight = maxCropBoxWidth / aspectRatio; + } else { + maxCropBoxWidth = maxCropBoxHeight * aspectRatio; + } + } + + // The minWidth/Height must be less than maxWidth/Height + cropBoxData.minWidth = Math.min(minCropBoxWidth, maxCropBoxWidth); + cropBoxData.minHeight = Math.min(minCropBoxHeight, maxCropBoxHeight); + cropBoxData.maxWidth = maxCropBoxWidth; + cropBoxData.maxHeight = maxCropBoxHeight; + } + + if (positionLimited) { + if (limited) { + cropBoxData.minLeft = Math.max(0, canvasData.left); + cropBoxData.minTop = Math.max(0, canvasData.top); + cropBoxData.maxLeft = Math.min(containerData.width, canvasData.left + canvasData.width) - cropBoxData.width; + cropBoxData.maxTop = Math.min(containerData.height, canvasData.top + canvasData.height) - cropBoxData.height; + } else { + cropBoxData.minLeft = 0; + cropBoxData.minTop = 0; + cropBoxData.maxLeft = containerData.width - cropBoxData.width; + cropBoxData.maxTop = containerData.height - cropBoxData.height; + } + } + }, + renderCropBox: function renderCropBox() { + var self = this; + var options = self.options; + var containerData = self.containerData; + var cropBoxData = self.cropBoxData; + + if (cropBoxData.width > cropBoxData.maxWidth || cropBoxData.width < cropBoxData.minWidth) { + cropBoxData.left = cropBoxData.oldLeft; + } + + if (cropBoxData.height > cropBoxData.maxHeight || cropBoxData.height < cropBoxData.minHeight) { + cropBoxData.top = cropBoxData.oldTop; + } + + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + self.limitCropBox(false, true); + + cropBoxData.oldLeft = cropBoxData.left = Math.min(Math.max(cropBoxData.left, cropBoxData.minLeft), cropBoxData.maxLeft); + cropBoxData.oldTop = cropBoxData.top = Math.min(Math.max(cropBoxData.top, cropBoxData.minTop), cropBoxData.maxTop); + + if (options.movable && options.cropBoxMovable) { + // Turn to move the canvas when the crop box is equal to the container + setData$1(self.face, 'action', cropBoxData.width === containerData.width && cropBoxData.height === containerData.height ? 'move' : 'all'); + } + + setStyle(self.cropBox, extend({ + width: cropBoxData.width, + height: cropBoxData.height + }, getTransforms({ + translateX: cropBoxData.left, + translateY: cropBoxData.top + }))); + + if (self.cropped && self.limited) { + self.limitCanvas(true, true); + } + + if (!self.disabled) { + self.output(); + } + }, + output: function output() { + var self = this; + + self.preview(); + + if (self.complete) { + dispatchEvent(self.element, 'crop', self.getData()); + } + } +}; + +var DATA_PREVIEW = 'preview'; + +var preview$1 = { + initPreview: function initPreview() { + var self = this; + var preview = self.options.preview; + var image = createElement('img'); + var crossOrigin = self.crossOrigin; + var url = crossOrigin ? self.crossOriginUrl : self.url; + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = url; + appendChild(self.viewBox, image); + self.image2 = image; + + if (!preview) { + return; + } + + var previews = preview.querySelector ? [preview] : document.querySelectorAll(preview); + + self.previews = previews; + + each(previews, function (element) { + var img = createElement('img'); + + // Save the original size for recover + setData$1(element, DATA_PREVIEW, { + width: element.offsetWidth, + height: element.offsetHeight, + html: element.innerHTML + }); + + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.src = url; + + /** + * Override img element styles + * Add `display:block` to avoid margin top issue + * Add `height:auto` to override `height` attribute on IE8 + * (Occur only when margin-top <= -height) + */ + + 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;"'; + + empty(element); + appendChild(element, img); + }); + }, + resetPreview: function resetPreview() { + each(this.previews, function (element) { + var data = getData$1(element, DATA_PREVIEW); + + setStyle(element, { + width: data.width, + height: data.height + }); + + element.innerHTML = data.html; + removeData(element, DATA_PREVIEW); + }); + }, + preview: function preview() { + var self = this; + var imageData = self.imageData; + var canvasData = self.canvasData; + var cropBoxData = self.cropBoxData; + var cropBoxWidth = cropBoxData.width; + var cropBoxHeight = cropBoxData.height; + var width = imageData.width; + var height = imageData.height; + var left = cropBoxData.left - canvasData.left - imageData.left; + var top = cropBoxData.top - canvasData.top - imageData.top; + + if (!self.cropped || self.disabled) { + return; + } + + setStyle(self.image2, extend({ + width: width, + height: height + }, getTransforms(extend({ + translateX: -left, + translateY: -top + }, imageData)))); + + each(self.previews, function (element) { + var data = getData$1(element, DATA_PREVIEW); + var originalWidth = data.width; + var originalHeight = data.height; + var newWidth = originalWidth; + var newHeight = originalHeight; + var ratio = 1; + + if (cropBoxWidth) { + ratio = originalWidth / cropBoxWidth; + newHeight = cropBoxHeight * ratio; + } + + if (cropBoxHeight && newHeight > originalHeight) { + ratio = originalHeight / cropBoxHeight; + newWidth = cropBoxWidth * ratio; + newHeight = originalHeight; + } + + setStyle(element, { + width: newWidth, + height: newHeight + }); + + setStyle(getByTag(element, 'img')[0], extend({ + width: width * ratio, + height: height * ratio + }, getTransforms(extend({ + translateX: -left * ratio, + translateY: -top * ratio + }, imageData)))); + }); + } +}; + +// Globals +var PointerEvent = typeof window !== 'undefined' ? window.PointerEvent : null; + +// Events +var EVENT_POINTER_DOWN = PointerEvent ? 'pointerdown' : 'touchstart mousedown'; +var EVENT_POINTER_MOVE = PointerEvent ? 'pointermove' : 'touchmove mousemove'; +var EVENT_POINTER_UP = PointerEvent ? ' pointerup pointercancel' : 'touchend touchcancel mouseup'; +var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll'; +var EVENT_DBLCLICK = 'dblclick'; +var EVENT_RESIZE = 'resize'; +var EVENT_CROP_START = 'cropstart'; +var EVENT_CROP_MOVE = 'cropmove'; +var EVENT_CROP_END = 'cropend'; +var EVENT_CROP$1 = 'crop'; +var EVENT_ZOOM = 'zoom'; + +var events = { + bind: function bind() { + var self = this; + var options = self.options; + var element = self.element; + var cropper = self.cropper; + + if (isFunction(options.cropstart)) { + addListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + addListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + addListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + addListener(element, EVENT_CROP$1, options.crop); + } + + if (isFunction(options.zoom)) { + addListener(element, EVENT_ZOOM, options.zoom); + } + + addListener(cropper, EVENT_POINTER_DOWN, self.onCropStart = proxy(self.cropStart, self)); + + if (options.zoomable && options.zoomOnWheel) { + addListener(cropper, EVENT_WHEEL, self.onWheel = proxy(self.wheel, self)); + } + + if (options.toggleDragModeOnDblclick) { + addListener(cropper, EVENT_DBLCLICK, self.onDblclick = proxy(self.dblclick, self)); + } + + addListener(document, EVENT_POINTER_MOVE, self.onCropMove = proxy(self.cropMove, self)); + addListener(document, EVENT_POINTER_UP, self.onCropEnd = proxy(self.cropEnd, self)); + + if (options.responsive) { + addListener(window, EVENT_RESIZE, self.onResize = proxy(self.resize, self)); + } + }, + unbind: function unbind() { + var self = this; + var options = self.options; + var element = self.element; + var cropper = self.cropper; + + if (isFunction(options.cropstart)) { + removeListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + removeListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + removeListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + removeListener(element, EVENT_CROP$1, options.crop); + } + + if (isFunction(options.zoom)) { + removeListener(element, EVENT_ZOOM, options.zoom); + } + + removeListener(cropper, EVENT_POINTER_DOWN, self.onCropStart); + + if (options.zoomable && options.zoomOnWheel) { + removeListener(cropper, EVENT_WHEEL, self.onWheel); + } + + if (options.toggleDragModeOnDblclick) { + removeListener(cropper, EVENT_DBLCLICK, self.onDblclick); + } + + removeListener(document, EVENT_POINTER_MOVE, self.onCropMove); + removeListener(document, EVENT_POINTER_UP, self.onCropEnd); + + if (options.responsive) { + removeListener(window, EVENT_RESIZE, self.onResize); + } + } +}; + +var REGEXP_ACTIONS = /^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/; + +function getPointer(_ref, endOnly) { + var pageX = _ref.pageX, + pageY = _ref.pageY; + + var end = { + endX: pageX, + endY: pageY + }; + + if (endOnly) { + return end; + } + + return extend({ + startX: pageX, + startY: pageY + }, end); +} + +var handlers = { + resize: function resize() { + var self = this; + var options = self.options; + var container = self.container; + var containerData = self.containerData; + var minContainerWidth = Number(options.minContainerWidth) || 200; + var minContainerHeight = Number(options.minContainerHeight) || 100; + + if (self.disabled || containerData.width === minContainerWidth || containerData.height === minContainerHeight) { + return; + } + + var ratio = container.offsetWidth / containerData.width; + + // Resize when width changed or height changed + if (ratio !== 1 || container.offsetHeight !== containerData.height) { + (function () { + var canvasData = void 0; + var cropBoxData = void 0; + + if (options.restore) { + canvasData = self.getCanvasData(); + cropBoxData = self.getCropBoxData(); + } + + self.render(); + + if (options.restore) { + self.setCanvasData(each(canvasData, function (n, i) { + canvasData[i] = n * ratio; + })); + self.setCropBoxData(each(cropBoxData, function (n, i) { + cropBoxData[i] = n * ratio; + })); + } + })(); + } + }, + dblclick: function dblclick() { + var self = this; + + if (self.disabled || self.options.dragMode === 'none') { + return; + } + + self.setDragMode(hasClass(self.dragBox, 'cropper-crop') ? 'move' : 'crop'); + }, + wheel: function wheel(event) { + var self = this; + var e = getEvent(event); + var ratio = Number(self.options.wheelZoomRatio) || 0.1; + var delta = 1; + + if (self.disabled) { + return; + } + + e.preventDefault(); + + // Limit wheel speed to prevent zoom too fast (#21) + if (self.wheeling) { + return; + } + + self.wheeling = true; + + setTimeout(function () { + self.wheeling = false; + }, 50); + + if (e.deltaY) { + delta = e.deltaY > 0 ? 1 : -1; + } else if (e.wheelDelta) { + delta = -e.wheelDelta / 120; + } else if (e.detail) { + delta = e.detail > 0 ? 1 : -1; + } + + self.zoom(-delta * ratio, e); + }, + cropStart: function cropStart(event) { + var self = this; + + if (self.disabled) { + return; + } + + var options = self.options; + var pointers = self.pointers; + var e = getEvent(event); + var action = void 0; + + if (e.changedTouches) { + // Handle touch event + each(e.changedTouches, function (touch) { + pointers[touch.identifier] = getPointer(touch); + }); + } else { + // Handle mouse event and pointer event + pointers[e.pointerId || 0] = getPointer(e); + } + + if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) { + action = 'zoom'; + } else { + action = getData$1(e.target, 'action'); + } + + if (!REGEXP_ACTIONS.test(action)) { + return; + } + + if (dispatchEvent(self.element, 'cropstart', { + originalEvent: e, + action: action + }) === false) { + return; + } + + e.preventDefault(); + + self.action = action; + self.cropping = false; + + if (action === 'crop') { + self.cropping = true; + addClass(self.dragBox, 'cropper-modal'); + } + }, + cropMove: function cropMove(event) { + var self = this; + var action = self.action; + + if (self.disabled || !action) { + return; + } + + var pointers = self.pointers; + var e = getEvent(event); + + e.preventDefault(); + + if (dispatchEvent(self.element, 'cropmove', { + originalEvent: e, + action: action + }) === false) { + return; + } + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + extend(pointers[touch.identifier], getPointer(touch, true)); + }); + } else { + extend(pointers[e.pointerId || 0], getPointer(e, true)); + } + + self.change(e); + }, + cropEnd: function cropEnd(event) { + var self = this; + + if (self.disabled) { + return; + } + + var action = self.action; + var pointers = self.pointers; + var e = getEvent(event); + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + delete pointers[touch.identifier]; + }); + } else { + delete pointers[e.pointerId || 0]; + } + + if (!action) { + return; + } + + e.preventDefault(); + + if (!Object.keys(pointers).length) { + self.action = ''; + } + + if (self.cropping) { + self.cropping = false; + toggleClass(self.dragBox, 'cropper-modal', self.cropped && this.options.modal); + } + + dispatchEvent(self.element, 'cropend', { + originalEvent: e, + action: action + }); + } +}; + +// Actions +var ACTION_EAST = 'e'; +var ACTION_WEST = 'w'; +var ACTION_SOUTH = 's'; +var ACTION_NORTH = 'n'; +var ACTION_SOUTH_EAST = 'se'; +var ACTION_SOUTH_WEST = 'sw'; +var ACTION_NORTH_EAST = 'ne'; +var ACTION_NORTH_WEST = 'nw'; + +function getMaxZoomRatio(pointers) { + var pointers2 = extend({}, pointers); + var ratios = []; + + each(pointers, function (pointer, pointerId) { + delete pointers2[pointerId]; + + each(pointers2, function (pointer2) { + var x1 = Math.abs(pointer.startX - pointer2.startX); + var y1 = Math.abs(pointer.startY - pointer2.startY); + var x2 = Math.abs(pointer.endX - pointer2.endX); + var y2 = Math.abs(pointer.endY - pointer2.endY); + var z1 = Math.sqrt(x1 * x1 + y1 * y1); + var z2 = Math.sqrt(x2 * x2 + y2 * y2); + var ratio = (z2 - z1) / z1; + + ratios.push(ratio); + }); + }); + + ratios.sort(function (a, b) { + return Math.abs(a) < Math.abs(b); + }); + + return ratios[0]; +} + +var change$1 = { + change: function change(e) { + var self = this; + var options = self.options; + var containerData = self.containerData; + var canvasData = self.canvasData; + var cropBoxData = self.cropBoxData; + var aspectRatio = options.aspectRatio; + var action = self.action; + var width = cropBoxData.width; + var height = cropBoxData.height; + var left = cropBoxData.left; + var top = cropBoxData.top; + var right = left + width; + var bottom = top + height; + var minLeft = 0; + var minTop = 0; + var maxWidth = containerData.width; + var maxHeight = containerData.height; + var renderable = true; + var offset = void 0; + + // Locking aspect ratio in "free mode" by holding shift key + if (!aspectRatio && e.shiftKey) { + aspectRatio = width && height ? width / height : 1; + } + + if (self.limited) { + minLeft = cropBoxData.minLeft; + minTop = cropBoxData.minTop; + maxWidth = minLeft + Math.min(containerData.width, canvasData.width, canvasData.left + canvasData.width); + maxHeight = minTop + Math.min(containerData.height, canvasData.height, canvasData.top + canvasData.height); + } + + var pointers = self.pointers; + var pointer = pointers[Object.keys(pointers)[0]]; + var range = { + x: pointer.endX - pointer.startX, + y: pointer.endY - pointer.startY + }; + + if (aspectRatio) { + range.X = range.y * aspectRatio; + range.Y = range.x / aspectRatio; + } + + switch (action) { + // Move crop box + case 'all': + left += range.x; + top += range.y; + break; + + // Resize crop box + case ACTION_EAST: + if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + width += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top -= range.Y / 2; + } + + if (width < 0) { + action = ACTION_WEST; + width = 0; + } + + break; + + case ACTION_NORTH: + if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + height -= range.y; + top += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left += range.X / 2; + } + + if (height < 0) { + action = ACTION_SOUTH; + height = 0; + } + + break; + + case ACTION_WEST: + if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + width -= range.x; + left += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top += range.Y / 2; + } + + if (width < 0) { + action = ACTION_EAST; + width = 0; + } + + break; + + case ACTION_SOUTH: + if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + height += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left -= range.X / 2; + } + + if (height < 0) { + action = ACTION_NORTH; + height = 0; + } + + break; + + case ACTION_NORTH_EAST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || right >= maxWidth)) { + renderable = false; + break; + } + + height -= range.y; + top += range.y; + width = height * aspectRatio; + } else { + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + } + + break; + + case ACTION_NORTH_WEST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || left <= minLeft)) { + renderable = false; + break; + } + + height -= range.y; + top += range.y; + width = height * aspectRatio; + left += range.X; + } else { + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_WEST: + if (aspectRatio) { + if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) { + renderable = false; + break; + } + + width -= range.x; + left += range.x; + height = width / aspectRatio; + } else { + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_EAST: + if (aspectRatio) { + if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) { + renderable = false; + break; + } + + width += range.x; + height = width / aspectRatio; + } else { + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + } + + break; + + // Move canvas + case 'move': + self.move(range.x, range.y); + renderable = false; + break; + + // Zoom canvas + case 'zoom': + self.zoom(getMaxZoomRatio(pointers), e); + renderable = false; + break; + + // Create crop box + case 'crop': + if (!range.x || !range.y) { + renderable = false; + break; + } + + offset = getOffset(self.cropper); + left = pointer.startX - offset.left; + top = pointer.startY - offset.top; + width = cropBoxData.minWidth; + height = cropBoxData.minHeight; + + if (range.x > 0) { + action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST; + } else if (range.x < 0) { + left -= width; + action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST; + } + + if (range.y < 0) { + top -= height; + } + + // Show the crop box if is hidden + if (!self.cropped) { + removeClass(self.cropBox, 'cropper-hidden'); + self.cropped = true; + + if (self.limited) { + self.limitCropBox(true, true); + } + } + + break; + + // No default + } + + if (renderable) { + cropBoxData.width = width; + cropBoxData.height = height; + cropBoxData.left = left; + cropBoxData.top = top; + self.action = action; + + self.renderCropBox(); + } + + // Override + each(pointers, function (p) { + p.startX = p.endX; + p.startY = p.endY; + }); + } +}; + +function getPointersCenter(pointers) { + var pageX = 0; + var pageY = 0; + var count = 0; + + each(pointers, function (_ref) { + var startX = _ref.startX, + startY = _ref.startY; + + pageX += startX; + pageY += startY; + count += 1; + }); + + pageX /= count; + pageY /= count; + + return { + pageX: pageX, + pageY: pageY + }; +} + +var methods = { + // Show the crop box manually + crop: function crop() { + var self = this; + + if (self.ready && !self.disabled) { + if (!self.cropped) { + self.cropped = true; + self.limitCropBox(true, true); + + if (self.options.modal) { + addClass(self.dragBox, 'cropper-modal'); + } + + removeClass(self.cropBox, 'cropper-hidden'); + } + + self.setCropBoxData(self.initialCropBoxData); + } + + return self; + }, + + + // Reset the image and crop box to their initial states + reset: function reset() { + var self = this; + + if (self.ready && !self.disabled) { + self.imageData = extend({}, self.initialImageData); + self.canvasData = extend({}, self.initialCanvasData); + self.cropBoxData = extend({}, self.initialCropBoxData); + + self.renderCanvas(); + + if (self.cropped) { + self.renderCropBox(); + } + } + + return self; + }, + + + // Clear the crop box + clear: function clear() { + var self = this; + + if (self.cropped && !self.disabled) { + extend(self.cropBoxData, { + left: 0, + top: 0, + width: 0, + height: 0 + }); + + self.cropped = false; + self.renderCropBox(); + + self.limitCanvas(); + + // Render canvas after crop box rendered + self.renderCanvas(); + + removeClass(self.dragBox, 'cropper-modal'); + addClass(self.cropBox, 'cropper-hidden'); + } + + return self; + }, + + + /** + * Replace the image's src and rebuild the cropper + * + * @param {String} url + * @param {Boolean} onlyColorChanged (optional) + */ + replace: function replace(url, onlyColorChanged) { + var self = this; + + if (!self.disabled && url) { + if (self.isImg) { + self.element.src = url; + } + + if (onlyColorChanged) { + self.url = url; + self.image.src = url; + + if (self.ready) { + self.image2.src = url; + + each(self.previews, function (element) { + getByTag(element, 'img')[0].src = url; + }); + } + } else { + if (self.isImg) { + self.replaced = true; + } + + // Clear previous data + self.options.data = null; + self.load(url); + } + } + + return self; + }, + + + // Enable (unfreeze) the cropper + enable: function enable() { + var self = this; + + if (self.ready) { + self.disabled = false; + removeClass(self.cropper, 'cropper-disabled'); + } + + return self; + }, + + + // Disable (freeze) the cropper + disable: function disable() { + var self = this; + + if (self.ready) { + self.disabled = true; + addClass(self.cropper, 'cropper-disabled'); + } + + return self; + }, + + + // Destroy the cropper and remove the instance from the image + destroy: function destroy() { + var self = this; + var element = self.element; + var image = self.image; + + if (self.loaded) { + if (self.isImg && self.replaced) { + element.src = self.originalUrl; + } + + self.unbuild(); + removeClass(element, 'cropper-hidden'); + } else if (self.isImg) { + removeListener(element, 'load', self.onStart); + } else if (image) { + removeChild(image); + } + + removeData(element, 'cropper'); + + return self; + }, + + + /** + * Move the canvas with relative offsets + * + * @param {Number} offsetX + * @param {Number} offsetY (optional) + */ + move: function move(offsetX, offsetY) { + var self = this; + var canvasData = self.canvasData; + + return self.moveTo(isUndefined(offsetX) ? offsetX : canvasData.left + Number(offsetX), isUndefined(offsetY) ? offsetY : canvasData.top + Number(offsetY)); + }, + + + /** + * Move the canvas to an absolute point + * + * @param {Number} x + * @param {Number} y (optional) + */ + moveTo: function moveTo(x, y) { + var self = this; + var canvasData = self.canvasData; + var changed = false; + + // If "y" is not present, its default value is "x" + if (isUndefined(y)) { + y = x; + } + + x = Number(x); + y = Number(y); + + if (self.ready && !self.disabled && self.options.movable) { + if (isNumber(x)) { + canvasData.left = x; + changed = true; + } + + if (isNumber(y)) { + canvasData.top = y; + changed = true; + } + + if (changed) { + self.renderCanvas(true); + } + } + + return self; + }, + + + /** + * Zoom the canvas with a relative ratio + * + * @param {Number} ratio + * @param {Event} _originalEvent (private) + */ + zoom: function zoom(ratio, _originalEvent) { + var self = this; + var canvasData = self.canvasData; + + ratio = Number(ratio); + + if (ratio < 0) { + ratio = 1 / (1 - ratio); + } else { + ratio = 1 + ratio; + } + + return self.zoomTo(canvasData.width * ratio / canvasData.naturalWidth, _originalEvent); + }, + + + /** + * Zoom the canvas to an absolute ratio + * + * @param {Number} ratio + * @param {Event} _originalEvent (private) + */ + zoomTo: function zoomTo(ratio, _originalEvent) { + var self = this; + var options = self.options; + var canvasData = self.canvasData; + var width = canvasData.width; + var height = canvasData.height; + var naturalWidth = canvasData.naturalWidth; + var naturalHeight = canvasData.naturalHeight; + + ratio = Number(ratio); + + if (ratio >= 0 && self.ready && !self.disabled && options.zoomable) { + var newWidth = naturalWidth * ratio; + var newHeight = naturalHeight * ratio; + + if (dispatchEvent(self.element, 'zoom', { + originalEvent: _originalEvent, + oldRatio: width / naturalWidth, + ratio: newWidth / naturalWidth + }) === false) { + return self; + } + + if (_originalEvent) { + var pointers = self.pointers; + var offset = getOffset(self.cropper); + var center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : { + pageX: _originalEvent.pageX, + pageY: _originalEvent.pageY + }; + + // Zoom from the triggering point of the event + canvasData.left -= (newWidth - width) * ((center.pageX - offset.left - canvasData.left) / width); + canvasData.top -= (newHeight - height) * ((center.pageY - offset.top - canvasData.top) / height); + } else { + // Zoom from the center of the canvas + canvasData.left -= (newWidth - width) / 2; + canvasData.top -= (newHeight - height) / 2; + } + + canvasData.width = newWidth; + canvasData.height = newHeight; + self.renderCanvas(true); + } + + return self; + }, + + + /** + * Rotate the canvas with a relative degree + * + * @param {Number} degree + */ + rotate: function rotate(degree) { + var self = this; + + return self.rotateTo((self.imageData.rotate || 0) + Number(degree)); + }, + + + /** + * Rotate the canvas to an absolute degree + * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate() + * + * @param {Number} degree + */ + rotateTo: function rotateTo(degree) { + var self = this; + + degree = Number(degree); + + if (isNumber(degree) && self.ready && !self.disabled && self.options.rotatable) { + self.imageData.rotate = degree % 360; + self.rotated = true; + self.renderCanvas(true); + } + + return self; + }, + + + /** + * Scale the image + * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#scale() + * + * @param {Number} scaleX + * @param {Number} scaleY (optional) + */ + scale: function scale(scaleX, scaleY) { + var self = this; + var imageData = self.imageData; + var changed = false; + + // If "scaleY" is not present, its default value is "scaleX" + if (isUndefined(scaleY)) { + scaleY = scaleX; + } + + scaleX = Number(scaleX); + scaleY = Number(scaleY); + + if (self.ready && !self.disabled && self.options.scalable) { + if (isNumber(scaleX)) { + imageData.scaleX = scaleX; + changed = true; + } + + if (isNumber(scaleY)) { + imageData.scaleY = scaleY; + changed = true; + } + + if (changed) { + self.renderImage(true); + } + } + + return self; + }, + + + /** + * Scale the abscissa of the image + * + * @param {Number} scaleX + */ + scaleX: function scaleX(_scaleX) { + var self = this; + var scaleY = self.imageData.scaleY; + + return self.scale(_scaleX, isNumber(scaleY) ? scaleY : 1); + }, + + + /** + * Scale the ordinate of the image + * + * @param {Number} scaleY + */ + scaleY: function scaleY(_scaleY) { + var self = this; + var scaleX = self.imageData.scaleX; + + return self.scale(isNumber(scaleX) ? scaleX : 1, _scaleY); + }, + + + /** + * Get the cropped area position and size data (base on the original image) + * + * @param {Boolean} rounded (optional) + * @return {Object} data + */ + getData: function getData(rounded) { + var self = this; + var options = self.options; + var imageData = self.imageData; + var canvasData = self.canvasData; + var cropBoxData = self.cropBoxData; + var ratio = void 0; + var data = void 0; + + if (self.ready && self.cropped) { + data = { + x: cropBoxData.left - canvasData.left, + y: cropBoxData.top - canvasData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + + ratio = imageData.width / imageData.naturalWidth; + + each(data, function (n, i) { + n /= ratio; + data[i] = rounded ? Math.round(n) : n; + }); + } else { + data = { + x: 0, + y: 0, + width: 0, + height: 0 + }; + } + + if (options.rotatable) { + data.rotate = imageData.rotate || 0; + } + + if (options.scalable) { + data.scaleX = imageData.scaleX || 1; + data.scaleY = imageData.scaleY || 1; + } + + return data; + }, + + + /** + * Set the cropped area position and size with new data + * + * @param {Object} data + */ + setData: function setData(data) { + var self = this; + var options = self.options; + var imageData = self.imageData; + var canvasData = self.canvasData; + var cropBoxData = {}; + var rotated = void 0; + var scaled = void 0; + var ratio = void 0; + + if (isFunction(data)) { + data = data.call(self.element); + } + + if (self.ready && !self.disabled && isPlainObject(data)) { + if (options.rotatable) { + if (isNumber(data.rotate) && data.rotate !== imageData.rotate) { + imageData.rotate = data.rotate; + self.rotated = rotated = true; + } + } + + if (options.scalable) { + if (isNumber(data.scaleX) && data.scaleX !== imageData.scaleX) { + imageData.scaleX = data.scaleX; + scaled = true; + } + + if (isNumber(data.scaleY) && data.scaleY !== imageData.scaleY) { + imageData.scaleY = data.scaleY; + scaled = true; + } + } + + if (rotated) { + self.renderCanvas(); + } else if (scaled) { + self.renderImage(); + } + + ratio = imageData.width / imageData.naturalWidth; + + if (isNumber(data.x)) { + cropBoxData.left = data.x * ratio + canvasData.left; + } + + if (isNumber(data.y)) { + cropBoxData.top = data.y * ratio + canvasData.top; + } + + if (isNumber(data.width)) { + cropBoxData.width = data.width * ratio; + } + + if (isNumber(data.height)) { + cropBoxData.height = data.height * ratio; + } + + self.setCropBoxData(cropBoxData); + } + + return self; + }, + + + /** + * Get the container size data + * + * @return {Object} data + */ + getContainerData: function getContainerData() { + var self = this; + + return self.ready ? self.containerData : {}; + }, + + + /** + * Get the image position and size data + * + * @return {Object} data + */ + getImageData: function getImageData() { + var self = this; + + return self.loaded ? self.imageData : {}; + }, + + + /** + * Get the canvas position and size data + * + * @return {Object} data + */ + getCanvasData: function getCanvasData() { + var self = this; + var canvasData = self.canvasData; + var data = {}; + + if (self.ready) { + each(['left', 'top', 'width', 'height', 'naturalWidth', 'naturalHeight'], function (n) { + data[n] = canvasData[n]; + }); + } + + return data; + }, + + + /** + * Set the canvas position and size with new data + * + * @param {Object} data + */ + setCanvasData: function setCanvasData(data) { + var self = this; + var canvasData = self.canvasData; + var aspectRatio = canvasData.aspectRatio; + + if (isFunction(data)) { + data = data.call(self.element); + } + + if (self.ready && !self.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + canvasData.left = data.left; + } + + if (isNumber(data.top)) { + canvasData.top = data.top; + } + + if (isNumber(data.width)) { + canvasData.width = data.width; + canvasData.height = data.width / aspectRatio; + } else if (isNumber(data.height)) { + canvasData.height = data.height; + canvasData.width = data.height * aspectRatio; + } + + self.renderCanvas(true); + } + + return self; + }, + + + /** + * Get the crop box position and size data + * + * @return {Object} data + */ + getCropBoxData: function getCropBoxData() { + var self = this; + var cropBoxData = self.cropBoxData; + var data = void 0; + + if (self.ready && self.cropped) { + data = { + left: cropBoxData.left, + top: cropBoxData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + } + + return data || {}; + }, + + + /** + * Set the crop box position and size with new data + * + * @param {Object} data + */ + setCropBoxData: function setCropBoxData(data) { + var self = this; + var cropBoxData = self.cropBoxData; + var aspectRatio = self.options.aspectRatio; + var widthChanged = void 0; + var heightChanged = void 0; + + if (isFunction(data)) { + data = data.call(self.element); + } + + if (self.ready && self.cropped && !self.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + cropBoxData.left = data.left; + } + + if (isNumber(data.top)) { + cropBoxData.top = data.top; + } + + if (isNumber(data.width) && data.width !== cropBoxData.width) { + widthChanged = true; + cropBoxData.width = data.width; + } + + if (isNumber(data.height) && data.height !== cropBoxData.height) { + heightChanged = true; + cropBoxData.height = data.height; + } + + if (aspectRatio) { + if (widthChanged) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else if (heightChanged) { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + self.renderCropBox(); + } + + return self; + }, + + + /** + * Get a canvas drawn the cropped image + * + * @param {Object} options (optional) + * @return {HTMLCanvasElement} canvas + */ + getCroppedCanvas: function getCroppedCanvas(options) { + var self = this; + + if (!self.ready || !window.HTMLCanvasElement) { + return null; + } + + // Return the whole canvas if not cropped + if (!self.cropped) { + return getSourceCanvas(self.image, self.imageData); + } + + if (!isPlainObject(options)) { + options = {}; + } + + var data = self.getData(); + var originalWidth = data.width; + var originalHeight = data.height; + var aspectRatio = originalWidth / originalHeight; + var scaledWidth = void 0; + var scaledHeight = void 0; + var scaledRatio = void 0; + + if (isPlainObject(options)) { + scaledWidth = options.width; + scaledHeight = options.height; + + if (scaledWidth) { + scaledHeight = scaledWidth / aspectRatio; + scaledRatio = scaledWidth / originalWidth; + } else if (scaledHeight) { + scaledWidth = scaledHeight * aspectRatio; + scaledRatio = scaledHeight / originalHeight; + } + } + + // The canvas element will use `Math.floor` on a float number, so floor first + var canvasWidth = Math.floor(scaledWidth || originalWidth); + var canvasHeight = Math.floor(scaledHeight || originalHeight); + + var canvas = createElement('canvas'); + var context = canvas.getContext('2d'); + + canvas.width = canvasWidth; + canvas.height = canvasHeight; + + if (options.fillColor) { + context.fillStyle = options.fillColor; + context.fillRect(0, 0, canvasWidth, canvasHeight); + } + + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage + var parameters = function () { + var source = getSourceCanvas(self.image, self.imageData); + var sourceWidth = source.width; + var sourceHeight = source.height; + var canvasData = self.canvasData; + var params = [source]; + + // Source canvas + var srcX = data.x + canvasData.naturalWidth * (Math.abs(data.scaleX || 1) - 1) / 2; + var srcY = data.y + canvasData.naturalHeight * (Math.abs(data.scaleY || 1) - 1) / 2; + var srcWidth = void 0; + var srcHeight = void 0; + + // Destination canvas + var dstX = void 0; + var dstY = void 0; + var dstWidth = void 0; + var dstHeight = void 0; + + if (srcX <= -originalWidth || srcX > sourceWidth) { + srcX = srcWidth = dstX = dstWidth = 0; + } else if (srcX <= 0) { + dstX = -srcX; + srcX = 0; + srcWidth = dstWidth = Math.min(sourceWidth, originalWidth + srcX); + } else if (srcX <= sourceWidth) { + dstX = 0; + srcWidth = dstWidth = Math.min(originalWidth, sourceWidth - srcX); + } + + if (srcWidth <= 0 || srcY <= -originalHeight || srcY > sourceHeight) { + srcY = srcHeight = dstY = dstHeight = 0; + } else if (srcY <= 0) { + dstY = -srcY; + srcY = 0; + srcHeight = dstHeight = Math.min(sourceHeight, originalHeight + srcY); + } else if (srcY <= sourceHeight) { + dstY = 0; + srcHeight = dstHeight = Math.min(originalHeight, sourceHeight - srcY); + } + + params.push(Math.floor(srcX), Math.floor(srcY), Math.floor(srcWidth), Math.floor(srcHeight)); + + // Scale destination sizes + if (scaledRatio) { + dstX *= scaledRatio; + dstY *= scaledRatio; + dstWidth *= scaledRatio; + dstHeight *= scaledRatio; + } + + // Avoid "IndexSizeError" in IE and Firefox + if (dstWidth > 0 && dstHeight > 0) { + params.push(Math.floor(dstX), Math.floor(dstY), Math.floor(dstWidth), Math.floor(dstHeight)); + } + + return params; + }(); + + context.drawImage.apply(context, toConsumableArray(parameters)); + + return canvas; + }, + + + /** + * Change the aspect ratio of the crop box + * + * @param {Number} aspectRatio + */ + setAspectRatio: function setAspectRatio(aspectRatio) { + var self = this; + var options = self.options; + + if (!self.disabled && !isUndefined(aspectRatio)) { + // 0 -> NaN + options.aspectRatio = Math.max(0, aspectRatio) || NaN; + + if (self.ready) { + self.initCropBox(); + + if (self.cropped) { + self.renderCropBox(); + } + } + } + + return self; + }, + + + /** + * Change the drag mode + * + * @param {String} mode (optional) + */ + setDragMode: function setDragMode(mode) { + var self = this; + var options = self.options; + var dragBox = self.dragBox; + var face = self.face; + var croppable = void 0; + var movable = void 0; + + if (self.loaded && !self.disabled) { + croppable = mode === 'crop'; + movable = options.movable && mode === 'move'; + mode = croppable || movable ? mode : 'none'; + + setData$1(dragBox, 'action', mode); + toggleClass(dragBox, 'cropper-crop', croppable); + toggleClass(dragBox, 'cropper-move', movable); + + if (!options.cropBoxMovable) { + // Sync drag mode to crop box when it is not movable + setData$1(face, 'action', mode); + toggleClass(face, 'cropper-crop', croppable); + toggleClass(face, 'cropper-move', movable); + } + } + + return self; + } +}; + +// Constants +var NAMESPACE = 'cropper'; + +// Classes +var CLASS_HIDDEN = NAMESPACE + '-hidden'; + +// Events +var EVENT_ERROR = 'error'; +var EVENT_LOAD = 'load'; +var EVENT_READY = 'ready'; +var EVENT_CROP = 'crop'; + +// RegExps +var REGEXP_DATA_URL = /^data:/; +var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg;base64,/; + +var AnotherCropper = void 0; + +var Cropper = function () { + function Cropper(element, options) { + classCallCheck(this, Cropper); + + var self = this; + + self.element = element; + self.options = extend({}, DEFAULTS, isPlainObject(options) && options); + self.loaded = false; + self.ready = false; + self.complete = false; + self.rotated = false; + self.cropped = false; + self.disabled = false; + self.replaced = false; + self.limited = false; + self.wheeling = false; + self.isImg = false; + self.originalUrl = ''; + self.canvasData = null; + self.cropBoxData = null; + self.previews = null; + self.pointers = {}; + self.init(); + } + + createClass(Cropper, [{ + key: 'init', + value: function init() { + var self = this; + var element = self.element; + var tagName = element.tagName.toLowerCase(); + var url = void 0; + + if (getData$1(element, NAMESPACE)) { + return; + } + + setData$1(element, NAMESPACE, self); + + if (tagName === 'img') { + self.isImg = true; + + // e.g.: "img/picture.jpg" + self.originalUrl = url = element.getAttribute('src'); + + // Stop when it's a blank image + if (!url) { + return; + } + + // e.g.: "http://example.com/img/picture.jpg" + url = element.src; + } else if (tagName === 'canvas' && window.HTMLCanvasElement) { + url = element.toDataURL(); + } + + self.load(url); + } + }, { + key: 'load', + value: function load(url) { + var self = this; + var options = self.options; + var element = self.element; + + if (!url) { + return; + } + + self.url = url; + self.imageData = {}; + + if (!options.checkOrientation || !window.ArrayBuffer) { + self.clone(); + return; + } + + // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari + if (REGEXP_DATA_URL.test(url)) { + if (REGEXP_DATA_URL_JPEG) { + self.read(dataURLToArrayBuffer(url)); + } else { + self.clone(); + } + return; + } + + var xhr = new XMLHttpRequest(); + + xhr.onerror = xhr.onabort = function () { + self.clone(); + }; + + xhr.onload = function () { + self.read(xhr.response); + }; + + if (options.checkCrossOrigin && isCrossOriginURL(url) && element.crossOrigin) { + url = addTimestamp(url); + } + + xhr.open('get', url); + xhr.responseType = 'arraybuffer'; + xhr.withCredentials = element.crossOrigin === 'use-credentials'; + xhr.send(); + } + }, { + key: 'read', + value: function read(arrayBuffer) { + var self = this; + var options = self.options; + var orientation = getOrientation(arrayBuffer); + var imageData = self.imageData; + var rotate = 0; + var scaleX = 1; + var scaleY = 1; + + if (orientation > 1) { + self.url = arrayBufferToDataURL(arrayBuffer); + + switch (orientation) { + + // flip horizontal + case 2: + scaleX = -1; + break; + + // rotate left 180° + case 3: + rotate = -180; + break; + + // flip vertical + case 4: + scaleY = -1; + break; + + // flip vertical + rotate right 90° + case 5: + rotate = 90; + scaleY = -1; + break; + + // rotate right 90° + case 6: + rotate = 90; + break; + + // flip horizontal + rotate right 90° + case 7: + rotate = 90; + scaleX = -1; + break; + + // rotate left 90° + case 8: + rotate = -90; + break; + } + } + + if (options.rotatable) { + imageData.rotate = rotate; + } + + if (options.scalable) { + imageData.scaleX = scaleX; + imageData.scaleY = scaleY; + } + + self.clone(); + } + }, { + key: 'clone', + value: function clone() { + var self = this; + var element = self.element; + var url = self.url; + var crossOrigin = void 0; + var crossOriginUrl = void 0; + var start = void 0; + var stop = void 0; + + if (self.options.checkCrossOrigin && isCrossOriginURL(url)) { + crossOrigin = element.crossOrigin; + + if (crossOrigin) { + crossOriginUrl = url; + } else { + crossOrigin = 'anonymous'; + + // Bust cache when there is not a "crossOrigin" property + crossOriginUrl = addTimestamp(url); + } + } + + self.crossOrigin = crossOrigin; + self.crossOriginUrl = crossOriginUrl; + + var image = createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = crossOriginUrl || url; + self.image = image; + self.onStart = start = proxy(self.start, self); + self.onStop = stop = proxy(self.stop, self); + + if (self.isImg) { + if (element.complete) { + self.start(); + } else { + addListener(element, EVENT_LOAD, start); + } + } else { + addListener(image, EVENT_LOAD, start); + addListener(image, EVENT_ERROR, stop); + addClass(image, 'cropper-hide'); + element.parentNode.insertBefore(image, element.nextSibling); + } + } + }, { + key: 'start', + value: function start(event) { + var self = this; + var image = self.isImg ? self.element : self.image; + + if (event) { + removeListener(image, EVENT_LOAD, self.onStart); + removeListener(image, EVENT_ERROR, self.onStop); + } + + getImageSize(image, function (naturalWidth, naturalHeight) { + extend(self.imageData, { + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + aspectRatio: naturalWidth / naturalHeight + }); + + self.loaded = true; + self.build(); + }); + } + }, { + key: 'stop', + value: function stop() { + var self = this; + var image = self.image; + + removeListener(image, EVENT_LOAD, self.onStart); + removeListener(image, EVENT_ERROR, self.onStop); + + removeChild(image); + self.image = null; + } + }, { + key: 'build', + value: function build() { + var self = this; + var options = self.options; + var element = self.element; + var image = self.image; + var container = void 0; + var cropper = void 0; + var canvas = void 0; + var dragBox = void 0; + var cropBox = void 0; + var face = void 0; + + if (!self.loaded) { + return; + } + + // Unbuild first when replace + if (self.ready) { + self.unbuild(); + } + + var template = createElement('div'); + template.innerHTML = TEMPLATE; + + // Create cropper elements + self.container = container = element.parentNode; + self.cropper = cropper = getByClass(template, 'cropper-container')[0]; + self.canvas = canvas = getByClass(cropper, 'cropper-canvas')[0]; + self.dragBox = dragBox = getByClass(cropper, 'cropper-drag-box')[0]; + self.cropBox = cropBox = getByClass(cropper, 'cropper-crop-box')[0]; + self.viewBox = getByClass(cropper, 'cropper-view-box')[0]; + self.face = face = getByClass(cropBox, 'cropper-face')[0]; + + appendChild(canvas, image); + + // Hide the original image + addClass(element, CLASS_HIDDEN); + + // Inserts the cropper after to the current image + container.insertBefore(cropper, element.nextSibling); + + // Show the image if is hidden + if (!self.isImg) { + removeClass(image, 'cropper-hide'); + } + + self.initPreview(); + self.bind(); + + options.aspectRatio = Math.max(0, options.aspectRatio) || NaN; + options.viewMode = Math.max(0, Math.min(3, Math.round(options.viewMode))) || 0; + + self.cropped = options.autoCrop; + + if (options.autoCrop) { + if (options.modal) { + addClass(dragBox, 'cropper-modal'); + } + } else { + addClass(cropBox, CLASS_HIDDEN); + } + + if (!options.guides) { + addClass(getByClass(cropBox, 'cropper-dashed'), CLASS_HIDDEN); + } + + if (!options.center) { + addClass(getByClass(cropBox, 'cropper-center'), CLASS_HIDDEN); + } + + if (options.background) { + addClass(cropper, 'cropper-bg'); + } + + if (!options.highlight) { + addClass(face, 'cropper-invisible'); + } + + if (options.cropBoxMovable) { + addClass(face, 'cropper-move'); + setData$1(face, 'action', 'all'); + } + + if (!options.cropBoxResizable) { + addClass(getByClass(cropBox, 'cropper-line'), CLASS_HIDDEN); + addClass(getByClass(cropBox, 'cropper-point'), CLASS_HIDDEN); + } + + self.setDragMode(options.dragMode); + self.render(); + self.ready = true; + self.setData(options.data); + + // Call the "ready" option asynchronously to keep "image.cropper" is defined + self.completing = setTimeout(function () { + if (isFunction(options.ready)) { + addListener(element, EVENT_READY, options.ready, true); + } + + dispatchEvent(element, EVENT_READY); + dispatchEvent(element, EVENT_CROP, self.getData()); + + self.complete = true; + }, 0); + } + }, { + key: 'unbuild', + value: function unbuild() { + var self = this; + + if (!self.ready) { + return; + } + + if (!self.complete) { + clearTimeout(self.completing); + } + + self.ready = false; + self.complete = false; + self.initialImageData = null; + + // Clear `initialCanvasData` is necessary when replace + self.initialCanvasData = null; + self.initialCropBoxData = null; + self.containerData = null; + self.canvasData = null; + + // Clear `cropBoxData` is necessary when replace + self.cropBoxData = null; + self.unbind(); + + self.resetPreview(); + self.previews = null; + + self.viewBox = null; + self.cropBox = null; + self.dragBox = null; + self.canvas = null; + self.container = null; + + removeChild(self.cropper); + self.cropper = null; + } + }], [{ + key: 'noConflict', + value: function noConflict() { + window.Cropper = AnotherCropper; + return Cropper; + } + }, { + key: 'setDefaults', + value: function setDefaults(options) { + extend(DEFAULTS, isPlainObject(options) && options); + } + }]); + return Cropper; +}(); + +extend(Cropper.prototype, render$1); +extend(Cropper.prototype, preview$1); +extend(Cropper.prototype, events); +extend(Cropper.prototype, handlers); +extend(Cropper.prototype, change$1); +extend(Cropper.prototype, methods); + +if (typeof window !== 'undefined') { + AnotherCropper = window.Cropper; + window.Cropper = Cropper; +} + +module.exports = Cropper; diff --git a/dist/cropper.css b/dist/cropper.css index edf515388..2878c950d 100644 --- a/dist/cropper.css +++ b/dist/cropper.css @@ -1,11 +1,11 @@ /*! - * Cropper.js v1.0.0-rc + * Cropper.js v1.0.0-rc.1 * https://github.com/fengyuanchen/cropperjs * * Copyright (c) 2017 Fengyuan Chen * Released under the MIT license * - * Date: 2017-03-25T12:02:21.062Z + * Date: 2017-04-30T03:26:33.550Z */ .cropper-container { diff --git a/dist/cropper.esm.js b/dist/cropper.esm.js new file mode 100644 index 000000000..85faed38b --- /dev/null +++ b/dist/cropper.esm.js @@ -0,0 +1,3558 @@ +/*! + * Cropper.js v1.0.0-rc.1 + * https://github.com/fengyuanchen/cropperjs + * + * Copyright (c) 2017 Fengyuan Chen + * Released under the MIT license + * + * Date: 2017-04-30T03:26:33.550Z + */ + +var DEFAULTS = { + // Define the view mode of the cropper + viewMode: 0, // 0, 1, 2, 3 + + // Define the dragging mode of the cropper + dragMode: 'crop', // 'crop', 'move' or 'none' + + // Define the aspect ratio of the crop box + aspectRatio: NaN, + + // An object with the previous cropping result data + data: null, + + // A selector for adding extra containers to preview + preview: '', + + // Re-render the cropper when resize the window + responsive: true, + + // Restore the cropped area after resize the window + restore: true, + + // Check if the current image is a cross-origin image + checkCrossOrigin: true, + + // Check the current image's Exif Orientation information + checkOrientation: true, + + // Show the black modal + modal: true, + + // Show the dashed lines for guiding + guides: true, + + // Show the center indicator for guiding + center: true, + + // Show the white modal to highlight the crop box + highlight: true, + + // Show the grid background + background: true, + + // Enable to crop the image automatically when initialize + autoCrop: true, + + // Define the percentage of automatic cropping area when initializes + autoCropArea: 0.8, + + // Enable to move the image + movable: true, + + // Enable to rotate the image + rotatable: true, + + // Enable to scale the image + scalable: true, + + // Enable to zoom the image + zoomable: true, + + // Enable to zoom the image by dragging touch + zoomOnTouch: true, + + // Enable to zoom the image by wheeling mouse + zoomOnWheel: true, + + // Define zoom ratio when zoom the image by wheeling mouse + wheelZoomRatio: 0.1, + + // Enable to move the crop box + cropBoxMovable: true, + + // Enable to resize the crop box + cropBoxResizable: true, + + // Toggle drag mode between "crop" and "move" when click twice on the cropper + toggleDragModeOnDblclick: true, + + // Size limitation + minCanvasWidth: 0, + minCanvasHeight: 0, + minCropBoxWidth: 0, + minCropBoxHeight: 0, + minContainerWidth: 200, + minContainerHeight: 100, + + // Shortcuts of events + ready: null, + cropstart: null, + cropmove: null, + cropend: null, + crop: null, + zoom: null +}; + +var TEMPLATE = '
' + '
' + '
' + '
' + '
' + '
' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
' + '
'; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; +}; + + + + + + + + + + + +var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +}; + +var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +}(); + + + + + + + +var get = function get(object, property, receiver) { + if (object === null) object = Function.prototype; + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent === null) { + return undefined; + } else { + return get(parent, property, receiver); + } + } else if ("value" in desc) { + return desc.value; + } else { + var getter = desc.get; + + if (getter === undefined) { + return undefined; + } + + return getter.call(receiver); + } +}; + + + + + + + + + + + + + + + + + +var set = function set(object, property, value, receiver) { + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent !== null) { + set(parent, property, value, receiver); + } + } else if ("value" in desc && desc.writable) { + desc.value = value; + } else { + var setter = desc.set; + + if (setter !== undefined) { + setter.call(receiver, value); + } + } + + return value; +}; + + + + + + + + + + + + + + + +var toConsumableArray = function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } else { + return Array.from(arr); + } +}; + +// RegExps +var REGEXP_DATA_URL_HEAD = /^data:.*,/; +var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g; +var REGEXP_ORIGINS = /^(https?:)\/\/([^:/?#]+):?(\d*)/i; +var REGEXP_SPACES = /\s+/; +var REGEXP_SUFFIX = /^(width|height|left|top|marginLeft|marginTop)$/; +var REGEXP_TRIM = /^\s+(.*)\s+$/; +var REGEXP_USERAGENT = /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i; + +// Utilities +var navigator = typeof window !== 'undefined' ? window.navigator : null; +var IS_SAFARI_OR_UIWEBVIEW = navigator && REGEXP_USERAGENT.test(navigator.userAgent); +var objectProto = Object.prototype; +var toString = objectProto.toString; +var hasOwnProperty = objectProto.hasOwnProperty; +var slice = Array.prototype.slice; +var fromCharCode = String.fromCharCode; + +function typeOf(obj) { + return toString.call(obj).slice(8, -1).toLowerCase(); +} + +function isNumber(num) { + return typeof num === 'number' && !isNaN(num); +} + +function isUndefined(obj) { + return typeof obj === 'undefined'; +} + +function isObject(obj) { + return (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' && obj !== null; +} + +function isPlainObject(obj) { + if (!isObject(obj)) { + return false; + } + + try { + var _constructor = obj.constructor; + var prototype = _constructor.prototype; + + return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf'); + } catch (e) { + return false; + } +} + +function isFunction(fn) { + return typeOf(fn) === 'function'; +} + +function isArray(arr) { + return Array.isArray ? Array.isArray(arr) : typeOf(arr) === 'array'; +} + + + +function trim(str) { + if (typeof str === 'string') { + str = str.trim ? str.trim() : str.replace(REGEXP_TRIM, '$1'); + } + + return str; +} + +function each(obj, callback) { + if (obj && isFunction(callback)) { + var i = void 0; + + if (isArray(obj) || isNumber(obj.length) /* array-like */) { + var length = obj.length; + + for (i = 0; i < length; i++) { + if (callback.call(obj, obj[i], i, obj) === false) { + break; + } + } + } else if (isObject(obj)) { + Object.keys(obj).forEach(function (key) { + callback.call(obj, obj[key], key, obj); + }); + } + } + + return obj; +} + +function extend(obj) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (isObject(obj) && args.length > 0) { + if (Object.assign) { + return Object.assign.apply(Object, [obj].concat(args)); + } + + args.forEach(function (arg) { + if (isObject(arg)) { + Object.keys(arg).forEach(function (key) { + obj[key] = arg[key]; + }); + } + }); + } + + return obj; +} + +function proxy(fn, context) { + for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { + args[_key2 - 2] = arguments[_key2]; + } + + return function () { + for (var _len3 = arguments.length, args2 = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args2[_key3] = arguments[_key3]; + } + + return fn.apply(context, args.concat(args2)); + }; +} + +function setStyle(element, styles) { + var style = element.style; + + each(styles, function (value, property) { + if (REGEXP_SUFFIX.test(property) && isNumber(value)) { + value += 'px'; + } + + style[property] = value; + }); +} + +function hasClass(element, value) { + return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1; +} + +function addClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + addClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.add(value); + return; + } + + var className = trim(element.className); + + if (!className) { + element.className = value; + } else if (className.indexOf(value) < 0) { + element.className = className + ' ' + value; + } +} + +function removeClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + removeClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.remove(value); + return; + } + + if (element.className.indexOf(value) >= 0) { + element.className = element.className.replace(value, ''); + } +} + +function toggleClass(element, value, added) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + toggleClass(elem, value, added); + }); + return; + } + + // IE10-11 doesn't support the second parameter of `classList.toggle` + if (added) { + addClass(element, value); + } else { + removeClass(element, value); + } +} + +function hyphenate(str) { + return str.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase(); +} + +function getData$1(element, name) { + if (isObject(element[name])) { + return element[name]; + } else if (element.dataset) { + return element.dataset[name]; + } + + return element.getAttribute('data-' + hyphenate(name)); +} + +function setData$1(element, name, data) { + if (isObject(data)) { + element[name] = data; + } else if (element.dataset) { + element.dataset[name] = data; + } else { + element.setAttribute('data-' + hyphenate(name), data); + } +} + +function removeData(element, name) { + if (isObject(element[name])) { + delete element[name]; + } else if (element.dataset) { + // #128 Safari not allows to delete dataset property + try { + delete element.dataset[name]; + } catch (e) { + element.dataset[name] = null; + } + } else { + element.removeAttribute('data-' + hyphenate(name)); + } +} + +function removeListener(element, type, handler) { + var types = trim(type).split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, function (t) { + removeListener(element, t, handler); + }); + return; + } + + if (element.removeEventListener) { + element.removeEventListener(type, handler, false); + } else if (element.detachEvent) { + element.detachEvent('on' + type, handler); + } +} + +function addListener(element, type, _handler, once) { + var types = trim(type).split(REGEXP_SPACES); + var originalHandler = _handler; + + if (types.length > 1) { + each(types, function (t) { + addListener(element, t, _handler); + }); + return; + } + + if (once) { + _handler = function handler() { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + removeListener(element, type, _handler); + + return originalHandler.apply(element, args); + }; + } + + if (element.addEventListener) { + element.addEventListener(type, _handler, false); + } else if (element.attachEvent) { + element.attachEvent('on' + type, _handler); + } +} + +function dispatchEvent(element, type, data) { + if (element.dispatchEvent) { + var event = void 0; + + // Event and CustomEvent on IE9-11 are global objects, not constructors + if (isFunction(Event) && isFunction(CustomEvent)) { + if (isUndefined(data)) { + event = new Event(type, { + bubbles: true, + cancelable: true + }); + } else { + event = new CustomEvent(type, { + detail: data, + bubbles: true, + cancelable: true + }); + } + } else if (isUndefined(data)) { + event = document.createEvent('Event'); + event.initEvent(type, true, true); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(type, true, true, data); + } + + // IE9+ + return element.dispatchEvent(event); + } else if (element.fireEvent) { + // IE6-10 (native events only) + return element.fireEvent('on' + type); + } + + return true; +} + +function getEvent(event) { + var e = event || window.event; + + // Fix target property (IE8) + if (!e.target) { + e.target = e.srcElement || document; + } + + if (!isNumber(e.pageX) && isNumber(e.clientX)) { + var eventDoc = event.target.ownerDocument || document; + var doc = eventDoc.documentElement; + var body = eventDoc.body; + + e.pageX = e.clientX + ((doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0)); + e.pageY = e.clientY + ((doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0)); + } + + return e; +} + +function getOffset(element) { + var doc = document.documentElement; + var box = element.getBoundingClientRect(); + + return { + left: box.left + ((window.scrollX || doc && doc.scrollLeft || 0) - (doc && doc.clientLeft || 0)), + top: box.top + ((window.scrollY || doc && doc.scrollTop || 0) - (doc && doc.clientTop || 0)) + }; +} + +function getByTag(element, tagName) { + return element.getElementsByTagName(tagName); +} + +function getByClass(element, className) { + return element.getElementsByClassName ? element.getElementsByClassName(className) : element.querySelectorAll('.' + className); +} + +function createElement(tagName) { + return document.createElement(tagName); +} + +function appendChild(element, elem) { + element.appendChild(elem); +} + +function removeChild(element) { + if (element.parentNode) { + element.parentNode.removeChild(element); + } +} + +function empty(element) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} + +function isCrossOriginURL(url) { + var parts = url.match(REGEXP_ORIGINS); + + return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port); +} + +function addTimestamp(url) { + var timestamp = 'timestamp=' + new Date().getTime(); + + return url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp; +} + +function getImageSize(image, callback) { + // Modern browsers (ignore Safari) + if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) { + callback(image.naturalWidth, image.naturalHeight); + return; + } + + // IE8: Don't use `new Image()` here + var newImage = createElement('img'); + + newImage.onload = function load() { + callback(this.width, this.height); + }; + + newImage.src = image.src; +} + +function getTransforms(data) { + var transforms = []; + var translateX = data.translateX; + var translateY = data.translateY; + var rotate = data.rotate; + var scaleX = data.scaleX; + var scaleY = data.scaleY; + + if (isNumber(translateX) && translateX !== 0) { + transforms.push('translateX(' + translateX + 'px)'); + } + + if (isNumber(translateY) && translateY !== 0) { + transforms.push('translateY(' + translateY + 'px)'); + } + + // Rotate should come first before scale to match orientation transform + if (isNumber(rotate) && rotate !== 0) { + transforms.push('rotate(' + rotate + 'deg)'); + } + + if (isNumber(scaleX) && scaleX !== 1) { + transforms.push('scaleX(' + scaleX + ')'); + } + + if (isNumber(scaleY) && scaleY !== 1) { + transforms.push('scaleY(' + scaleY + ')'); + } + + var transform = transforms.length ? transforms.join(' ') : 'none'; + + return { + WebkitTransform: transform, + msTransform: transform, + transform: transform + }; +} + +function getRotatedSizes(data, reversed) { + var deg = Math.abs(data.degree) % 180; + var arc = (deg > 90 ? 180 - deg : deg) * Math.PI / 180; + var sinArc = Math.sin(arc); + var cosArc = Math.cos(arc); + var width = data.width; + var height = data.height; + var aspectRatio = data.aspectRatio; + var newWidth = void 0; + var newHeight = void 0; + + if (!reversed) { + newWidth = width * cosArc + height * sinArc; + newHeight = width * sinArc + height * cosArc; + } else { + newWidth = width / (cosArc + sinArc / aspectRatio); + newHeight = newWidth / aspectRatio; + } + + return { + width: newWidth, + height: newHeight + }; +} + +function getSourceCanvas(image, data) { + var canvas = createElement('canvas'); + var context = canvas.getContext('2d'); + var dstX = 0; + var dstY = 0; + var dstWidth = data.naturalWidth; + var dstHeight = data.naturalHeight; + var rotate = data.rotate; + var scaleX = data.scaleX; + var scaleY = data.scaleY; + var scalable = isNumber(scaleX) && isNumber(scaleY) && (scaleX !== 1 || scaleY !== 1); + var rotatable = isNumber(rotate) && rotate !== 0; + var advanced = rotatable || scalable; + var canvasWidth = dstWidth * Math.abs(scaleX || 1); + var canvasHeight = dstHeight * Math.abs(scaleY || 1); + var translateX = void 0; + var translateY = void 0; + var rotated = void 0; + + if (scalable) { + translateX = canvasWidth / 2; + translateY = canvasHeight / 2; + } + + if (rotatable) { + rotated = getRotatedSizes({ + width: canvasWidth, + height: canvasHeight, + degree: rotate + }); + + canvasWidth = rotated.width; + canvasHeight = rotated.height; + translateX = canvasWidth / 2; + translateY = canvasHeight / 2; + } + + canvas.width = canvasWidth; + canvas.height = canvasHeight; + + if (advanced) { + dstX = -dstWidth / 2; + dstY = -dstHeight / 2; + + context.save(); + context.translate(translateX, translateY); + } + + // Rotate should come first before scale as in the "getTransform" function + if (rotatable) { + context.rotate(rotate * Math.PI / 180); + } + + if (scalable) { + context.scale(scaleX, scaleY); + } + + context.drawImage(image, Math.floor(dstX), Math.floor(dstY), Math.floor(dstWidth), Math.floor(dstHeight)); + + if (advanced) { + context.restore(); + } + + return canvas; +} + +function getStringFromCharCode(dataView, start, length) { + var str = ''; + var i = start; + + for (length += start; i < length; i++) { + str += fromCharCode(dataView.getUint8(i)); + } + + return str; +} + +function getOrientation(arrayBuffer) { + var dataView = new DataView(arrayBuffer); + var length = dataView.byteLength; + var orientation = void 0; + var exifIDCode = void 0; + var tiffOffset = void 0; + var firstIFDOffset = void 0; + var littleEndian = void 0; + var endianness = void 0; + var app1Start = void 0; + var ifdStart = void 0; + var offset = void 0; + var i = void 0; + + // Only handle JPEG image (start by 0xFFD8) + if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) { + offset = 2; + + while (offset < length) { + if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) { + app1Start = offset; + break; + } + + offset++; + } + } + + if (app1Start) { + exifIDCode = app1Start + 4; + tiffOffset = app1Start + 10; + + if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') { + endianness = dataView.getUint16(tiffOffset); + littleEndian = endianness === 0x4949; + + if (littleEndian || endianness === 0x4D4D /* bigEndian */) { + if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) { + firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian); + + if (firstIFDOffset >= 0x00000008) { + ifdStart = tiffOffset + firstIFDOffset; + } + } + } + } + } + + if (ifdStart) { + length = dataView.getUint16(ifdStart, littleEndian); + + for (i = 0; i < length; i++) { + offset = ifdStart + i * 12 + 2; + + if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) { + // 8 is the offset of the current tag's value + offset += 8; + + // Get the original orientation value + orientation = dataView.getUint16(offset, littleEndian); + + // Override the orientation with its default value for Safari + if (IS_SAFARI_OR_UIWEBVIEW) { + dataView.setUint16(offset, 1, littleEndian); + } + + break; + } + } + } + + return orientation; +} + +function dataURLToArrayBuffer(dataURL) { + var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, ''); + var binary = atob(base64); + var length = binary.length; + var arrayBuffer = new ArrayBuffer(length); + var dataView = new Uint8Array(arrayBuffer); + var i = void 0; + + for (i = 0; i < length; i++) { + dataView[i] = binary.charCodeAt(i); + } + + return arrayBuffer; +} + +// Only available for JPEG image +function arrayBufferToDataURL(arrayBuffer) { + var dataView = new Uint8Array(arrayBuffer); + var length = dataView.length; + var base64 = ''; + var i = void 0; + + for (i = 0; i < length; i++) { + base64 += fromCharCode(dataView[i]); + } + + return 'data:image/jpeg;base64,' + btoa(base64); +} + +var render$1 = { + render: function render() { + var self = this; + + self.initContainer(); + self.initCanvas(); + self.initCropBox(); + + self.renderCanvas(); + + if (self.cropped) { + self.renderCropBox(); + } + }, + initContainer: function initContainer() { + var self = this; + var options = self.options; + var element = self.element; + var container = self.container; + var cropper = self.cropper; + var hidden = 'cropper-hidden'; + var containerData = void 0; + + addClass(cropper, hidden); + removeClass(element, hidden); + + self.containerData = containerData = { + width: Math.max(container.offsetWidth, Number(options.minContainerWidth) || 200), + height: Math.max(container.offsetHeight, Number(options.minContainerHeight) || 100) + }; + + setStyle(cropper, { + width: containerData.width, + height: containerData.height + }); + + addClass(element, hidden); + removeClass(cropper, hidden); + }, + + + // Canvas (image wrapper) + initCanvas: function initCanvas() { + var self = this; + var viewMode = self.options.viewMode; + var containerData = self.containerData; + var imageData = self.imageData; + var rotated = Math.abs(imageData.rotate) === 90; + var naturalWidth = rotated ? imageData.naturalHeight : imageData.naturalWidth; + var naturalHeight = rotated ? imageData.naturalWidth : imageData.naturalHeight; + var aspectRatio = naturalWidth / naturalHeight; + var canvasWidth = containerData.width; + var canvasHeight = containerData.height; + + if (containerData.height * aspectRatio > containerData.width) { + if (viewMode === 3) { + canvasWidth = containerData.height * aspectRatio; + } else { + canvasHeight = containerData.width / aspectRatio; + } + } else if (viewMode === 3) { + canvasHeight = containerData.width / aspectRatio; + } else { + canvasWidth = containerData.height * aspectRatio; + } + + var canvasData = { + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + aspectRatio: aspectRatio, + width: canvasWidth, + height: canvasHeight + }; + + canvasData.oldLeft = canvasData.left = (containerData.width - canvasWidth) / 2; + canvasData.oldTop = canvasData.top = (containerData.height - canvasHeight) / 2; + + self.canvasData = canvasData; + self.limited = viewMode === 1 || viewMode === 2; + self.limitCanvas(true, true); + self.initialImageData = extend({}, imageData); + self.initialCanvasData = extend({}, canvasData); + }, + limitCanvas: function limitCanvas(sizeLimited, positionLimited) { + var self = this; + var options = self.options; + var viewMode = options.viewMode; + var containerData = self.containerData; + var canvasData = self.canvasData; + var aspectRatio = canvasData.aspectRatio; + var cropBoxData = self.cropBoxData; + var cropped = self.cropped && cropBoxData; + + if (sizeLimited) { + var minCanvasWidth = Number(options.minCanvasWidth) || 0; + var minCanvasHeight = Number(options.minCanvasHeight) || 0; + + if (viewMode > 1) { + minCanvasWidth = Math.max(minCanvasWidth, containerData.width); + minCanvasHeight = Math.max(minCanvasHeight, containerData.height); + + if (viewMode === 3) { + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } else if (viewMode > 0) { + if (minCanvasWidth) { + minCanvasWidth = Math.max(minCanvasWidth, cropped ? cropBoxData.width : 0); + } else if (minCanvasHeight) { + minCanvasHeight = Math.max(minCanvasHeight, cropped ? cropBoxData.height : 0); + } else if (cropped) { + minCanvasWidth = cropBoxData.width; + minCanvasHeight = cropBoxData.height; + + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } + + if (minCanvasWidth && minCanvasHeight) { + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasHeight = minCanvasWidth / aspectRatio; + } else { + minCanvasWidth = minCanvasHeight * aspectRatio; + } + } else if (minCanvasWidth) { + minCanvasHeight = minCanvasWidth / aspectRatio; + } else if (minCanvasHeight) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } + + canvasData.minWidth = minCanvasWidth; + canvasData.minHeight = minCanvasHeight; + canvasData.maxWidth = Infinity; + canvasData.maxHeight = Infinity; + } + + if (positionLimited) { + if (viewMode) { + var newCanvasLeft = containerData.width - canvasData.width; + var newCanvasTop = containerData.height - canvasData.height; + + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + canvasData.maxTop = Math.max(0, newCanvasTop); + + if (cropped && self.limited) { + canvasData.minLeft = Math.min(cropBoxData.left, cropBoxData.left + (cropBoxData.width - canvasData.width)); + canvasData.minTop = Math.min(cropBoxData.top, cropBoxData.top + (cropBoxData.height - canvasData.height)); + canvasData.maxLeft = cropBoxData.left; + canvasData.maxTop = cropBoxData.top; + + if (viewMode === 2) { + if (canvasData.width >= containerData.width) { + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + } + + if (canvasData.height >= containerData.height) { + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxTop = Math.max(0, newCanvasTop); + } + } + } + } else { + canvasData.minLeft = -canvasData.width; + canvasData.minTop = -canvasData.height; + canvasData.maxLeft = containerData.width; + canvasData.maxTop = containerData.height; + } + } + }, + renderCanvas: function renderCanvas(changed) { + var self = this; + var canvasData = self.canvasData; + var imageData = self.imageData; + var rotate = imageData.rotate; + + if (self.rotated) { + self.rotated = false; + + // Computes rotated sizes with image sizes + var rotatedData = getRotatedSizes({ + width: imageData.width, + height: imageData.height, + degree: rotate + }); + var aspectRatio = rotatedData.width / rotatedData.height; + var isSquareImage = imageData.aspectRatio === 1; + + if (isSquareImage || aspectRatio !== canvasData.aspectRatio) { + canvasData.left -= (rotatedData.width - canvasData.width) / 2; + canvasData.top -= (rotatedData.height - canvasData.height) / 2; + canvasData.width = rotatedData.width; + canvasData.height = rotatedData.height; + canvasData.aspectRatio = aspectRatio; + canvasData.naturalWidth = imageData.naturalWidth; + canvasData.naturalHeight = imageData.naturalHeight; + + // Computes rotated sizes with natural image sizes + if (isSquareImage && rotate % 90 || rotate % 180) { + var rotatedData2 = getRotatedSizes({ + width: imageData.naturalWidth, + height: imageData.naturalHeight, + degree: rotate + }); + + canvasData.naturalWidth = rotatedData2.width; + canvasData.naturalHeight = rotatedData2.height; + } + + self.limitCanvas(true, false); + } + } + + if (canvasData.width > canvasData.maxWidth || canvasData.width < canvasData.minWidth) { + canvasData.left = canvasData.oldLeft; + } + + if (canvasData.height > canvasData.maxHeight || canvasData.height < canvasData.minHeight) { + canvasData.top = canvasData.oldTop; + } + + canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth); + canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight); + + self.limitCanvas(false, true); + + canvasData.oldLeft = canvasData.left = Math.min(Math.max(canvasData.left, canvasData.minLeft), canvasData.maxLeft); + canvasData.oldTop = canvasData.top = Math.min(Math.max(canvasData.top, canvasData.minTop), canvasData.maxTop); + + setStyle(self.canvas, extend({ + width: canvasData.width, + height: canvasData.height + }, getTransforms({ + translateX: canvasData.left, + translateY: canvasData.top + }))); + + self.renderImage(); + + if (self.cropped && self.limited) { + self.limitCropBox(true, true); + } + + if (changed) { + self.output(); + } + }, + renderImage: function renderImage(changed) { + var self = this; + var canvasData = self.canvasData; + var imageData = self.imageData; + var newImageData = void 0; + var reversedData = void 0; + var reversedWidth = void 0; + var reversedHeight = void 0; + + if (imageData.rotate) { + reversedData = getRotatedSizes({ + width: canvasData.width, + height: canvasData.height, + degree: imageData.rotate, + aspectRatio: imageData.aspectRatio + }, true); + + reversedWidth = reversedData.width; + reversedHeight = reversedData.height; + + newImageData = { + width: reversedWidth, + height: reversedHeight, + left: (canvasData.width - reversedWidth) / 2, + top: (canvasData.height - reversedHeight) / 2 + }; + } + + extend(imageData, newImageData || { + width: canvasData.width, + height: canvasData.height, + left: 0, + top: 0 + }); + + setStyle(self.image, extend({ + width: imageData.width, + height: imageData.height + }, getTransforms(extend({ + translateX: imageData.left, + translateY: imageData.top + }, imageData)))); + + if (changed) { + self.output(); + } + }, + initCropBox: function initCropBox() { + var self = this; + var options = self.options; + var aspectRatio = options.aspectRatio; + var autoCropArea = Number(options.autoCropArea) || 0.8; + var canvasData = self.canvasData; + var cropBoxData = { + width: canvasData.width, + height: canvasData.height + }; + + if (aspectRatio) { + if (canvasData.height * aspectRatio > canvasData.width) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + self.cropBoxData = cropBoxData; + self.limitCropBox(true, true); + + // Initialize auto crop area + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + // The width/height of auto crop area must large than "minWidth/Height" + cropBoxData.width = Math.max(cropBoxData.minWidth, cropBoxData.width * autoCropArea); + cropBoxData.height = Math.max(cropBoxData.minHeight, cropBoxData.height * autoCropArea); + cropBoxData.oldLeft = cropBoxData.left = canvasData.left + (canvasData.width - cropBoxData.width) / 2; + cropBoxData.oldTop = cropBoxData.top = canvasData.top + (canvasData.height - cropBoxData.height) / 2; + + self.initialCropBoxData = extend({}, cropBoxData); + }, + limitCropBox: function limitCropBox(sizeLimited, positionLimited) { + var self = this; + var options = self.options; + var aspectRatio = options.aspectRatio; + var containerData = self.containerData; + var canvasData = self.canvasData; + var cropBoxData = self.cropBoxData; + var limited = self.limited; + + if (sizeLimited) { + var minCropBoxWidth = Number(options.minCropBoxWidth) || 0; + var minCropBoxHeight = Number(options.minCropBoxHeight) || 0; + var maxCropBoxWidth = Math.min(containerData.width, limited ? canvasData.width : containerData.width); + var maxCropBoxHeight = Math.min(containerData.height, limited ? canvasData.height : containerData.height); + + // The min/maxCropBoxWidth/Height must be less than containerWidth/Height + minCropBoxWidth = Math.min(minCropBoxWidth, containerData.width); + minCropBoxHeight = Math.min(minCropBoxHeight, containerData.height); + + if (aspectRatio) { + if (minCropBoxWidth && minCropBoxHeight) { + if (minCropBoxHeight * aspectRatio > minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + } else if (minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else if (minCropBoxHeight) { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + + if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) { + maxCropBoxHeight = maxCropBoxWidth / aspectRatio; + } else { + maxCropBoxWidth = maxCropBoxHeight * aspectRatio; + } + } + + // The minWidth/Height must be less than maxWidth/Height + cropBoxData.minWidth = Math.min(minCropBoxWidth, maxCropBoxWidth); + cropBoxData.minHeight = Math.min(minCropBoxHeight, maxCropBoxHeight); + cropBoxData.maxWidth = maxCropBoxWidth; + cropBoxData.maxHeight = maxCropBoxHeight; + } + + if (positionLimited) { + if (limited) { + cropBoxData.minLeft = Math.max(0, canvasData.left); + cropBoxData.minTop = Math.max(0, canvasData.top); + cropBoxData.maxLeft = Math.min(containerData.width, canvasData.left + canvasData.width) - cropBoxData.width; + cropBoxData.maxTop = Math.min(containerData.height, canvasData.top + canvasData.height) - cropBoxData.height; + } else { + cropBoxData.minLeft = 0; + cropBoxData.minTop = 0; + cropBoxData.maxLeft = containerData.width - cropBoxData.width; + cropBoxData.maxTop = containerData.height - cropBoxData.height; + } + } + }, + renderCropBox: function renderCropBox() { + var self = this; + var options = self.options; + var containerData = self.containerData; + var cropBoxData = self.cropBoxData; + + if (cropBoxData.width > cropBoxData.maxWidth || cropBoxData.width < cropBoxData.minWidth) { + cropBoxData.left = cropBoxData.oldLeft; + } + + if (cropBoxData.height > cropBoxData.maxHeight || cropBoxData.height < cropBoxData.minHeight) { + cropBoxData.top = cropBoxData.oldTop; + } + + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + self.limitCropBox(false, true); + + cropBoxData.oldLeft = cropBoxData.left = Math.min(Math.max(cropBoxData.left, cropBoxData.minLeft), cropBoxData.maxLeft); + cropBoxData.oldTop = cropBoxData.top = Math.min(Math.max(cropBoxData.top, cropBoxData.minTop), cropBoxData.maxTop); + + if (options.movable && options.cropBoxMovable) { + // Turn to move the canvas when the crop box is equal to the container + setData$1(self.face, 'action', cropBoxData.width === containerData.width && cropBoxData.height === containerData.height ? 'move' : 'all'); + } + + setStyle(self.cropBox, extend({ + width: cropBoxData.width, + height: cropBoxData.height + }, getTransforms({ + translateX: cropBoxData.left, + translateY: cropBoxData.top + }))); + + if (self.cropped && self.limited) { + self.limitCanvas(true, true); + } + + if (!self.disabled) { + self.output(); + } + }, + output: function output() { + var self = this; + + self.preview(); + + if (self.complete) { + dispatchEvent(self.element, 'crop', self.getData()); + } + } +}; + +var DATA_PREVIEW = 'preview'; + +var preview$1 = { + initPreview: function initPreview() { + var self = this; + var preview = self.options.preview; + var image = createElement('img'); + var crossOrigin = self.crossOrigin; + var url = crossOrigin ? self.crossOriginUrl : self.url; + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = url; + appendChild(self.viewBox, image); + self.image2 = image; + + if (!preview) { + return; + } + + var previews = preview.querySelector ? [preview] : document.querySelectorAll(preview); + + self.previews = previews; + + each(previews, function (element) { + var img = createElement('img'); + + // Save the original size for recover + setData$1(element, DATA_PREVIEW, { + width: element.offsetWidth, + height: element.offsetHeight, + html: element.innerHTML + }); + + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.src = url; + + /** + * Override img element styles + * Add `display:block` to avoid margin top issue + * Add `height:auto` to override `height` attribute on IE8 + * (Occur only when margin-top <= -height) + */ + + 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;"'; + + empty(element); + appendChild(element, img); + }); + }, + resetPreview: function resetPreview() { + each(this.previews, function (element) { + var data = getData$1(element, DATA_PREVIEW); + + setStyle(element, { + width: data.width, + height: data.height + }); + + element.innerHTML = data.html; + removeData(element, DATA_PREVIEW); + }); + }, + preview: function preview() { + var self = this; + var imageData = self.imageData; + var canvasData = self.canvasData; + var cropBoxData = self.cropBoxData; + var cropBoxWidth = cropBoxData.width; + var cropBoxHeight = cropBoxData.height; + var width = imageData.width; + var height = imageData.height; + var left = cropBoxData.left - canvasData.left - imageData.left; + var top = cropBoxData.top - canvasData.top - imageData.top; + + if (!self.cropped || self.disabled) { + return; + } + + setStyle(self.image2, extend({ + width: width, + height: height + }, getTransforms(extend({ + translateX: -left, + translateY: -top + }, imageData)))); + + each(self.previews, function (element) { + var data = getData$1(element, DATA_PREVIEW); + var originalWidth = data.width; + var originalHeight = data.height; + var newWidth = originalWidth; + var newHeight = originalHeight; + var ratio = 1; + + if (cropBoxWidth) { + ratio = originalWidth / cropBoxWidth; + newHeight = cropBoxHeight * ratio; + } + + if (cropBoxHeight && newHeight > originalHeight) { + ratio = originalHeight / cropBoxHeight; + newWidth = cropBoxWidth * ratio; + newHeight = originalHeight; + } + + setStyle(element, { + width: newWidth, + height: newHeight + }); + + setStyle(getByTag(element, 'img')[0], extend({ + width: width * ratio, + height: height * ratio + }, getTransforms(extend({ + translateX: -left * ratio, + translateY: -top * ratio + }, imageData)))); + }); + } +}; + +// Globals +var PointerEvent = typeof window !== 'undefined' ? window.PointerEvent : null; + +// Events +var EVENT_POINTER_DOWN = PointerEvent ? 'pointerdown' : 'touchstart mousedown'; +var EVENT_POINTER_MOVE = PointerEvent ? 'pointermove' : 'touchmove mousemove'; +var EVENT_POINTER_UP = PointerEvent ? ' pointerup pointercancel' : 'touchend touchcancel mouseup'; +var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll'; +var EVENT_DBLCLICK = 'dblclick'; +var EVENT_RESIZE = 'resize'; +var EVENT_CROP_START = 'cropstart'; +var EVENT_CROP_MOVE = 'cropmove'; +var EVENT_CROP_END = 'cropend'; +var EVENT_CROP$1 = 'crop'; +var EVENT_ZOOM = 'zoom'; + +var events = { + bind: function bind() { + var self = this; + var options = self.options; + var element = self.element; + var cropper = self.cropper; + + if (isFunction(options.cropstart)) { + addListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + addListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + addListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + addListener(element, EVENT_CROP$1, options.crop); + } + + if (isFunction(options.zoom)) { + addListener(element, EVENT_ZOOM, options.zoom); + } + + addListener(cropper, EVENT_POINTER_DOWN, self.onCropStart = proxy(self.cropStart, self)); + + if (options.zoomable && options.zoomOnWheel) { + addListener(cropper, EVENT_WHEEL, self.onWheel = proxy(self.wheel, self)); + } + + if (options.toggleDragModeOnDblclick) { + addListener(cropper, EVENT_DBLCLICK, self.onDblclick = proxy(self.dblclick, self)); + } + + addListener(document, EVENT_POINTER_MOVE, self.onCropMove = proxy(self.cropMove, self)); + addListener(document, EVENT_POINTER_UP, self.onCropEnd = proxy(self.cropEnd, self)); + + if (options.responsive) { + addListener(window, EVENT_RESIZE, self.onResize = proxy(self.resize, self)); + } + }, + unbind: function unbind() { + var self = this; + var options = self.options; + var element = self.element; + var cropper = self.cropper; + + if (isFunction(options.cropstart)) { + removeListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + removeListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + removeListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + removeListener(element, EVENT_CROP$1, options.crop); + } + + if (isFunction(options.zoom)) { + removeListener(element, EVENT_ZOOM, options.zoom); + } + + removeListener(cropper, EVENT_POINTER_DOWN, self.onCropStart); + + if (options.zoomable && options.zoomOnWheel) { + removeListener(cropper, EVENT_WHEEL, self.onWheel); + } + + if (options.toggleDragModeOnDblclick) { + removeListener(cropper, EVENT_DBLCLICK, self.onDblclick); + } + + removeListener(document, EVENT_POINTER_MOVE, self.onCropMove); + removeListener(document, EVENT_POINTER_UP, self.onCropEnd); + + if (options.responsive) { + removeListener(window, EVENT_RESIZE, self.onResize); + } + } +}; + +var REGEXP_ACTIONS = /^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/; + +function getPointer(_ref, endOnly) { + var pageX = _ref.pageX, + pageY = _ref.pageY; + + var end = { + endX: pageX, + endY: pageY + }; + + if (endOnly) { + return end; + } + + return extend({ + startX: pageX, + startY: pageY + }, end); +} + +var handlers = { + resize: function resize() { + var self = this; + var options = self.options; + var container = self.container; + var containerData = self.containerData; + var minContainerWidth = Number(options.minContainerWidth) || 200; + var minContainerHeight = Number(options.minContainerHeight) || 100; + + if (self.disabled || containerData.width === minContainerWidth || containerData.height === minContainerHeight) { + return; + } + + var ratio = container.offsetWidth / containerData.width; + + // Resize when width changed or height changed + if (ratio !== 1 || container.offsetHeight !== containerData.height) { + (function () { + var canvasData = void 0; + var cropBoxData = void 0; + + if (options.restore) { + canvasData = self.getCanvasData(); + cropBoxData = self.getCropBoxData(); + } + + self.render(); + + if (options.restore) { + self.setCanvasData(each(canvasData, function (n, i) { + canvasData[i] = n * ratio; + })); + self.setCropBoxData(each(cropBoxData, function (n, i) { + cropBoxData[i] = n * ratio; + })); + } + })(); + } + }, + dblclick: function dblclick() { + var self = this; + + if (self.disabled || self.options.dragMode === 'none') { + return; + } + + self.setDragMode(hasClass(self.dragBox, 'cropper-crop') ? 'move' : 'crop'); + }, + wheel: function wheel(event) { + var self = this; + var e = getEvent(event); + var ratio = Number(self.options.wheelZoomRatio) || 0.1; + var delta = 1; + + if (self.disabled) { + return; + } + + e.preventDefault(); + + // Limit wheel speed to prevent zoom too fast (#21) + if (self.wheeling) { + return; + } + + self.wheeling = true; + + setTimeout(function () { + self.wheeling = false; + }, 50); + + if (e.deltaY) { + delta = e.deltaY > 0 ? 1 : -1; + } else if (e.wheelDelta) { + delta = -e.wheelDelta / 120; + } else if (e.detail) { + delta = e.detail > 0 ? 1 : -1; + } + + self.zoom(-delta * ratio, e); + }, + cropStart: function cropStart(event) { + var self = this; + + if (self.disabled) { + return; + } + + var options = self.options; + var pointers = self.pointers; + var e = getEvent(event); + var action = void 0; + + if (e.changedTouches) { + // Handle touch event + each(e.changedTouches, function (touch) { + pointers[touch.identifier] = getPointer(touch); + }); + } else { + // Handle mouse event and pointer event + pointers[e.pointerId || 0] = getPointer(e); + } + + if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) { + action = 'zoom'; + } else { + action = getData$1(e.target, 'action'); + } + + if (!REGEXP_ACTIONS.test(action)) { + return; + } + + if (dispatchEvent(self.element, 'cropstart', { + originalEvent: e, + action: action + }) === false) { + return; + } + + e.preventDefault(); + + self.action = action; + self.cropping = false; + + if (action === 'crop') { + self.cropping = true; + addClass(self.dragBox, 'cropper-modal'); + } + }, + cropMove: function cropMove(event) { + var self = this; + var action = self.action; + + if (self.disabled || !action) { + return; + } + + var pointers = self.pointers; + var e = getEvent(event); + + e.preventDefault(); + + if (dispatchEvent(self.element, 'cropmove', { + originalEvent: e, + action: action + }) === false) { + return; + } + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + extend(pointers[touch.identifier], getPointer(touch, true)); + }); + } else { + extend(pointers[e.pointerId || 0], getPointer(e, true)); + } + + self.change(e); + }, + cropEnd: function cropEnd(event) { + var self = this; + + if (self.disabled) { + return; + } + + var action = self.action; + var pointers = self.pointers; + var e = getEvent(event); + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + delete pointers[touch.identifier]; + }); + } else { + delete pointers[e.pointerId || 0]; + } + + if (!action) { + return; + } + + e.preventDefault(); + + if (!Object.keys(pointers).length) { + self.action = ''; + } + + if (self.cropping) { + self.cropping = false; + toggleClass(self.dragBox, 'cropper-modal', self.cropped && this.options.modal); + } + + dispatchEvent(self.element, 'cropend', { + originalEvent: e, + action: action + }); + } +}; + +// Actions +var ACTION_EAST = 'e'; +var ACTION_WEST = 'w'; +var ACTION_SOUTH = 's'; +var ACTION_NORTH = 'n'; +var ACTION_SOUTH_EAST = 'se'; +var ACTION_SOUTH_WEST = 'sw'; +var ACTION_NORTH_EAST = 'ne'; +var ACTION_NORTH_WEST = 'nw'; + +function getMaxZoomRatio(pointers) { + var pointers2 = extend({}, pointers); + var ratios = []; + + each(pointers, function (pointer, pointerId) { + delete pointers2[pointerId]; + + each(pointers2, function (pointer2) { + var x1 = Math.abs(pointer.startX - pointer2.startX); + var y1 = Math.abs(pointer.startY - pointer2.startY); + var x2 = Math.abs(pointer.endX - pointer2.endX); + var y2 = Math.abs(pointer.endY - pointer2.endY); + var z1 = Math.sqrt(x1 * x1 + y1 * y1); + var z2 = Math.sqrt(x2 * x2 + y2 * y2); + var ratio = (z2 - z1) / z1; + + ratios.push(ratio); + }); + }); + + ratios.sort(function (a, b) { + return Math.abs(a) < Math.abs(b); + }); + + return ratios[0]; +} + +var change$1 = { + change: function change(e) { + var self = this; + var options = self.options; + var containerData = self.containerData; + var canvasData = self.canvasData; + var cropBoxData = self.cropBoxData; + var aspectRatio = options.aspectRatio; + var action = self.action; + var width = cropBoxData.width; + var height = cropBoxData.height; + var left = cropBoxData.left; + var top = cropBoxData.top; + var right = left + width; + var bottom = top + height; + var minLeft = 0; + var minTop = 0; + var maxWidth = containerData.width; + var maxHeight = containerData.height; + var renderable = true; + var offset = void 0; + + // Locking aspect ratio in "free mode" by holding shift key + if (!aspectRatio && e.shiftKey) { + aspectRatio = width && height ? width / height : 1; + } + + if (self.limited) { + minLeft = cropBoxData.minLeft; + minTop = cropBoxData.minTop; + maxWidth = minLeft + Math.min(containerData.width, canvasData.width, canvasData.left + canvasData.width); + maxHeight = minTop + Math.min(containerData.height, canvasData.height, canvasData.top + canvasData.height); + } + + var pointers = self.pointers; + var pointer = pointers[Object.keys(pointers)[0]]; + var range = { + x: pointer.endX - pointer.startX, + y: pointer.endY - pointer.startY + }; + + if (aspectRatio) { + range.X = range.y * aspectRatio; + range.Y = range.x / aspectRatio; + } + + switch (action) { + // Move crop box + case 'all': + left += range.x; + top += range.y; + break; + + // Resize crop box + case ACTION_EAST: + if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + width += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top -= range.Y / 2; + } + + if (width < 0) { + action = ACTION_WEST; + width = 0; + } + + break; + + case ACTION_NORTH: + if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + height -= range.y; + top += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left += range.X / 2; + } + + if (height < 0) { + action = ACTION_SOUTH; + height = 0; + } + + break; + + case ACTION_WEST: + if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + width -= range.x; + left += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top += range.Y / 2; + } + + if (width < 0) { + action = ACTION_EAST; + width = 0; + } + + break; + + case ACTION_SOUTH: + if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + height += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left -= range.X / 2; + } + + if (height < 0) { + action = ACTION_NORTH; + height = 0; + } + + break; + + case ACTION_NORTH_EAST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || right >= maxWidth)) { + renderable = false; + break; + } + + height -= range.y; + top += range.y; + width = height * aspectRatio; + } else { + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + } + + break; + + case ACTION_NORTH_WEST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || left <= minLeft)) { + renderable = false; + break; + } + + height -= range.y; + top += range.y; + width = height * aspectRatio; + left += range.X; + } else { + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_WEST: + if (aspectRatio) { + if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) { + renderable = false; + break; + } + + width -= range.x; + left += range.x; + height = width / aspectRatio; + } else { + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_EAST: + if (aspectRatio) { + if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) { + renderable = false; + break; + } + + width += range.x; + height = width / aspectRatio; + } else { + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + } + + break; + + // Move canvas + case 'move': + self.move(range.x, range.y); + renderable = false; + break; + + // Zoom canvas + case 'zoom': + self.zoom(getMaxZoomRatio(pointers), e); + renderable = false; + break; + + // Create crop box + case 'crop': + if (!range.x || !range.y) { + renderable = false; + break; + } + + offset = getOffset(self.cropper); + left = pointer.startX - offset.left; + top = pointer.startY - offset.top; + width = cropBoxData.minWidth; + height = cropBoxData.minHeight; + + if (range.x > 0) { + action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST; + } else if (range.x < 0) { + left -= width; + action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST; + } + + if (range.y < 0) { + top -= height; + } + + // Show the crop box if is hidden + if (!self.cropped) { + removeClass(self.cropBox, 'cropper-hidden'); + self.cropped = true; + + if (self.limited) { + self.limitCropBox(true, true); + } + } + + break; + + // No default + } + + if (renderable) { + cropBoxData.width = width; + cropBoxData.height = height; + cropBoxData.left = left; + cropBoxData.top = top; + self.action = action; + + self.renderCropBox(); + } + + // Override + each(pointers, function (p) { + p.startX = p.endX; + p.startY = p.endY; + }); + } +}; + +function getPointersCenter(pointers) { + var pageX = 0; + var pageY = 0; + var count = 0; + + each(pointers, function (_ref) { + var startX = _ref.startX, + startY = _ref.startY; + + pageX += startX; + pageY += startY; + count += 1; + }); + + pageX /= count; + pageY /= count; + + return { + pageX: pageX, + pageY: pageY + }; +} + +var methods = { + // Show the crop box manually + crop: function crop() { + var self = this; + + if (self.ready && !self.disabled) { + if (!self.cropped) { + self.cropped = true; + self.limitCropBox(true, true); + + if (self.options.modal) { + addClass(self.dragBox, 'cropper-modal'); + } + + removeClass(self.cropBox, 'cropper-hidden'); + } + + self.setCropBoxData(self.initialCropBoxData); + } + + return self; + }, + + + // Reset the image and crop box to their initial states + reset: function reset() { + var self = this; + + if (self.ready && !self.disabled) { + self.imageData = extend({}, self.initialImageData); + self.canvasData = extend({}, self.initialCanvasData); + self.cropBoxData = extend({}, self.initialCropBoxData); + + self.renderCanvas(); + + if (self.cropped) { + self.renderCropBox(); + } + } + + return self; + }, + + + // Clear the crop box + clear: function clear() { + var self = this; + + if (self.cropped && !self.disabled) { + extend(self.cropBoxData, { + left: 0, + top: 0, + width: 0, + height: 0 + }); + + self.cropped = false; + self.renderCropBox(); + + self.limitCanvas(); + + // Render canvas after crop box rendered + self.renderCanvas(); + + removeClass(self.dragBox, 'cropper-modal'); + addClass(self.cropBox, 'cropper-hidden'); + } + + return self; + }, + + + /** + * Replace the image's src and rebuild the cropper + * + * @param {String} url + * @param {Boolean} onlyColorChanged (optional) + */ + replace: function replace(url, onlyColorChanged) { + var self = this; + + if (!self.disabled && url) { + if (self.isImg) { + self.element.src = url; + } + + if (onlyColorChanged) { + self.url = url; + self.image.src = url; + + if (self.ready) { + self.image2.src = url; + + each(self.previews, function (element) { + getByTag(element, 'img')[0].src = url; + }); + } + } else { + if (self.isImg) { + self.replaced = true; + } + + // Clear previous data + self.options.data = null; + self.load(url); + } + } + + return self; + }, + + + // Enable (unfreeze) the cropper + enable: function enable() { + var self = this; + + if (self.ready) { + self.disabled = false; + removeClass(self.cropper, 'cropper-disabled'); + } + + return self; + }, + + + // Disable (freeze) the cropper + disable: function disable() { + var self = this; + + if (self.ready) { + self.disabled = true; + addClass(self.cropper, 'cropper-disabled'); + } + + return self; + }, + + + // Destroy the cropper and remove the instance from the image + destroy: function destroy() { + var self = this; + var element = self.element; + var image = self.image; + + if (self.loaded) { + if (self.isImg && self.replaced) { + element.src = self.originalUrl; + } + + self.unbuild(); + removeClass(element, 'cropper-hidden'); + } else if (self.isImg) { + removeListener(element, 'load', self.onStart); + } else if (image) { + removeChild(image); + } + + removeData(element, 'cropper'); + + return self; + }, + + + /** + * Move the canvas with relative offsets + * + * @param {Number} offsetX + * @param {Number} offsetY (optional) + */ + move: function move(offsetX, offsetY) { + var self = this; + var canvasData = self.canvasData; + + return self.moveTo(isUndefined(offsetX) ? offsetX : canvasData.left + Number(offsetX), isUndefined(offsetY) ? offsetY : canvasData.top + Number(offsetY)); + }, + + + /** + * Move the canvas to an absolute point + * + * @param {Number} x + * @param {Number} y (optional) + */ + moveTo: function moveTo(x, y) { + var self = this; + var canvasData = self.canvasData; + var changed = false; + + // If "y" is not present, its default value is "x" + if (isUndefined(y)) { + y = x; + } + + x = Number(x); + y = Number(y); + + if (self.ready && !self.disabled && self.options.movable) { + if (isNumber(x)) { + canvasData.left = x; + changed = true; + } + + if (isNumber(y)) { + canvasData.top = y; + changed = true; + } + + if (changed) { + self.renderCanvas(true); + } + } + + return self; + }, + + + /** + * Zoom the canvas with a relative ratio + * + * @param {Number} ratio + * @param {Event} _originalEvent (private) + */ + zoom: function zoom(ratio, _originalEvent) { + var self = this; + var canvasData = self.canvasData; + + ratio = Number(ratio); + + if (ratio < 0) { + ratio = 1 / (1 - ratio); + } else { + ratio = 1 + ratio; + } + + return self.zoomTo(canvasData.width * ratio / canvasData.naturalWidth, _originalEvent); + }, + + + /** + * Zoom the canvas to an absolute ratio + * + * @param {Number} ratio + * @param {Event} _originalEvent (private) + */ + zoomTo: function zoomTo(ratio, _originalEvent) { + var self = this; + var options = self.options; + var canvasData = self.canvasData; + var width = canvasData.width; + var height = canvasData.height; + var naturalWidth = canvasData.naturalWidth; + var naturalHeight = canvasData.naturalHeight; + + ratio = Number(ratio); + + if (ratio >= 0 && self.ready && !self.disabled && options.zoomable) { + var newWidth = naturalWidth * ratio; + var newHeight = naturalHeight * ratio; + + if (dispatchEvent(self.element, 'zoom', { + originalEvent: _originalEvent, + oldRatio: width / naturalWidth, + ratio: newWidth / naturalWidth + }) === false) { + return self; + } + + if (_originalEvent) { + var pointers = self.pointers; + var offset = getOffset(self.cropper); + var center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : { + pageX: _originalEvent.pageX, + pageY: _originalEvent.pageY + }; + + // Zoom from the triggering point of the event + canvasData.left -= (newWidth - width) * ((center.pageX - offset.left - canvasData.left) / width); + canvasData.top -= (newHeight - height) * ((center.pageY - offset.top - canvasData.top) / height); + } else { + // Zoom from the center of the canvas + canvasData.left -= (newWidth - width) / 2; + canvasData.top -= (newHeight - height) / 2; + } + + canvasData.width = newWidth; + canvasData.height = newHeight; + self.renderCanvas(true); + } + + return self; + }, + + + /** + * Rotate the canvas with a relative degree + * + * @param {Number} degree + */ + rotate: function rotate(degree) { + var self = this; + + return self.rotateTo((self.imageData.rotate || 0) + Number(degree)); + }, + + + /** + * Rotate the canvas to an absolute degree + * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate() + * + * @param {Number} degree + */ + rotateTo: function rotateTo(degree) { + var self = this; + + degree = Number(degree); + + if (isNumber(degree) && self.ready && !self.disabled && self.options.rotatable) { + self.imageData.rotate = degree % 360; + self.rotated = true; + self.renderCanvas(true); + } + + return self; + }, + + + /** + * Scale the image + * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#scale() + * + * @param {Number} scaleX + * @param {Number} scaleY (optional) + */ + scale: function scale(scaleX, scaleY) { + var self = this; + var imageData = self.imageData; + var changed = false; + + // If "scaleY" is not present, its default value is "scaleX" + if (isUndefined(scaleY)) { + scaleY = scaleX; + } + + scaleX = Number(scaleX); + scaleY = Number(scaleY); + + if (self.ready && !self.disabled && self.options.scalable) { + if (isNumber(scaleX)) { + imageData.scaleX = scaleX; + changed = true; + } + + if (isNumber(scaleY)) { + imageData.scaleY = scaleY; + changed = true; + } + + if (changed) { + self.renderImage(true); + } + } + + return self; + }, + + + /** + * Scale the abscissa of the image + * + * @param {Number} scaleX + */ + scaleX: function scaleX(_scaleX) { + var self = this; + var scaleY = self.imageData.scaleY; + + return self.scale(_scaleX, isNumber(scaleY) ? scaleY : 1); + }, + + + /** + * Scale the ordinate of the image + * + * @param {Number} scaleY + */ + scaleY: function scaleY(_scaleY) { + var self = this; + var scaleX = self.imageData.scaleX; + + return self.scale(isNumber(scaleX) ? scaleX : 1, _scaleY); + }, + + + /** + * Get the cropped area position and size data (base on the original image) + * + * @param {Boolean} rounded (optional) + * @return {Object} data + */ + getData: function getData(rounded) { + var self = this; + var options = self.options; + var imageData = self.imageData; + var canvasData = self.canvasData; + var cropBoxData = self.cropBoxData; + var ratio = void 0; + var data = void 0; + + if (self.ready && self.cropped) { + data = { + x: cropBoxData.left - canvasData.left, + y: cropBoxData.top - canvasData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + + ratio = imageData.width / imageData.naturalWidth; + + each(data, function (n, i) { + n /= ratio; + data[i] = rounded ? Math.round(n) : n; + }); + } else { + data = { + x: 0, + y: 0, + width: 0, + height: 0 + }; + } + + if (options.rotatable) { + data.rotate = imageData.rotate || 0; + } + + if (options.scalable) { + data.scaleX = imageData.scaleX || 1; + data.scaleY = imageData.scaleY || 1; + } + + return data; + }, + + + /** + * Set the cropped area position and size with new data + * + * @param {Object} data + */ + setData: function setData(data) { + var self = this; + var options = self.options; + var imageData = self.imageData; + var canvasData = self.canvasData; + var cropBoxData = {}; + var rotated = void 0; + var scaled = void 0; + var ratio = void 0; + + if (isFunction(data)) { + data = data.call(self.element); + } + + if (self.ready && !self.disabled && isPlainObject(data)) { + if (options.rotatable) { + if (isNumber(data.rotate) && data.rotate !== imageData.rotate) { + imageData.rotate = data.rotate; + self.rotated = rotated = true; + } + } + + if (options.scalable) { + if (isNumber(data.scaleX) && data.scaleX !== imageData.scaleX) { + imageData.scaleX = data.scaleX; + scaled = true; + } + + if (isNumber(data.scaleY) && data.scaleY !== imageData.scaleY) { + imageData.scaleY = data.scaleY; + scaled = true; + } + } + + if (rotated) { + self.renderCanvas(); + } else if (scaled) { + self.renderImage(); + } + + ratio = imageData.width / imageData.naturalWidth; + + if (isNumber(data.x)) { + cropBoxData.left = data.x * ratio + canvasData.left; + } + + if (isNumber(data.y)) { + cropBoxData.top = data.y * ratio + canvasData.top; + } + + if (isNumber(data.width)) { + cropBoxData.width = data.width * ratio; + } + + if (isNumber(data.height)) { + cropBoxData.height = data.height * ratio; + } + + self.setCropBoxData(cropBoxData); + } + + return self; + }, + + + /** + * Get the container size data + * + * @return {Object} data + */ + getContainerData: function getContainerData() { + var self = this; + + return self.ready ? self.containerData : {}; + }, + + + /** + * Get the image position and size data + * + * @return {Object} data + */ + getImageData: function getImageData() { + var self = this; + + return self.loaded ? self.imageData : {}; + }, + + + /** + * Get the canvas position and size data + * + * @return {Object} data + */ + getCanvasData: function getCanvasData() { + var self = this; + var canvasData = self.canvasData; + var data = {}; + + if (self.ready) { + each(['left', 'top', 'width', 'height', 'naturalWidth', 'naturalHeight'], function (n) { + data[n] = canvasData[n]; + }); + } + + return data; + }, + + + /** + * Set the canvas position and size with new data + * + * @param {Object} data + */ + setCanvasData: function setCanvasData(data) { + var self = this; + var canvasData = self.canvasData; + var aspectRatio = canvasData.aspectRatio; + + if (isFunction(data)) { + data = data.call(self.element); + } + + if (self.ready && !self.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + canvasData.left = data.left; + } + + if (isNumber(data.top)) { + canvasData.top = data.top; + } + + if (isNumber(data.width)) { + canvasData.width = data.width; + canvasData.height = data.width / aspectRatio; + } else if (isNumber(data.height)) { + canvasData.height = data.height; + canvasData.width = data.height * aspectRatio; + } + + self.renderCanvas(true); + } + + return self; + }, + + + /** + * Get the crop box position and size data + * + * @return {Object} data + */ + getCropBoxData: function getCropBoxData() { + var self = this; + var cropBoxData = self.cropBoxData; + var data = void 0; + + if (self.ready && self.cropped) { + data = { + left: cropBoxData.left, + top: cropBoxData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + } + + return data || {}; + }, + + + /** + * Set the crop box position and size with new data + * + * @param {Object} data + */ + setCropBoxData: function setCropBoxData(data) { + var self = this; + var cropBoxData = self.cropBoxData; + var aspectRatio = self.options.aspectRatio; + var widthChanged = void 0; + var heightChanged = void 0; + + if (isFunction(data)) { + data = data.call(self.element); + } + + if (self.ready && self.cropped && !self.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + cropBoxData.left = data.left; + } + + if (isNumber(data.top)) { + cropBoxData.top = data.top; + } + + if (isNumber(data.width) && data.width !== cropBoxData.width) { + widthChanged = true; + cropBoxData.width = data.width; + } + + if (isNumber(data.height) && data.height !== cropBoxData.height) { + heightChanged = true; + cropBoxData.height = data.height; + } + + if (aspectRatio) { + if (widthChanged) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else if (heightChanged) { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + self.renderCropBox(); + } + + return self; + }, + + + /** + * Get a canvas drawn the cropped image + * + * @param {Object} options (optional) + * @return {HTMLCanvasElement} canvas + */ + getCroppedCanvas: function getCroppedCanvas(options) { + var self = this; + + if (!self.ready || !window.HTMLCanvasElement) { + return null; + } + + // Return the whole canvas if not cropped + if (!self.cropped) { + return getSourceCanvas(self.image, self.imageData); + } + + if (!isPlainObject(options)) { + options = {}; + } + + var data = self.getData(); + var originalWidth = data.width; + var originalHeight = data.height; + var aspectRatio = originalWidth / originalHeight; + var scaledWidth = void 0; + var scaledHeight = void 0; + var scaledRatio = void 0; + + if (isPlainObject(options)) { + scaledWidth = options.width; + scaledHeight = options.height; + + if (scaledWidth) { + scaledHeight = scaledWidth / aspectRatio; + scaledRatio = scaledWidth / originalWidth; + } else if (scaledHeight) { + scaledWidth = scaledHeight * aspectRatio; + scaledRatio = scaledHeight / originalHeight; + } + } + + // The canvas element will use `Math.floor` on a float number, so floor first + var canvasWidth = Math.floor(scaledWidth || originalWidth); + var canvasHeight = Math.floor(scaledHeight || originalHeight); + + var canvas = createElement('canvas'); + var context = canvas.getContext('2d'); + + canvas.width = canvasWidth; + canvas.height = canvasHeight; + + if (options.fillColor) { + context.fillStyle = options.fillColor; + context.fillRect(0, 0, canvasWidth, canvasHeight); + } + + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage + var parameters = function () { + var source = getSourceCanvas(self.image, self.imageData); + var sourceWidth = source.width; + var sourceHeight = source.height; + var canvasData = self.canvasData; + var params = [source]; + + // Source canvas + var srcX = data.x + canvasData.naturalWidth * (Math.abs(data.scaleX || 1) - 1) / 2; + var srcY = data.y + canvasData.naturalHeight * (Math.abs(data.scaleY || 1) - 1) / 2; + var srcWidth = void 0; + var srcHeight = void 0; + + // Destination canvas + var dstX = void 0; + var dstY = void 0; + var dstWidth = void 0; + var dstHeight = void 0; + + if (srcX <= -originalWidth || srcX > sourceWidth) { + srcX = srcWidth = dstX = dstWidth = 0; + } else if (srcX <= 0) { + dstX = -srcX; + srcX = 0; + srcWidth = dstWidth = Math.min(sourceWidth, originalWidth + srcX); + } else if (srcX <= sourceWidth) { + dstX = 0; + srcWidth = dstWidth = Math.min(originalWidth, sourceWidth - srcX); + } + + if (srcWidth <= 0 || srcY <= -originalHeight || srcY > sourceHeight) { + srcY = srcHeight = dstY = dstHeight = 0; + } else if (srcY <= 0) { + dstY = -srcY; + srcY = 0; + srcHeight = dstHeight = Math.min(sourceHeight, originalHeight + srcY); + } else if (srcY <= sourceHeight) { + dstY = 0; + srcHeight = dstHeight = Math.min(originalHeight, sourceHeight - srcY); + } + + params.push(Math.floor(srcX), Math.floor(srcY), Math.floor(srcWidth), Math.floor(srcHeight)); + + // Scale destination sizes + if (scaledRatio) { + dstX *= scaledRatio; + dstY *= scaledRatio; + dstWidth *= scaledRatio; + dstHeight *= scaledRatio; + } + + // Avoid "IndexSizeError" in IE and Firefox + if (dstWidth > 0 && dstHeight > 0) { + params.push(Math.floor(dstX), Math.floor(dstY), Math.floor(dstWidth), Math.floor(dstHeight)); + } + + return params; + }(); + + context.drawImage.apply(context, toConsumableArray(parameters)); + + return canvas; + }, + + + /** + * Change the aspect ratio of the crop box + * + * @param {Number} aspectRatio + */ + setAspectRatio: function setAspectRatio(aspectRatio) { + var self = this; + var options = self.options; + + if (!self.disabled && !isUndefined(aspectRatio)) { + // 0 -> NaN + options.aspectRatio = Math.max(0, aspectRatio) || NaN; + + if (self.ready) { + self.initCropBox(); + + if (self.cropped) { + self.renderCropBox(); + } + } + } + + return self; + }, + + + /** + * Change the drag mode + * + * @param {String} mode (optional) + */ + setDragMode: function setDragMode(mode) { + var self = this; + var options = self.options; + var dragBox = self.dragBox; + var face = self.face; + var croppable = void 0; + var movable = void 0; + + if (self.loaded && !self.disabled) { + croppable = mode === 'crop'; + movable = options.movable && mode === 'move'; + mode = croppable || movable ? mode : 'none'; + + setData$1(dragBox, 'action', mode); + toggleClass(dragBox, 'cropper-crop', croppable); + toggleClass(dragBox, 'cropper-move', movable); + + if (!options.cropBoxMovable) { + // Sync drag mode to crop box when it is not movable + setData$1(face, 'action', mode); + toggleClass(face, 'cropper-crop', croppable); + toggleClass(face, 'cropper-move', movable); + } + } + + return self; + } +}; + +// Constants +var NAMESPACE = 'cropper'; + +// Classes +var CLASS_HIDDEN = NAMESPACE + '-hidden'; + +// Events +var EVENT_ERROR = 'error'; +var EVENT_LOAD = 'load'; +var EVENT_READY = 'ready'; +var EVENT_CROP = 'crop'; + +// RegExps +var REGEXP_DATA_URL = /^data:/; +var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg;base64,/; + +var AnotherCropper = void 0; + +var Cropper = function () { + function Cropper(element, options) { + classCallCheck(this, Cropper); + + var self = this; + + self.element = element; + self.options = extend({}, DEFAULTS, isPlainObject(options) && options); + self.loaded = false; + self.ready = false; + self.complete = false; + self.rotated = false; + self.cropped = false; + self.disabled = false; + self.replaced = false; + self.limited = false; + self.wheeling = false; + self.isImg = false; + self.originalUrl = ''; + self.canvasData = null; + self.cropBoxData = null; + self.previews = null; + self.pointers = {}; + self.init(); + } + + createClass(Cropper, [{ + key: 'init', + value: function init() { + var self = this; + var element = self.element; + var tagName = element.tagName.toLowerCase(); + var url = void 0; + + if (getData$1(element, NAMESPACE)) { + return; + } + + setData$1(element, NAMESPACE, self); + + if (tagName === 'img') { + self.isImg = true; + + // e.g.: "img/picture.jpg" + self.originalUrl = url = element.getAttribute('src'); + + // Stop when it's a blank image + if (!url) { + return; + } + + // e.g.: "http://example.com/img/picture.jpg" + url = element.src; + } else if (tagName === 'canvas' && window.HTMLCanvasElement) { + url = element.toDataURL(); + } + + self.load(url); + } + }, { + key: 'load', + value: function load(url) { + var self = this; + var options = self.options; + var element = self.element; + + if (!url) { + return; + } + + self.url = url; + self.imageData = {}; + + if (!options.checkOrientation || !window.ArrayBuffer) { + self.clone(); + return; + } + + // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari + if (REGEXP_DATA_URL.test(url)) { + if (REGEXP_DATA_URL_JPEG) { + self.read(dataURLToArrayBuffer(url)); + } else { + self.clone(); + } + return; + } + + var xhr = new XMLHttpRequest(); + + xhr.onerror = xhr.onabort = function () { + self.clone(); + }; + + xhr.onload = function () { + self.read(xhr.response); + }; + + if (options.checkCrossOrigin && isCrossOriginURL(url) && element.crossOrigin) { + url = addTimestamp(url); + } + + xhr.open('get', url); + xhr.responseType = 'arraybuffer'; + xhr.withCredentials = element.crossOrigin === 'use-credentials'; + xhr.send(); + } + }, { + key: 'read', + value: function read(arrayBuffer) { + var self = this; + var options = self.options; + var orientation = getOrientation(arrayBuffer); + var imageData = self.imageData; + var rotate = 0; + var scaleX = 1; + var scaleY = 1; + + if (orientation > 1) { + self.url = arrayBufferToDataURL(arrayBuffer); + + switch (orientation) { + + // flip horizontal + case 2: + scaleX = -1; + break; + + // rotate left 180° + case 3: + rotate = -180; + break; + + // flip vertical + case 4: + scaleY = -1; + break; + + // flip vertical + rotate right 90° + case 5: + rotate = 90; + scaleY = -1; + break; + + // rotate right 90° + case 6: + rotate = 90; + break; + + // flip horizontal + rotate right 90° + case 7: + rotate = 90; + scaleX = -1; + break; + + // rotate left 90° + case 8: + rotate = -90; + break; + } + } + + if (options.rotatable) { + imageData.rotate = rotate; + } + + if (options.scalable) { + imageData.scaleX = scaleX; + imageData.scaleY = scaleY; + } + + self.clone(); + } + }, { + key: 'clone', + value: function clone() { + var self = this; + var element = self.element; + var url = self.url; + var crossOrigin = void 0; + var crossOriginUrl = void 0; + var start = void 0; + var stop = void 0; + + if (self.options.checkCrossOrigin && isCrossOriginURL(url)) { + crossOrigin = element.crossOrigin; + + if (crossOrigin) { + crossOriginUrl = url; + } else { + crossOrigin = 'anonymous'; + + // Bust cache when there is not a "crossOrigin" property + crossOriginUrl = addTimestamp(url); + } + } + + self.crossOrigin = crossOrigin; + self.crossOriginUrl = crossOriginUrl; + + var image = createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = crossOriginUrl || url; + self.image = image; + self.onStart = start = proxy(self.start, self); + self.onStop = stop = proxy(self.stop, self); + + if (self.isImg) { + if (element.complete) { + self.start(); + } else { + addListener(element, EVENT_LOAD, start); + } + } else { + addListener(image, EVENT_LOAD, start); + addListener(image, EVENT_ERROR, stop); + addClass(image, 'cropper-hide'); + element.parentNode.insertBefore(image, element.nextSibling); + } + } + }, { + key: 'start', + value: function start(event) { + var self = this; + var image = self.isImg ? self.element : self.image; + + if (event) { + removeListener(image, EVENT_LOAD, self.onStart); + removeListener(image, EVENT_ERROR, self.onStop); + } + + getImageSize(image, function (naturalWidth, naturalHeight) { + extend(self.imageData, { + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + aspectRatio: naturalWidth / naturalHeight + }); + + self.loaded = true; + self.build(); + }); + } + }, { + key: 'stop', + value: function stop() { + var self = this; + var image = self.image; + + removeListener(image, EVENT_LOAD, self.onStart); + removeListener(image, EVENT_ERROR, self.onStop); + + removeChild(image); + self.image = null; + } + }, { + key: 'build', + value: function build() { + var self = this; + var options = self.options; + var element = self.element; + var image = self.image; + var container = void 0; + var cropper = void 0; + var canvas = void 0; + var dragBox = void 0; + var cropBox = void 0; + var face = void 0; + + if (!self.loaded) { + return; + } + + // Unbuild first when replace + if (self.ready) { + self.unbuild(); + } + + var template = createElement('div'); + template.innerHTML = TEMPLATE; + + // Create cropper elements + self.container = container = element.parentNode; + self.cropper = cropper = getByClass(template, 'cropper-container')[0]; + self.canvas = canvas = getByClass(cropper, 'cropper-canvas')[0]; + self.dragBox = dragBox = getByClass(cropper, 'cropper-drag-box')[0]; + self.cropBox = cropBox = getByClass(cropper, 'cropper-crop-box')[0]; + self.viewBox = getByClass(cropper, 'cropper-view-box')[0]; + self.face = face = getByClass(cropBox, 'cropper-face')[0]; + + appendChild(canvas, image); + + // Hide the original image + addClass(element, CLASS_HIDDEN); + + // Inserts the cropper after to the current image + container.insertBefore(cropper, element.nextSibling); + + // Show the image if is hidden + if (!self.isImg) { + removeClass(image, 'cropper-hide'); + } + + self.initPreview(); + self.bind(); + + options.aspectRatio = Math.max(0, options.aspectRatio) || NaN; + options.viewMode = Math.max(0, Math.min(3, Math.round(options.viewMode))) || 0; + + self.cropped = options.autoCrop; + + if (options.autoCrop) { + if (options.modal) { + addClass(dragBox, 'cropper-modal'); + } + } else { + addClass(cropBox, CLASS_HIDDEN); + } + + if (!options.guides) { + addClass(getByClass(cropBox, 'cropper-dashed'), CLASS_HIDDEN); + } + + if (!options.center) { + addClass(getByClass(cropBox, 'cropper-center'), CLASS_HIDDEN); + } + + if (options.background) { + addClass(cropper, 'cropper-bg'); + } + + if (!options.highlight) { + addClass(face, 'cropper-invisible'); + } + + if (options.cropBoxMovable) { + addClass(face, 'cropper-move'); + setData$1(face, 'action', 'all'); + } + + if (!options.cropBoxResizable) { + addClass(getByClass(cropBox, 'cropper-line'), CLASS_HIDDEN); + addClass(getByClass(cropBox, 'cropper-point'), CLASS_HIDDEN); + } + + self.setDragMode(options.dragMode); + self.render(); + self.ready = true; + self.setData(options.data); + + // Call the "ready" option asynchronously to keep "image.cropper" is defined + self.completing = setTimeout(function () { + if (isFunction(options.ready)) { + addListener(element, EVENT_READY, options.ready, true); + } + + dispatchEvent(element, EVENT_READY); + dispatchEvent(element, EVENT_CROP, self.getData()); + + self.complete = true; + }, 0); + } + }, { + key: 'unbuild', + value: function unbuild() { + var self = this; + + if (!self.ready) { + return; + } + + if (!self.complete) { + clearTimeout(self.completing); + } + + self.ready = false; + self.complete = false; + self.initialImageData = null; + + // Clear `initialCanvasData` is necessary when replace + self.initialCanvasData = null; + self.initialCropBoxData = null; + self.containerData = null; + self.canvasData = null; + + // Clear `cropBoxData` is necessary when replace + self.cropBoxData = null; + self.unbind(); + + self.resetPreview(); + self.previews = null; + + self.viewBox = null; + self.cropBox = null; + self.dragBox = null; + self.canvas = null; + self.container = null; + + removeChild(self.cropper); + self.cropper = null; + } + }], [{ + key: 'noConflict', + value: function noConflict() { + window.Cropper = AnotherCropper; + return Cropper; + } + }, { + key: 'setDefaults', + value: function setDefaults(options) { + extend(DEFAULTS, isPlainObject(options) && options); + } + }]); + return Cropper; +}(); + +extend(Cropper.prototype, render$1); +extend(Cropper.prototype, preview$1); +extend(Cropper.prototype, events); +extend(Cropper.prototype, handlers); +extend(Cropper.prototype, change$1); +extend(Cropper.prototype, methods); + +if (typeof window !== 'undefined') { + AnotherCropper = window.Cropper; + window.Cropper = Cropper; +} + +export default Cropper; diff --git a/dist/cropper.js b/dist/cropper.js index 005ef27d3..33ff26fb9 100644 --- a/dist/cropper.js +++ b/dist/cropper.js @@ -1,11 +1,11 @@ /*! - * Cropper.js v1.0.0-rc + * Cropper.js v1.0.0-rc.1 * https://github.com/fengyuanchen/cropperjs * * Copyright (c) 2017 Fengyuan Chen * Released under the MIT license * - * Date: 2017-03-25T12:02:21.062Z + * Date: 2017-04-30T03:26:33.550Z */ (function (global, factory) { diff --git a/dist/cropper.min.css b/dist/cropper.min.css index ca7c5c74b..c8932ee47 100644 --- a/dist/cropper.min.css +++ b/dist/cropper.min.css @@ -1,11 +1,11 @@ /*! - * Cropper.js v1.0.0-rc + * Cropper.js v1.0.0-rc.1 * https://github.com/fengyuanchen/cropperjs * * Copyright (c) 2017 Fengyuan Chen * Released under the MIT license * - * Date: 2017-03-25T12:02:21.062Z + * Date: 2017-04-30T03:26:33.550Z */ .cropper-container{font-size:0;line-height:0;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;direction:ltr;-ms-touch-action:none;touch-action:none}.cropper-container img{display:block;min-width:0!important;max-width:none!important;min-height:0!important;max-height:none!important;width:100%;height:100%;image-orientation:0deg}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{position:absolute;top:0;right:0;bottom:0;left:0}.cropper-wrap-box{overflow:hidden}.cropper-drag-box{opacity:0;background-color:#fff}.cropper-modal{opacity:.5;background-color:#000}.cropper-view-box{display:block;overflow:hidden;width:100%;height:100%;outline:1px solid #39f;outline-color:rgba(51,153,255,.75)}.cropper-dashed{position:absolute;display:block;opacity:.5;border:0 dashed #eee}.cropper-dashed.dashed-h{top:33.33333%;left:0;width:100%;height:33.33333%;border-top-width:1px;border-bottom-width:1px}.cropper-dashed.dashed-v{top:0;left:33.33333%;width:33.33333%;height:100%;border-right-width:1px;border-left-width:1px}.cropper-center{position:absolute;top:50%;left:50%;display:block;width:0;height:0;opacity:.75}.cropper-center:after,.cropper-center:before{position:absolute;display:block;content:" ";background-color:#eee}.cropper-center:before{top:0;left:-3px;width:7px;height:1px}.cropper-center:after{top:-3px;left:0;width:1px;height:7px}.cropper-face,.cropper-line,.cropper-point{position:absolute;display:block;width:100%;height:100%;opacity:.1}.cropper-face{top:0;left:0;background-color:#fff}.cropper-line{background-color:#39f}.cropper-line.line-e{top:0;right:-3px;width:5px;cursor:e-resize}.cropper-line.line-n{top:-3px;left:0;height:5px;cursor:n-resize}.cropper-line.line-w{top:0;left:-3px;width:5px;cursor:w-resize}.cropper-line.line-s{bottom:-3px;left:0;height:5px;cursor:s-resize}.cropper-point{width:5px;height:5px;opacity:.75;background-color:#39f}.cropper-point.point-e{top:50%;right:-3px;margin-top:-3px;cursor:e-resize}.cropper-point.point-n{top:-3px;left:50%;margin-left:-3px;cursor:n-resize}.cropper-point.point-w{top:50%;left:-3px;margin-top:-3px;cursor:w-resize}.cropper-point.point-s{bottom:-3px;left:50%;margin-left:-3px;cursor:s-resize}.cropper-point.point-ne{top:-3px;right:-3px;cursor:ne-resize}.cropper-point.point-nw{top:-3px;left:-3px;cursor:nw-resize}.cropper-point.point-sw{bottom:-3px;left:-3px;cursor:sw-resize}.cropper-point.point-se{right:-3px;bottom:-3px;width:20px;height:20px;cursor:se-resize;opacity:1}@media (min-width:768px){.cropper-point.point-se{width:15px;height:15px}}@media (min-width:992px){.cropper-point.point-se{width:10px;height:10px}}@media (min-width:1200px){.cropper-point.point-se{width:5px;height:5px;opacity:.75}}.cropper-point.point-se:before{position:absolute;right:-50%;bottom:-50%;display:block;width:200%;height:200%;content:" ";opacity:0;background-color:#39f}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{position:absolute;display:block;width:0;height:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed} \ No newline at end of file diff --git a/dist/cropper.min.js b/dist/cropper.min.js index 2c9f3377a..21f9b1ad5 100644 --- a/dist/cropper.min.js +++ b/dist/cropper.min.js @@ -1,11 +1,11 @@ /*! - * Cropper.js v1.0.0-rc + * Cropper.js v1.0.0-rc.1 * https://github.com/fengyuanchen/cropperjs * * Copyright (c) 2017 Fengyuan Chen * Released under the MIT license * - * Date: 2017-03-25T12:02:21.062Z + * Date: 2017-04-30T03:26:33.550Z */ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Cropper=e()}(this,function(){"use strict";function t(t){return rt.call(t).slice(8,-1).toLowerCase()}function e(t){return"number"==typeof t&&!isNaN(t)}function a(t){return"undefined"==typeof t}function i(t){return"object"===("undefined"==typeof t?"undefined":Z(t))&&null!==t}function o(t){if(!i(t))return!1;try{var e=t.constructor,a=e.prototype;return e&&a&&ht.call(a,"isPrototypeOf")}catch(t){return!1}}function n(e){return"function"===t(e)}function r(e){return Array.isArray?Array.isArray(e):"array"===t(e)}function h(t){return"string"==typeof t&&(t=t.trim?t.trim():t.replace(et,"$1")),t}function c(t,a){if(t&&n(a)){var o=void 0;if(r(t)||e(t.length)){var h=t.length;for(o=0;o1?e-1:0),o=1;o0){if(Object.assign)return Object.assign.apply(Object,[t].concat(a));a.forEach(function(e){i(e)&&Object.keys(e).forEach(function(a){t[a]=e[a]})})}return t}function d(t,e){for(var a=arguments.length,i=Array(a>2?a-2:0),o=2;o-1}function u(t,a){if(a){if(e(t.length))return void c(t,function(t){u(t,a)});if(t.classList)return void t.classList.add(a);var i=h(t.className);i?i.indexOf(a)<0&&(t.className=i+" "+a):t.className=a}}function m(t,a){if(a)return e(t.length)?void c(t,function(t){m(t,a)}):t.classList?void t.classList.remove(a):void(t.className.indexOf(a)>=0&&(t.className=t.className.replace(a,"")))}function f(t,a,i){if(a)return e(t.length)?void c(t,function(t){f(t,a,i)}):void(i?u(t,a):m(t,a))}function g(t){return t.replace(J,"$1-$2").toLowerCase()}function v(t,e){return i(t[e])?t[e]:t.dataset?t.dataset[e]:t.getAttribute("data-"+g(e))}function w(t,e,a){i(a)?t[e]=a:t.dataset?t.dataset[e]=a:t.setAttribute("data-"+g(e),a)}function b(t,e){if(i(t[e]))delete t[e];else if(t.dataset)try{delete t.dataset[e]}catch(a){t.dataset[e]=null}else t.removeAttribute("data-"+g(e))}function x(t,e,a){var i=h(e).split(_);return i.length>1?void c(i,function(e){x(t,e,a)}):void(t.removeEventListener?t.removeEventListener(e,a,!1):t.detachEvent&&t.detachEvent("on"+e,a))}function y(t,e,a,i){var o=h(e).split(_),n=a;return o.length>1?void c(o,function(e){y(t,e,a)}):(i&&(a=function(){for(var i=arguments.length,o=Array(i),r=0;r90?180-a:a)*Math.PI/180,o=Math.sin(i),n=Math.cos(i),r=t.width,h=t.height,c=t.aspectRatio,s=void 0,d=void 0;return e?(s=r/(n+o/c),d=s/c):(s=r*n+h*o,d=r*o+h*n),{width:s,height:d}}function z(t,a){var i=T("canvas"),o=i.getContext("2d"),n=0,r=0,h=a.naturalWidth,c=a.naturalHeight,s=a.rotate,d=a.scaleX,l=a.scaleY,p=e(d)&&e(l)&&(1!==d||1!==l),u=e(s)&&0!==s,m=u||p,f=h*Math.abs(d||1),g=c*Math.abs(l||1),v=void 0,w=void 0,b=void 0;return p&&(v=f/2,w=g/2),u&&(b=O({width:f,height:g,degree:s}),f=b.width,g=b.height,v=f/2,w=g/2),i.width=f,i.height=g,m&&(n=-h/2,r=-c/2,o.save(),o.translate(v,w)),u&&o.rotate(s*Math.PI/180),p&&o.scale(d,l),o.drawImage(t,Math.floor(n),Math.floor(r),Math.floor(h),Math.floor(c)),m&&o.restore(),i}function A(t,e,a){var i="",o=e;for(a+=e;o=8&&(d=n+r)))),d)for(a=e.getUint16(d,h),p=0;p
',Z="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},K=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},V=function(){function t(t,e){for(var a=0;aa.width?3===e?c=a.height*h:d=a.width/h:3===e?d=a.width/h:c=a.height*h;var l={naturalWidth:n,naturalHeight:r,aspectRatio:h,width:c,height:d};l.oldLeft=l.left=(a.width-c)/2,l.oldTop=l.top=(a.height-d)/2,t.canvasData=l,t.limited=1===e||2===e,t.limitCanvas(!0,!0),t.initialImageData=s({},i),t.initialCanvasData=s({},l)},limitCanvas:function(t,e){var a=this,i=a.options,o=i.viewMode,n=a.containerData,r=a.canvasData,h=r.aspectRatio,c=a.cropBoxData,s=a.cropped&&c;if(t){var d=Number(i.minCanvasWidth)||0,l=Number(i.minCanvasHeight)||0;o>1?(d=Math.max(d,n.width),l=Math.max(l,n.height),3===o&&(l*h>d?d=l*h:l=d/h)):o>0&&(d?d=Math.max(d,s?c.width:0):l?l=Math.max(l,s?c.height:0):s&&(d=c.width,l=c.height,l*h>d?d=l*h:l=d/h)),d&&l?l*h>d?l=d/h:d=l*h:d?l=d/h:l&&(d=l*h),r.minWidth=d,r.minHeight=l,r.maxWidth=1/0,r.maxHeight=1/0}if(e)if(o){var p=n.width-r.width,u=n.height-r.height;r.minLeft=Math.min(0,p),r.minTop=Math.min(0,u),r.maxLeft=Math.max(0,p),r.maxTop=Math.max(0,u),s&&a.limited&&(r.minLeft=Math.min(c.left,c.left+(c.width-r.width)),r.minTop=Math.min(c.top,c.top+(c.height-r.height)),r.maxLeft=c.left,r.maxTop=c.top,2===o&&(r.width>=n.width&&(r.minLeft=Math.min(0,p),r.maxLeft=Math.max(0,p)),r.height>=n.height&&(r.minTop=Math.min(0,u),r.maxTop=Math.max(0,u))))}else r.minLeft=-r.width,r.minTop=-r.height,r.maxLeft=n.width,r.maxTop=n.height},renderCanvas:function(t){var e=this,a=e.canvasData,i=e.imageData,o=i.rotate;if(e.rotated){e.rotated=!1;var n=O({width:i.width,height:i.height,degree:o}),r=n.width/n.height,h=1===i.aspectRatio;if(h||r!==a.aspectRatio){if(a.left-=(n.width-a.width)/2,a.top-=(n.height-a.height)/2,a.width=n.width,a.height=n.height,a.aspectRatio=r,a.naturalWidth=i.naturalWidth,a.naturalHeight=i.naturalHeight,h&&o%90||o%180){var c=O({width:i.naturalWidth,height:i.naturalHeight,degree:o});a.naturalWidth=c.width,a.naturalHeight=c.height}e.limitCanvas(!0,!1)}}(a.width>a.maxWidth||a.widtha.maxHeight||a.heighto.width?n.height=n.width/a:n.width=n.height*a),t.cropBoxData=n,t.limitCropBox(!0,!0),n.width=Math.min(Math.max(n.width,n.minWidth),n.maxWidth),n.height=Math.min(Math.max(n.height,n.minHeight),n.maxHeight),n.width=Math.max(n.minWidth,n.width*i),n.height=Math.max(n.minHeight,n.height*i),n.oldLeft=n.left=o.left+(o.width-n.width)/2,n.oldTop=n.top=o.top+(o.height-n.height)/2,t.initialCropBoxData=s({},n)},limitCropBox:function(t,e){var a=this,i=a.options,o=i.aspectRatio,n=a.containerData,r=a.canvasData,h=a.cropBoxData,c=a.limited;if(t){var s=Number(i.minCropBoxWidth)||0,d=Number(i.minCropBoxHeight)||0,l=Math.min(n.width,c?r.width:n.width),p=Math.min(n.height,c?r.height:n.height);s=Math.min(s,n.width),d=Math.min(d,n.height),o&&(s&&d?d*o>s?d=s/o:s=d*o:s?d=s/o:d&&(s=d*o),p*o>l?p=l/o:l=p*o),h.minWidth=Math.min(s,l),h.minHeight=Math.min(d,p),h.maxWidth=l,h.maxHeight=p}e&&(c?(h.minLeft=Math.max(0,r.left),h.minTop=Math.max(0,r.top),h.maxLeft=Math.min(n.width,r.left+r.width)-h.width,h.maxTop=Math.min(n.height,r.top+r.height)-h.height):(h.minLeft=0,h.minTop=0,h.maxLeft=n.width-h.width,h.maxTop=n.height-h.height))},renderCropBox:function(){var t=this,e=t.options,a=t.containerData,i=t.cropBoxData;(i.width>i.maxWidth||i.widthi.maxHeight||i.heightc&&(f=c/n,u=o*f,m=c),l(t,{width:u,height:m}),l(B(t,"img")[0],s({width:r*f,height:h*f},N(s({translateX:-d*f,translateY:-p*f},e))))}))}},pt="undefined"!=typeof window?window.PointerEvent:null,ut=pt?"pointerdown":"touchstart mousedown",mt=pt?"pointermove":"touchmove mousemove",ft=pt?" pointerup pointercancel":"touchend touchcancel mouseup",gt="wheel mousewheel DOMMouseScroll",vt="dblclick",wt="resize",bt="cropstart",xt="cropmove",yt="cropend",Mt="crop",Ct="zoom",Dt={bind:function(){var t=this,e=t.options,a=t.element,i=t.cropper;n(e.cropstart)&&y(a,bt,e.cropstart),n(e.cropmove)&&y(a,xt,e.cropmove),n(e.cropend)&&y(a,yt,e.cropend),n(e.crop)&&y(a,Mt,e.crop),n(e.zoom)&&y(a,Ct,e.zoom),y(i,ut,t.onCropStart=d(t.cropStart,t)),e.zoomable&&e.zoomOnWheel&&y(i,gt,t.onWheel=d(t.wheel,t)),e.toggleDragModeOnDblclick&&y(i,vt,t.onDblclick=d(t.dblclick,t)),y(document,mt,t.onCropMove=d(t.cropMove,t)),y(document,ft,t.onCropEnd=d(t.cropEnd,t)),e.responsive&&y(window,wt,t.onResize=d(t.resize,t))},unbind:function(){var t=this,e=t.options,a=t.element,i=t.cropper;n(e.cropstart)&&x(a,bt,e.cropstart),n(e.cropmove)&&x(a,xt,e.cropmove),n(e.cropend)&&x(a,yt,e.cropend),n(e.crop)&&x(a,Mt,e.crop),n(e.zoom)&&x(a,Ct,e.zoom),x(i,ut,t.onCropStart),e.zoomable&&e.zoomOnWheel&&x(i,gt,t.onWheel),e.toggleDragModeOnDblclick&&x(i,vt,t.onDblclick),x(document,mt,t.onCropMove),x(document,ft,t.onCropEnd),e.responsive&&x(window,wt,t.onResize)}},Bt=/^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/,kt={resize:function(){var t=this,e=t.options,a=t.container,i=t.containerData,o=Number(e.minContainerWidth)||200,n=Number(e.minContainerHeight)||100;if(!t.disabled&&i.width!==o&&i.height!==n){var r=a.offsetWidth/i.width;1===r&&a.offsetHeight===i.height||!function(){var a=void 0,i=void 0;e.restore&&(a=t.getCanvasData(),i=t.getCropBoxData()),t.render(),e.restore&&(t.setCanvasData(c(a,function(t,e){a[e]=t*r})),t.setCropBoxData(c(i,function(t,e){i[e]=t*r})))}()}},dblclick:function(){var t=this;t.disabled||"none"===t.options.dragMode||t.setDragMode(p(t.dragBox,"cropper-crop")?"move":"crop")},wheel:function(t){var e=this,a=C(t),i=Number(e.options.wheelZoomRatio)||.1,o=1;e.disabled||(a.preventDefault(),e.wheeling||(e.wheeling=!0,setTimeout(function(){e.wheeling=!1},50),a.deltaY?o=a.deltaY>0?1:-1:a.wheelDelta?o=-a.wheelDelta/120:a.detail&&(o=a.detail>0?1:-1),e.zoom(-o*i,a)))},cropStart:function(t){var e=this;if(!e.disabled){var a=e.options,i=e.pointers,o=C(t),n=void 0;o.changedTouches?c(o.changedTouches,function(t){i[t.identifier]=U(t)}):i[o.pointerId||0]=U(o),n=Object.keys(i).length>1&&a.zoomable&&a.zoomOnTouch?"zoom":v(o.target,"action"),Bt.test(n)&&M(e.element,"cropstart",{originalEvent:o,action:n})!==!1&&(o.preventDefault(),e.action=n,e.cropping=!1,"crop"===n&&(e.cropping=!0,u(e.dragBox,"cropper-modal")))}},cropMove:function(t){var e=this,a=e.action;if(!e.disabled&&a){var i=e.pointers,o=C(t);o.preventDefault(),M(e.element,"cropmove",{originalEvent:o,action:a})!==!1&&(o.changedTouches?c(o.changedTouches,function(t){s(i[t.identifier],U(t,!0))}):s(i[o.pointerId||0],U(o,!0)),e.change(o))}},cropEnd:function(t){var e=this;if(!e.disabled){var a=e.action,i=e.pointers,o=C(t);o.changedTouches?c(o.changedTouches,function(t){delete i[t.identifier]}):delete i[o.pointerId||0],a&&(o.preventDefault(),Object.keys(i).length||(e.action=""),e.cropping&&(e.cropping=!1,f(e.dragBox,"cropper-modal",e.cropped&&this.options.modal)),M(e.element,"cropend",{originalEvent:o,action:a}))}}},Tt="e",Lt="w",Wt="s",Xt="n",Yt="se",Et="sw",Ht="ne",Nt="nw",Ot={change:function(t){var e=this,a=e.options,i=e.containerData,o=e.canvasData,n=e.cropBoxData,r=a.aspectRatio,h=e.action,s=n.width,d=n.height,l=n.left,p=n.top,u=l+s,f=p+d,g=0,v=0,w=i.width,b=i.height,x=!0,y=void 0;!r&&t.shiftKey&&(r=s&&d?s/d:1),e.limited&&(g=n.minLeft,v=n.minTop,w=g+Math.min(i.width,o.width,o.left+o.width),b=v+Math.min(i.height,o.height,o.top+o.height));var M=e.pointers,C=M[Object.keys(M)[0]],B={x:C.endX-C.startX,y:C.endY-C.startY};switch(r&&(B.X=B.y*r,B.Y=B.x/r),h){case"all":l+=B.x,p+=B.y;break;case Tt:if(B.x>=0&&(u>=w||r&&(p<=v||f>=b))){x=!1;break}s+=B.x,r&&(d=s/r,p-=B.Y/2),s<0&&(h=Lt,s=0);break;case Xt:if(B.y<=0&&(p<=v||r&&(l<=g||u>=w))){x=!1;break}d-=B.y,p+=B.y,r&&(s=d*r,l+=B.X/2),d<0&&(h=Wt,d=0);break;case Lt:if(B.x<=0&&(l<=g||r&&(p<=v||f>=b))){x=!1;break}s-=B.x,l+=B.x,r&&(d=s/r,p+=B.Y/2),s<0&&(h=Tt,s=0);break;case Wt:if(B.y>=0&&(f>=b||r&&(l<=g||u>=w))){x=!1;break}d+=B.y,r&&(s=d*r,l-=B.X/2),d<0&&(h=Xt,d=0);break;case Ht:if(r){if(B.y<=0&&(p<=v||u>=w)){x=!1;break}d-=B.y,p+=B.y,s=d*r}else B.x>=0?uv&&(d-=B.y,p+=B.y):(d-=B.y,p+=B.y);s<0&&d<0?(h=Et,d=0,s=0):s<0?(h=Nt,s=0):d<0&&(h=Yt,d=0);break;case Nt:if(r){if(B.y<=0&&(p<=v||l<=g)){x=!1;break}d-=B.y,p+=B.y,s=d*r,l+=B.X}else B.x<=0?l>g?(s-=B.x,l+=B.x):B.y<=0&&p<=v&&(x=!1):(s-=B.x,l+=B.x),B.y<=0?p>v&&(d-=B.y,p+=B.y):(d-=B.y,p+=B.y);s<0&&d<0?(h=Yt,d=0,s=0):s<0?(h=Ht,s=0):d<0&&(h=Et,d=0);break;case Et:if(r){if(B.x<=0&&(l<=g||f>=b)){x=!1;break}s-=B.x,l+=B.x,d=s/r}else B.x<=0?l>g?(s-=B.x,l+=B.x):B.y>=0&&f>=b&&(x=!1):(s-=B.x,l+=B.x),B.y>=0?f=0&&(u>=w||f>=b)){x=!1;break}s+=B.x,d=s/r}else B.x>=0?u=0&&f>=b&&(x=!1):s+=B.x,B.y>=0?f0?h=B.y>0?Yt:Ht:B.x<0&&(l-=s,h=B.y>0?Et:Nt),B.y<0&&(p-=d),e.cropped||(m(e.cropBox,"cropper-hidden"),e.cropped=!0,e.limited&&e.limitCropBox(!0,!0))}x&&(n.width=s,n.height=d,n.left=l,n.top=p,e.action=h,e.renderCropBox()),c(M,function(t){t.startX=t.endX,t.startY=t.endY})}},zt={crop:function(){var t=this;return t.ready&&!t.disabled&&(t.cropped||(t.cropped=!0,t.limitCropBox(!0,!0),t.options.modal&&u(t.dragBox,"cropper-modal"),m(t.cropBox,"cropper-hidden")),t.setCropBoxData(t.initialCropBoxData)),t},reset:function(){var t=this;return t.ready&&!t.disabled&&(t.imageData=s({},t.initialImageData),t.canvasData=s({},t.initialCanvasData),t.cropBoxData=s({},t.initialCropBoxData),t.renderCanvas(),t.cropped&&t.renderCropBox()),t},clear:function(){var t=this;return t.cropped&&!t.disabled&&(s(t.cropBoxData,{left:0,top:0,width:0,height:0}),t.cropped=!1,t.renderCropBox(),t.limitCanvas(),t.renderCanvas(),m(t.dragBox,"cropper-modal"),u(t.cropBox,"cropper-hidden")),t},replace:function(t,e){var a=this;return!a.disabled&&t&&(a.isImg&&(a.element.src=t),e?(a.url=t,a.image.src=t,a.ready&&(a.image2.src=t,c(a.previews,function(e){B(e,"img")[0].src=t}))):(a.isImg&&(a.replaced=!0),a.options.data=null,a.load(t))),a},enable:function(){var t=this;return t.ready&&(t.disabled=!1,m(t.cropper,"cropper-disabled")),t},disable:function(){var t=this;return t.ready&&(t.disabled=!0,u(t.cropper,"cropper-disabled")),t},destroy:function(){var t=this,e=t.element,a=t.image;return t.loaded?(t.isImg&&t.replaced&&(e.src=t.originalUrl),t.unbuild(),m(e,"cropper-hidden")):t.isImg?x(e,"load",t.onStart):a&&W(a),b(e,"cropper"),t},move:function(t,e){var i=this,o=i.canvasData;return i.moveTo(a(t)?t:o.left+Number(t),a(e)?e:o.top+Number(e))},moveTo:function(t,i){var o=this,n=o.canvasData,r=!1;return a(i)&&(i=t),t=Number(t),i=Number(i),o.ready&&!o.disabled&&o.options.movable&&(e(t)&&(n.left=t,r=!0),e(i)&&(n.top=i,r=!0),r&&o.renderCanvas(!0)),o},zoom:function(t,e){var a=this,i=a.canvasData;return t=Number(t),t=t<0?1/(1-t):1+t,a.zoomTo(i.width*t/i.naturalWidth,e)},zoomTo:function(t,e){var a=this,i=a.options,o=a.canvasData,n=o.width,r=o.height,h=o.naturalWidth,c=o.naturalHeight;if(t=Number(t),t>=0&&a.ready&&!a.disabled&&i.zoomable){var s=h*t,d=c*t;if(M(a.element,"zoom",{originalEvent:e,oldRatio:n/h,ratio:s/h})===!1)return a;if(e){var l=a.pointers,p=D(a.cropper),u=l&&Object.keys(l).length?P(l):{pageX:e.pageX,pageY:e.pageY};o.left-=(s-n)*((u.pageX-p.left-o.left)/n),o.top-=(d-r)*((u.pageY-p.top-o.top)/r)}else o.left-=(s-n)/2,o.top-=(d-r)/2;o.width=s,o.height=d,a.renderCanvas(!0)}return a},rotate:function(t){var e=this;return e.rotateTo((e.imageData.rotate||0)+Number(t))},rotateTo:function(t){var a=this;return t=Number(t),e(t)&&a.ready&&!a.disabled&&a.options.rotatable&&(a.imageData.rotate=t%360,a.rotated=!0,a.renderCanvas(!0)),a},scale:function(t,i){var o=this,n=o.imageData,r=!1;return a(i)&&(i=t),t=Number(t),i=Number(i),o.ready&&!o.disabled&&o.options.scalable&&(e(t)&&(n.scaleX=t,r=!0),e(i)&&(n.scaleY=i,r=!0),r&&o.renderImage(!0)),o},scaleX:function(t){var a=this,i=a.imageData.scaleY;return a.scale(t,e(i)?i:1)},scaleY:function(t){var a=this,i=a.imageData.scaleX;return a.scale(e(i)?i:1,t)},getData:function(t){var e=this,a=e.options,i=e.imageData,o=e.canvasData,n=e.cropBoxData,r=void 0,h=void 0;return e.ready&&e.cropped?(h={x:n.left-o.left,y:n.top-o.top,width:n.width,height:n.height},r=i.width/i.naturalWidth,c(h,function(e,a){e/=r,h[a]=t?Math.round(e):e})):h={x:0,y:0,width:0,height:0},a.rotatable&&(h.rotate=i.rotate||0),a.scalable&&(h.scaleX=i.scaleX||1,h.scaleY=i.scaleY||1),h},setData:function(t){var a=this,i=a.options,r=a.imageData,h=a.canvasData,c={},s=void 0,d=void 0,l=void 0;return n(t)&&(t=t.call(a.element)),a.ready&&!a.disabled&&o(t)&&(i.rotatable&&e(t.rotate)&&t.rotate!==r.rotate&&(r.rotate=t.rotate,a.rotated=s=!0),i.scalable&&(e(t.scaleX)&&t.scaleX!==r.scaleX&&(r.scaleX=t.scaleX,d=!0),e(t.scaleY)&&t.scaleY!==r.scaleY&&(r.scaleY=t.scaleY,d=!0)),s?a.renderCanvas():d&&a.renderImage(),l=r.width/r.naturalWidth,e(t.x)&&(c.left=t.x*l+h.left),e(t.y)&&(c.top=t.y*l+h.top),e(t.width)&&(c.width=t.width*l),e(t.height)&&(c.height=t.height*l),a.setCropBoxData(c)),a},getContainerData:function(){var t=this;return t.ready?t.containerData:{}},getImageData:function(){var t=this;return t.loaded?t.imageData:{}},getCanvasData:function(){var t=this,e=t.canvasData,a={};return t.ready&&c(["left","top","width","height","naturalWidth","naturalHeight"],function(t){a[t]=e[t]}),a},setCanvasData:function(t){var a=this,i=a.canvasData,r=i.aspectRatio;return n(t)&&(t=t.call(a.element)),a.ready&&!a.disabled&&o(t)&&(e(t.left)&&(i.left=t.left),e(t.top)&&(i.top=t.top),e(t.width)?(i.width=t.width,i.height=t.width/r):e(t.height)&&(i.height=t.height,i.width=t.height*r),a.renderCanvas(!0)),a},getCropBoxData:function(){var t=this,e=t.cropBoxData,a=void 0;return t.ready&&t.cropped&&(a={left:e.left,top:e.top,width:e.width,height:e.height}),a||{}},setCropBoxData:function(t){var a=this,i=a.cropBoxData,r=a.options.aspectRatio,h=void 0,c=void 0;return n(t)&&(t=t.call(a.element)),a.ready&&a.cropped&&!a.disabled&&o(t)&&(e(t.left)&&(i.left=t.left),e(t.top)&&(i.top=t.top),e(t.width)&&t.width!==i.width&&(h=!0,i.width=t.width),e(t.height)&&t.height!==i.height&&(c=!0,i.height=t.height),r&&(h?i.height=i.width/r:c&&(i.width=i.height*r)),a.renderCropBox()),a},getCroppedCanvas:function(t){var e=this;if(!e.ready||!window.HTMLCanvasElement)return null;if(!e.cropped)return z(e.image,e.imageData);o(t)||(t={});var a=e.getData(),i=a.width,n=a.height,r=i/n,h=void 0,c=void 0,s=void 0;o(t)&&(h=t.width,c=t.height,h?(c=h/r,s=h/i):c&&(h=c*r,s=c/n));var d=Math.floor(h||i),l=Math.floor(c||n),p=T("canvas"),u=p.getContext("2d");p.width=d,p.height=l,t.fillColor&&(u.fillStyle=t.fillColor,u.fillRect(0,0,d,l));var m=function(){var t=z(e.image,e.imageData),o=t.width,r=t.height,h=e.canvasData,c=[t],d=a.x+h.naturalWidth*(Math.abs(a.scaleX||1)-1)/2,l=a.y+h.naturalHeight*(Math.abs(a.scaleY||1)-1)/2,p=void 0,u=void 0,m=void 0,f=void 0,g=void 0,v=void 0;return d<=-i||d>o?d=p=m=g=0:d<=0?(m=-d,d=0,p=g=Math.min(o,i+d)):d<=o&&(m=0,p=g=Math.min(i,o-d)),p<=0||l<=-n||l>r?l=u=f=v=0:l<=0?(f=-l,l=0,u=v=Math.min(r,n+l)):l<=r&&(f=0,u=v=Math.min(n,r-l)),c.push(Math.floor(d),Math.floor(l),Math.floor(p),Math.floor(u)),s&&(m*=s,f*=s,g*=s,v*=s),g>0&&v>0&&c.push(Math.floor(m),Math.floor(f),Math.floor(g),Math.floor(v)),c}();return u.drawImage.apply(u,F(m)),p},setAspectRatio:function(t){var e=this,i=e.options;return e.disabled||a(t)||(i.aspectRatio=Math.max(0,t)||NaN,e.ready&&(e.initCropBox(),e.cropped&&e.renderCropBox())),e},setDragMode:function(t){var e=this,a=e.options,i=e.dragBox,o=e.face,n=void 0,r=void 0;return e.loaded&&!e.disabled&&(n="crop"===t,r=a.movable&&"move"===t,t=n||r?t:"none",w(i,"action",t),f(i,"cropper-crop",n),f(i,"cropper-move",r),a.cropBoxMovable||(w(o,"action",t),f(o,"cropper-crop",n),f(o,"cropper-move",r))),e}},At="cropper",Rt=At+"-hidden",St="error",It="load",Ut="ready",jt="crop",Pt=/^data:/,qt=/^data:image\/jpeg;base64,/,$t=void 0,Zt=function(){function t(e,a){K(this,t);var i=this;i.element=e,i.options=s({},q,o(a)&&a),i.loaded=!1,i.ready=!1,i.complete=!1,i.rotated=!1,i.cropped=!1,i.disabled=!1,i.replaced=!1,i.limited=!1,i.wheeling=!1,i.isImg=!1,i.originalUrl="",i.canvasData=null,i.cropBoxData=null,i.previews=null,i.pointers={},i.init()}return V(t,[{key:"init",value:function(){var t=this,e=t.element,a=e.tagName.toLowerCase(),i=void 0;if(!v(e,At)){if(w(e,At,t),"img"===a){if(t.isImg=!0,t.originalUrl=i=e.getAttribute("src"),!i)return;i=e.src}else"canvas"===a&&window.HTMLCanvasElement&&(i=e.toDataURL());t.load(i)}}},{key:"load",value:function(t){var e=this,a=e.options,i=e.element;if(t){if(e.url=t,e.imageData={},!a.checkOrientation||!window.ArrayBuffer)return void e.clone();if(Pt.test(t))return void(qt?e.read(S(t)):e.clone());var o=new XMLHttpRequest;o.onerror=o.onabort=function(){e.clone()},o.onload=function(){e.read(o.response)},a.checkCrossOrigin&&Y(t)&&i.crossOrigin&&(t=E(t)),o.open("get",t),o.responseType="arraybuffer",o.withCredentials="use-credentials"===i.crossOrigin,o.send()}}},{key:"read",value:function(t){var e=this,a=e.options,i=R(t),o=e.imageData,n=0,r=1,h=1;if(i>1)switch(e.url=I(t),i){case 2:r=-1;break;case 3:n=-180;break;case 4:h=-1;break;case 5:n=90,h=-1;break;case 6:n=90;break;case 7:n=90,r=-1;break;case 8:n=-90}a.rotatable&&(o.rotate=n),a.scalable&&(o.scaleX=r,o.scaleY=h),e.clone()}},{key:"clone",value:function(){var t=this,e=t.element,a=t.url,i=void 0,o=void 0,n=void 0,r=void 0;t.options.checkCrossOrigin&&Y(a)&&(i=e.crossOrigin,i?o=a:(i="anonymous",o=E(a))),t.crossOrigin=i,t.crossOriginUrl=o;var h=T("img");i&&(h.crossOrigin=i),h.src=o||a,t.image=h,t.onStart=n=d(t.start,t),t.onStop=r=d(t.stop,t),t.isImg?e.complete?t.start():y(e,It,n):(y(h,It,n),y(h,St,r),u(h,"cropper-hide"),e.parentNode.insertBefore(h,e.nextSibling))}},{key:"start",value:function(t){var e=this,a=e.isImg?e.element:e.image;t&&(x(a,It,e.onStart),x(a,St,e.onStop)),H(a,function(t,a){s(e.imageData,{naturalWidth:t,naturalHeight:a,aspectRatio:t/a}),e.loaded=!0,e.build()})}},{key:"stop",value:function(){var t=this,e=t.image;x(e,It,t.onStart),x(e,St,t.onStop),W(e),t.image=null}},{key:"build",value:function(){var t=this,e=t.options,a=t.element,i=t.image,o=void 0,r=void 0,h=void 0,c=void 0,s=void 0,d=void 0;if(t.loaded){t.ready&&t.unbuild();var l=T("div");l.innerHTML=$,t.container=o=a.parentNode,t.cropper=r=k(l,"cropper-container")[0],t.canvas=h=k(r,"cropper-canvas")[0],t.dragBox=c=k(r,"cropper-drag-box")[0],t.cropBox=s=k(r,"cropper-crop-box")[0],t.viewBox=k(r,"cropper-view-box")[0],t.face=d=k(s,"cropper-face")[0],L(h,i),u(a,Rt),o.insertBefore(r,a.nextSibling),t.isImg||m(i,"cropper-hide"),t.initPreview(),t.bind(),e.aspectRatio=Math.max(0,e.aspectRatio)||NaN,e.viewMode=Math.max(0,Math.min(3,Math.round(e.viewMode)))||0,t.cropped=e.autoCrop, diff --git a/docs/css/cropper.css b/docs/css/cropper.css index edf515388..2878c950d 100644 --- a/docs/css/cropper.css +++ b/docs/css/cropper.css @@ -1,11 +1,11 @@ /*! - * Cropper.js v1.0.0-rc + * Cropper.js v1.0.0-rc.1 * https://github.com/fengyuanchen/cropperjs * * Copyright (c) 2017 Fengyuan Chen * Released under the MIT license * - * Date: 2017-03-25T12:02:21.062Z + * Date: 2017-04-30T03:26:33.550Z */ .cropper-container { diff --git a/docs/index.html b/docs/index.html index 2e9e0f3f2..c1fa988cd 100644 --- a/docs/index.html +++ b/docs/index.html @@ -41,7 +41,7 @@
-

Cropper.js v1.0.0-rc

+

Cropper.js v1.0.0-rc.1

JavaScript image cropper.

diff --git a/docs/js/cropper.js b/docs/js/cropper.js index 005ef27d3..33ff26fb9 100644 --- a/docs/js/cropper.js +++ b/docs/js/cropper.js @@ -1,11 +1,11 @@ /*! - * Cropper.js v1.0.0-rc + * Cropper.js v1.0.0-rc.1 * https://github.com/fengyuanchen/cropperjs * * Copyright (c) 2017 Fengyuan Chen * Released under the MIT license * - * Date: 2017-03-25T12:02:21.062Z + * Date: 2017-04-30T03:26:33.550Z */ (function (global, factory) { diff --git a/package.json b/package.json index b0c45e8e9..caa66100d 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,10 @@ { "name": "cropperjs", "description": "JavaScript image cropper.", - "version": "1.0.0-rc", - "main": "dist/cropper.js", + "version": "1.0.0-rc.1", + "main": "dist/cropper.common.js", + "module": "dist/cropper.esm.js", + "browser": "dist/cropper.js", "license": "MIT", "repository": "fengyuanchen/cropperjs", "homepage": "https://fengyuanchen.github.io/cropperjs", diff --git a/rollup.config.js b/rollup.config.js index 3e6ee20ef..0899fe6cc 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -6,6 +6,14 @@ module.exports = { { dest: 'dist/cropper.js', }, + { + dest: 'dist/cropper.common.js', + format: 'cjs', + }, + { + dest: 'dist/cropper.esm.js', + format: 'es', + }, { dest: 'docs/js/cropper.js', },