diff options
Diffstat (limited to 'library/cropperjs/src/js/methods.js')
-rw-r--r-- | library/cropperjs/src/js/methods.js | 156 |
1 files changed, 74 insertions, 82 deletions
diff --git a/library/cropperjs/src/js/methods.js b/library/cropperjs/src/js/methods.js index 3627d2bd1..574ac2a71 100644 --- a/library/cropperjs/src/js/methods.js +++ b/library/cropperjs/src/js/methods.js @@ -8,27 +8,23 @@ import { DRAG_MODE_CROP, DRAG_MODE_MOVE, DRAG_MODE_NONE, - EVENT_LOAD, EVENT_ZOOM, NAMESPACE, } from './constants'; import { addClass, + assign, dispatchEvent, - each, - extend, + forEach, getAdjustedSizes, getOffset, getPointersCenter, getSourceCanvas, - isFunction, isNumber, isPlainObject, isUndefined, normalizeDecimalNumber, removeClass, - removeData, - removeListener, setData, toggleClass, } from './utilities'; @@ -36,18 +32,15 @@ import { export default { // Show the crop box manually crop() { - if (this.ready && !this.disabled) { - if (!this.cropped) { - this.cropped = true; - this.limitCropBox(true, true); - - if (this.options.modal) { - addClass(this.dragBox, CLASS_MODAL); - } + if (this.ready && !this.cropped && !this.disabled) { + this.cropped = true; + this.limitCropBox(true, true); - removeClass(this.cropBox, CLASS_HIDDEN); + if (this.options.modal) { + addClass(this.dragBox, CLASS_MODAL); } + removeClass(this.cropBox, CLASS_HIDDEN); this.setCropBoxData(this.initialCropBoxData); } @@ -57,9 +50,9 @@ export default { // Reset the image and crop box to their initial states reset() { if (this.ready && !this.disabled) { - this.imageData = extend({}, this.initialImageData); - this.canvasData = extend({}, this.initialCanvasData); - this.cropBoxData = extend({}, this.initialCropBoxData); + this.imageData = assign({}, this.initialImageData); + this.canvasData = assign({}, this.initialCanvasData); + this.cropBoxData = assign({}, this.initialCropBoxData); this.renderCanvas(); if (this.cropped) { @@ -73,7 +66,7 @@ export default { // Clear the crop box clear() { if (this.cropped && !this.disabled) { - extend(this.cropBoxData, { + assign(this.cropBoxData, { left: 0, top: 0, width: 0, @@ -96,23 +89,23 @@ export default { /** * Replace the image's src and rebuild the cropper * @param {string} url - The new URL. - * @param {boolean} [onlyColorChanged] - Indicate if the new image only changed color. - * @returns {Object} this + * @param {boolean} [hasSameSize] - Indicate if the new image has the same size as the old one. + * @returns {Cropper} this */ - replace(url, onlyColorChanged = false) { + replace(url, hasSameSize = false) { if (!this.disabled && url) { if (this.isImg) { this.element.src = url; } - if (onlyColorChanged) { + if (hasSameSize) { this.url = url; this.image.src = url; if (this.ready) { - this.image2.src = url; + this.viewBoxImage.src = url; - each(this.previews, (element) => { + forEach(this.previews, (element) => { element.getElementsByTagName('img')[0].src = url; }); } @@ -121,8 +114,8 @@ export default { this.replaced = true; } - // Clear previous data this.options.data = null; + this.uncreate(); this.load(url); } } @@ -132,7 +125,7 @@ export default { // Enable (unfreeze) the cropper enable() { - if (this.ready) { + if (this.ready && this.disabled) { this.disabled = false; removeClass(this.cropper, CLASS_DISABLED); } @@ -142,7 +135,7 @@ export default { // Disable (freeze) the cropper disable() { - if (this.ready) { + if (this.ready && !this.disabled) { this.disabled = true; addClass(this.cropper, CLASS_DISABLED); } @@ -150,35 +143,34 @@ export default { return this; }, - // Destroy the cropper and remove the instance from the image + /** + * Destroy the cropper and remove the instance from the image + * @returns {Cropper} this + */ destroy() { - const { element, image } = this; - - if (this.loaded) { - if (this.isImg && this.replaced) { - element.src = this.originalUrl; - } + const { element } = this; - this.unbuild(); - removeClass(element, CLASS_HIDDEN); - } else if (this.isImg) { - removeListener(element, EVENT_LOAD, this.onStart); - } else if (image) { - image.parentNode.removeChild(image); + if (!element[NAMESPACE]) { + return this; } - removeData(element, NAMESPACE); + element[NAMESPACE] = undefined; + if (this.isImg && this.replaced) { + element.src = this.originalUrl; + } + + this.uncreate(); return this; }, /** * Move the canvas with relative offsets * @param {number} offsetX - The relative offset distance on the x-axis. - * @param {number} offsetY - The relative offset distance on the y-axis. - * @returns {Object} this + * @param {number} [offsetY=offsetX] - The relative offset distance on the y-axis. + * @returns {Cropper} this */ - move(offsetX, offsetY) { + move(offsetX, offsetY = offsetX) { const { left, top } = this.canvasData; return this.moveTo( @@ -191,7 +183,7 @@ export default { * Move the canvas to an absolute point * @param {number} x - The x-axis coordinate. * @param {number} [y=x] - The y-axis coordinate. - * @returns {Object} this + * @returns {Cropper} this */ moveTo(x, y = x) { const { canvasData } = this; @@ -223,7 +215,7 @@ export default { * Zoom the canvas with a relative ratio * @param {number} ratio - The target ratio. * @param {Event} _originalEvent - The original event if any. - * @returns {Object} this + * @returns {Cropper} this */ zoom(ratio, _originalEvent) { const { canvasData } = this; @@ -244,7 +236,7 @@ export default { * @param {number} ratio - The target ratio. * @param {Object} pivot - The zoom pivot point coordinate. * @param {Event} _originalEvent - The original event if any. - * @returns {Object} this + * @returns {Cropper} this */ zoomTo(ratio, pivot, _originalEvent) { const { options, canvasData } = this; @@ -262,9 +254,9 @@ export default { const newHeight = naturalHeight * ratio; if (dispatchEvent(this.element, EVENT_ZOOM, { - originalEvent: _originalEvent, + ratio, oldRatio: width / naturalWidth, - ratio: newWidth / naturalWidth, + originalEvent: _originalEvent, }) === false) { return this; } @@ -308,7 +300,7 @@ export default { /** * Rotate the canvas with a relative degree * @param {number} degree - The rotate degree. - * @returns {Object} this + * @returns {Cropper} this */ rotate(degree) { return this.rotateTo((this.imageData.rotate || 0) + Number(degree)); @@ -317,7 +309,7 @@ export default { /** * Rotate the canvas to an absolute degree * @param {number} degree - The rotate degree. - * @returns {Object} this + * @returns {Cropper} this */ rotateTo(degree) { degree = Number(degree); @@ -333,7 +325,7 @@ export default { /** * Scale the image on the x-axis. * @param {number} scaleX - The scale ratio on the x-axis. - * @returns {Object} this + * @returns {Cropper} this */ scaleX(scaleX) { const { scaleY } = this.imageData; @@ -344,7 +336,7 @@ export default { /** * Scale the image on the y-axis. * @param {number} scaleY - The scale ratio on the y-axis. - * @returns {Object} this + * @returns {Cropper} this */ scaleY(scaleY) { const { scaleX } = this.imageData; @@ -356,7 +348,7 @@ export default { * Scale the image * @param {number} scaleX - The scale ratio on the x-axis. * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis. - * @returns {Object} this + * @returns {Cropper} this */ scale(scaleX, scaleY = scaleX) { const { imageData } = this; @@ -408,10 +400,21 @@ export default { const ratio = imageData.width / imageData.naturalWidth; - each(data, (n, i) => { - n /= ratio; - data[i] = rounded ? Math.round(n) : n; + forEach(data, (n, i) => { + data[i] = n / ratio; }); + + if (rounded) { + // In case rounding off leads to extra 1px in right or bottom border + // we should round the top-left corner and the dimension (#343). + const bottom = Math.round(data.y + data.height); + const right = Math.round(data.x + data.width); + + data.x = Math.round(data.x); + data.y = Math.round(data.y); + data.width = right - data.x; + data.height = bottom - data.y; + } } else { data = { x: 0, @@ -436,16 +439,12 @@ export default { /** * Set the cropped area position and size with new data * @param {Object} data - The new data. - * @returns {Object} this + * @returns {Cropper} this */ setData(data) { const { options, imageData, canvasData } = this; const cropBoxData = {}; - if (isFunction(data)) { - data = data.call(this.element); - } - if (this.ready && !this.disabled && isPlainObject(data)) { let transformed = false; @@ -501,7 +500,7 @@ export default { * @returns {Object} The result container data. */ getContainerData() { - return this.ready ? extend({}, this.containerData) : {}; + return this.ready ? assign({}, this.containerData) : {}; }, /** @@ -509,7 +508,7 @@ export default { * @returns {Object} The result image data. */ getImageData() { - return this.loaded ? extend({}, this.imageData) : {}; + return this.sized ? assign({}, this.imageData) : {}; }, /** @@ -521,7 +520,7 @@ export default { const data = {}; if (this.ready) { - each([ + forEach([ 'left', 'top', 'width', @@ -539,16 +538,12 @@ export default { /** * Set the canvas position and size with new data. * @param {Object} data - The new canvas data. - * @returns {Object} this + * @returns {Cropper} this */ setCanvasData(data) { const { canvasData } = this; const { aspectRatio } = canvasData; - if (isFunction(data)) { - data = data.call(this.element); - } - if (this.ready && !this.disabled && isPlainObject(data)) { if (isNumber(data.left)) { canvasData.left = data.left; @@ -595,7 +590,7 @@ export default { /** * Set the crop box position and size with new data. * @param {Object} data - The new crop box data. - * @returns {Object} this + * @returns {Cropper} this */ setCropBoxData(data) { const { cropBoxData } = this; @@ -603,10 +598,6 @@ export default { let widthChanged; let heightChanged; - if (isFunction(data)) { - data = data.call(this.element); - } - if (this.ready && this.cropped && !this.disabled && isPlainObject(data)) { if (isNumber(data.left)) { cropBoxData.left = data.left; @@ -761,8 +752,6 @@ export default { dstHeight = srcHeight; } - // All the numerical parameters should be integer for `drawImage` - // https://github.com/fengyuanchen/cropper/issues/476 const params = [ srcX, srcY, @@ -782,7 +771,9 @@ export default { ); } - context.drawImage(source, ...params.map(param => Math.floor(normalizeDecimalNumber(param)))); + // All the numerical parameters should be integer for `drawImage` + // https://github.com/fengyuanchen/cropper/issues/476 + context.drawImage(source, ...params.map((param) => Math.floor(normalizeDecimalNumber(param)))); return canvas; }, @@ -790,7 +781,7 @@ export default { /** * Change the aspect ratio of the crop box. * @param {number} aspectRatio - The new aspect ratio. - * @returns {Object} this + * @returns {Cropper} this */ setAspectRatio(aspectRatio) { const { options } = this; @@ -814,17 +805,18 @@ export default { /** * Change the drag mode. * @param {string} mode - The new drag mode. - * @returns {Object} this + * @returns {Cropper} this */ setDragMode(mode) { const { options, dragBox, face } = this; - if (this.loaded && !this.disabled) { + if (this.ready && !this.disabled) { const croppable = mode === DRAG_MODE_CROP; const movable = options.movable && mode === DRAG_MODE_MOVE; mode = (croppable || movable) ? mode : DRAG_MODE_NONE; + options.dragMode = mode; setData(dragBox, DATA_ACTION, mode); toggleClass(dragBox, CLASS_CROP, croppable); toggleClass(dragBox, CLASS_MOVE, movable); |