$.extend(prototype, { render: function () { this.initContainer(); this.initCanvas(); this.initCropBox(); this.renderCanvas(); if (this.cropped) { this.renderCropBox(); } }, initContainer: function () { var options = this.options; var $this = this.$element; var $container = this.$container; var $cropper = this.$cropper; $cropper.addClass(CLASS_HIDDEN); $this.removeClass(CLASS_HIDDEN); $cropper.css((this.container = { width: max($container.width(), num(options.minContainerWidth) || 200), height: max($container.height(), num(options.minContainerHeight) || 100) })); $this.addClass(CLASS_HIDDEN); $cropper.removeClass(CLASS_HIDDEN); }, // Canvas (image wrapper) initCanvas: function () { var container = this.container; var containerWidth = container.width; var containerHeight = container.height; var image = this.image; var aspectRatio = image.aspectRatio; var canvas = { aspectRatio: aspectRatio, width: containerWidth, height: containerHeight }; if (containerHeight * aspectRatio > containerWidth) { canvas.height = containerWidth / aspectRatio; } else { canvas.width = containerHeight * aspectRatio; } canvas.oldLeft = canvas.left = (containerWidth - canvas.width) / 2; canvas.oldTop = canvas.top = (containerHeight - canvas.height) / 2; this.canvas = canvas; this.limitCanvas(true, true); this.initialImage = $.extend({}, image); this.initialCanvas = $.extend({}, canvas); }, limitCanvas: function (size, position) { var options = this.options; var strict = options.strict; var container = this.container; var containerWidth = container.width; var containerHeight = container.height; var canvas = this.canvas; var aspectRatio = canvas.aspectRatio; var cropBox = this.cropBox; var cropped = this.cropped && cropBox; var initialCanvas = this.initialCanvas || canvas; var minCanvasWidth; var minCanvasHeight; if (size) { minCanvasWidth = num(options.minCanvasWidth) || 0; minCanvasHeight = num(options.minCanvasHeight) || 0; if (strict) { if (minCanvasWidth) { minCanvasWidth = max(minCanvasWidth, cropped ? cropBox.width : initialCanvas.width); } else if (minCanvasHeight) { minCanvasHeight = max(minCanvasHeight, cropped ? cropBox.height : initialCanvas.height); } else if (cropped) { minCanvasWidth = cropBox.width; minCanvasHeight = cropBox.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; } canvas.minWidth = minCanvasWidth; canvas.minHeight = minCanvasHeight; canvas.maxWidth = Infinity; canvas.maxHeight = Infinity; } if (position) { if (strict) { canvas.minLeft = cropped ? min(cropBox.left, (cropBox.left + cropBox.width) - canvas.width) : min(0, containerWidth - canvas.width); canvas.minTop = cropped ? min(cropBox.top, (cropBox.top + cropBox.height) - canvas.height) : min(0, containerHeight - canvas.height); canvas.maxLeft = cropped ? cropBox.left : max(0, containerWidth - canvas.width); canvas.maxTop = cropped ? cropBox.top : max(0, containerHeight - canvas.height); } else { canvas.minLeft = -canvas.width; canvas.minTop = -canvas.height; canvas.maxLeft = containerWidth; canvas.maxTop = containerHeight; } } }, renderCanvas: function (changed) { var options = this.options; var canvas = this.canvas; var image = this.image; var aspectRatio; var rotated; if (this.rotated) { this.rotated = false; // Computes rotated sizes with image sizes rotated = getRotatedSizes({ width: image.width, height: image.height, degree: image.rotate }); aspectRatio = rotated.width / rotated.height; if (aspectRatio !== canvas.aspectRatio) { canvas.left -= (rotated.width - canvas.width) / 2; canvas.top -= (rotated.height - canvas.height) / 2; canvas.width = rotated.width; canvas.height = rotated.height; canvas.aspectRatio = aspectRatio; this.limitCanvas(true, false); } } if (canvas.width > canvas.maxWidth || canvas.width < canvas.minWidth) { canvas.left = canvas.oldLeft; } if (canvas.height > canvas.maxHeight || canvas.height < canvas.minHeight) { canvas.top = canvas.oldTop; } canvas.width = min(max(canvas.width, canvas.minWidth), canvas.maxWidth); canvas.height = min(max(canvas.height, canvas.minHeight), canvas.maxHeight); this.limitCanvas(false, true); canvas.oldLeft = canvas.left = min(max(canvas.left, canvas.minLeft), canvas.maxLeft); canvas.oldTop = canvas.top = min(max(canvas.top, canvas.minTop), canvas.maxTop); this.$canvas.css({ width: canvas.width, height: canvas.height, left: canvas.left, top: canvas.top }); this.renderImage(); if (this.cropped && options.strict) { this.limitCropBox(true, true); } if (changed) { this.output(); } }, renderImage: function (changed) { var canvas = this.canvas; var image = this.image; var reversed; if (image.rotate) { reversed = getRotatedSizes({ width: canvas.width, height: canvas.height, degree: image.rotate, aspectRatio: image.aspectRatio }, true); } $.extend(image, reversed ? { width: reversed.width, height: reversed.height, left: (canvas.width - reversed.width) / 2, top: (canvas.height - reversed.height) / 2 } : { width: canvas.width, height: canvas.height, left: 0, top: 0 }); this.$clone.css({ width: image.width, height: image.height, marginLeft: image.left, marginTop: image.top, transform: getTransform(image) }); if (changed) { this.output(); } }, initCropBox: function () { var options = this.options; var canvas = this.canvas; var aspectRatio = options.aspectRatio; var autoCropArea = num(options.autoCropArea) || 0.8; var cropBox = { width: canvas.width, height: canvas.height }; if (aspectRatio) { if (canvas.height * aspectRatio > canvas.width) { cropBox.height = cropBox.width / aspectRatio; } else { cropBox.width = cropBox.height * aspectRatio; } } this.cropBox = cropBox; this.limitCropBox(true, true); // Initialize auto crop area cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth); cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight); // The width of auto crop area must large than "minWidth", and the height too. (#164) cropBox.width = max(cropBox.minWidth, cropBox.width * autoCropArea); cropBox.height = max(cropBox.minHeight, cropBox.height * autoCropArea); cropBox.oldLeft = cropBox.left = canvas.left + (canvas.width - cropBox.width) / 2; cropBox.oldTop = cropBox.top = canvas.top + (canvas.height - cropBox.height) / 2; this.initialCropBox = $.extend({}, cropBox); }, limitCropBox: function (size, position) { var options = this.options; var strict = options.strict; var container = this.container; var containerWidth = container.width; var containerHeight = container.height; var canvas = this.canvas; var cropBox = this.cropBox; var aspectRatio = options.aspectRatio; var minCropBoxWidth; var minCropBoxHeight; var maxCropBoxWidth; var maxCropBoxHeight; if (size) { minCropBoxWidth = num(options.minCropBoxWidth) || 0; minCropBoxHeight = num(options.minCropBoxHeight) || 0; // The min/maxCropBoxWidth/Height must be less than containerWidth/Height minCropBoxWidth = min(minCropBoxWidth, containerWidth); minCropBoxHeight = min(minCropBoxHeight, containerHeight); maxCropBoxWidth = min(containerWidth, strict ? canvas.width : containerWidth); maxCropBoxHeight = min(containerHeight, strict ? canvas.height : containerHeight); 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 cropBox.minWidth = min(minCropBoxWidth, maxCropBoxWidth); cropBox.minHeight = min(minCropBoxHeight, maxCropBoxHeight); cropBox.maxWidth = maxCropBoxWidth; cropBox.maxHeight = maxCropBoxHeight; } if (position) { if (strict) { cropBox.minLeft = max(0, canvas.left); cropBox.minTop = max(0, canvas.top); cropBox.maxLeft = min(containerWidth, canvas.left + canvas.width) - cropBox.width; cropBox.maxTop = min(containerHeight, canvas.top + canvas.height) - cropBox.height; } else { cropBox.minLeft = 0; cropBox.minTop = 0; cropBox.maxLeft = containerWidth - cropBox.width; cropBox.maxTop = containerHeight - cropBox.height; } } }, renderCropBox: function () { var options = this.options; var container = this.container; var containerWidth = container.width; var containerHeight = container.height; var cropBox = this.cropBox; if (cropBox.width > cropBox.maxWidth || cropBox.width < cropBox.minWidth) { cropBox.left = cropBox.oldLeft; } if (cropBox.height > cropBox.maxHeight || cropBox.height < cropBox.minHeight) { cropBox.top = cropBox.oldTop; } cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth); cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight); this.limitCropBox(false, true); cropBox.oldLeft = cropBox.left = min(max(cropBox.left, cropBox.minLeft), cropBox.maxLeft); cropBox.oldTop = cropBox.top = min(max(cropBox.top, cropBox.minTop), cropBox.maxTop); if (options.movable && options.cropBoxMovable) { // Turn to move the canvas when the crop box is equal to the container this.$face.data(DATA_ACTION, (cropBox.width === containerWidth && cropBox.height === containerHeight) ? ACTION_MOVE : ACTION_ALL); } this.$cropBox.css({ width: cropBox.width, height: cropBox.height, left: cropBox.left, top: cropBox.top }); if (this.cropped && options.strict) { this.limitCanvas(true, true); } if (!this.disabled) { this.output(); } }, output: function () { this.preview(); if (this.complete) { this.trigger(EVENT_CROP, this.getData()); } else if (!this.built) { // Only trigger one crop event before complete this.$element.one(EVENT_BUILT, $.proxy(function () { this.trigger(EVENT_CROP, this.getData()); }, this)); } } });