aboutsummaryrefslogtreecommitdiffstats
path: root/library/cropperjs/src/js/render.js
diff options
context:
space:
mode:
Diffstat (limited to 'library/cropperjs/src/js/render.js')
-rw-r--r--library/cropperjs/src/js/render.js495
1 files changed, 495 insertions, 0 deletions
diff --git a/library/cropperjs/src/js/render.js b/library/cropperjs/src/js/render.js
new file mode 100644
index 000000000..09085ce41
--- /dev/null
+++ b/library/cropperjs/src/js/render.js
@@ -0,0 +1,495 @@
+import {
+ ACTION_ALL,
+ ACTION_MOVE,
+ CLASS_HIDDEN,
+ DATA_ACTION,
+ EVENT_CROP,
+} from './constants';
+import {
+ addClass,
+ dispatchEvent,
+ extend,
+ getAdjustedSizes,
+ getRotatedSizes,
+ getTransforms,
+ removeClass,
+ setData,
+ setStyle,
+} from './utilities';
+
+export default {
+ render() {
+ this.initContainer();
+ this.initCanvas();
+ this.initCropBox();
+ this.renderCanvas();
+
+ if (this.cropped) {
+ this.renderCropBox();
+ }
+ },
+
+ initContainer() {
+ const {
+ element,
+ options,
+ container,
+ cropper,
+ } = this;
+
+ addClass(cropper, CLASS_HIDDEN);
+ removeClass(element, CLASS_HIDDEN);
+
+ const containerData = {
+ width: Math.max(
+ container.offsetWidth,
+ Number(options.minContainerWidth) || 200,
+ ),
+ height: Math.max(
+ container.offsetHeight,
+ Number(options.minContainerHeight) || 100,
+ ),
+ };
+
+ this.containerData = containerData;
+
+ setStyle(cropper, {
+ width: containerData.width,
+ height: containerData.height,
+ });
+
+ addClass(element, CLASS_HIDDEN);
+ removeClass(cropper, CLASS_HIDDEN);
+ },
+
+ // Canvas (image wrapper)
+ initCanvas() {
+ const { containerData, imageData } = this;
+ const { viewMode } = this.options;
+ const rotated = Math.abs(imageData.rotate) % 180 === 90;
+ const naturalWidth = rotated ? imageData.naturalHeight : imageData.naturalWidth;
+ const naturalHeight = rotated ? imageData.naturalWidth : imageData.naturalHeight;
+ const aspectRatio = naturalWidth / naturalHeight;
+ let canvasWidth = containerData.width;
+ let 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;
+ }
+
+ const canvasData = {
+ aspectRatio,
+ naturalWidth,
+ naturalHeight,
+ width: canvasWidth,
+ height: canvasHeight,
+ };
+
+ canvasData.left = (containerData.width - canvasWidth) / 2;
+ canvasData.top = (containerData.height - canvasHeight) / 2;
+ canvasData.oldLeft = canvasData.left;
+ canvasData.oldTop = canvasData.top;
+
+ this.canvasData = canvasData;
+ this.limited = (viewMode === 1 || viewMode === 2);
+ this.limitCanvas(true, true);
+ this.initialImageData = extend({}, imageData);
+ this.initialCanvasData = extend({}, canvasData);
+ },
+
+ limitCanvas(sizeLimited, positionLimited) {
+ const {
+ options,
+ containerData,
+ canvasData,
+ cropBoxData,
+ } = this;
+ const { viewMode } = options;
+ const { aspectRatio } = canvasData;
+ const cropped = this.cropped && cropBoxData;
+
+ if (sizeLimited) {
+ let minCanvasWidth = Number(options.minCanvasWidth) || 0;
+ let 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;
+ }
+ }
+ }
+
+ ({ width: minCanvasWidth, height: minCanvasHeight } = getAdjustedSizes({
+ aspectRatio,
+ width: minCanvasWidth,
+ height: minCanvasHeight,
+ }, 'cover'));
+
+ canvasData.minWidth = minCanvasWidth;
+ canvasData.minHeight = minCanvasHeight;
+ canvasData.maxWidth = Infinity;
+ canvasData.maxHeight = Infinity;
+ }
+
+ if (positionLimited) {
+ if (viewMode) {
+ const newCanvasLeft = containerData.width - canvasData.width;
+ const 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 && this.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(changed, transformed) {
+ const { canvasData, imageData } = this;
+
+ if (transformed) {
+ const { width: naturalWidth, height: naturalHeight } = getRotatedSizes({
+ width: imageData.naturalWidth * Math.abs(imageData.scaleX || 1),
+ height: imageData.naturalHeight * Math.abs(imageData.scaleY || 1),
+ degree: imageData.rotate || 0,
+ });
+ const width = canvasData.width * (naturalWidth / canvasData.naturalWidth);
+ const height = canvasData.height * (naturalHeight / canvasData.naturalHeight);
+
+ canvasData.left -= (width - canvasData.width) / 2;
+ canvasData.top -= (height - canvasData.height) / 2;
+ canvasData.width = width;
+ canvasData.height = height;
+ canvasData.aspectRatio = naturalWidth / naturalHeight;
+ canvasData.naturalWidth = naturalWidth;
+ canvasData.naturalHeight = naturalHeight;
+ this.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,
+ );
+
+ this.limitCanvas(false, true);
+
+ canvasData.left = Math.min(
+ Math.max(canvasData.left, canvasData.minLeft),
+ canvasData.maxLeft,
+ );
+ canvasData.top = Math.min(
+ Math.max(canvasData.top, canvasData.minTop),
+ canvasData.maxTop,
+ );
+ canvasData.oldLeft = canvasData.left;
+ canvasData.oldTop = canvasData.top;
+
+ setStyle(this.canvas, extend({
+ width: canvasData.width,
+ height: canvasData.height,
+ }, getTransforms({
+ translateX: canvasData.left,
+ translateY: canvasData.top,
+ })));
+
+ this.renderImage(changed);
+
+ if (this.cropped && this.limited) {
+ this.limitCropBox(true, true);
+ }
+ },
+
+ renderImage(changed) {
+ const { canvasData, imageData } = this;
+ const width = imageData.naturalWidth * (canvasData.width / canvasData.naturalWidth);
+ const height = imageData.naturalHeight * (canvasData.height / canvasData.naturalHeight);
+
+ extend(imageData, {
+ width,
+ height,
+ left: (canvasData.width - width) / 2,
+ top: (canvasData.height - height) / 2,
+ });
+ setStyle(this.image, extend({
+ width: imageData.width,
+ height: imageData.height,
+ }, getTransforms(extend({
+ translateX: imageData.left,
+ translateY: imageData.top,
+ }, imageData))));
+
+ if (changed) {
+ this.output();
+ }
+ },
+
+ initCropBox() {
+ const { options, canvasData } = this;
+ const { aspectRatio } = options;
+ const autoCropArea = Number(options.autoCropArea) || 0.8;
+ const 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;
+ }
+ }
+
+ this.cropBoxData = cropBoxData;
+ this.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.left = (
+ canvasData.left + ((canvasData.width - cropBoxData.width) / 2)
+ );
+ cropBoxData.top = (
+ canvasData.top + ((canvasData.height - cropBoxData.height) / 2)
+ );
+ cropBoxData.oldLeft = cropBoxData.left;
+ cropBoxData.oldTop = cropBoxData.top;
+
+ this.initialCropBoxData = extend({}, cropBoxData);
+ },
+
+ limitCropBox(sizeLimited, positionLimited) {
+ const {
+ options,
+ containerData,
+ canvasData,
+ cropBoxData,
+ limited,
+ } = this;
+ const { aspectRatio } = options;
+
+ if (sizeLimited) {
+ let minCropBoxWidth = Number(options.minCropBoxWidth) || 0;
+ let minCropBoxHeight = Number(options.minCropBoxHeight) || 0;
+ let maxCropBoxWidth = Math.min(
+ containerData.width,
+ limited ? canvasData.width : containerData.width,
+ );
+ let maxCropBoxHeight = Math.min(
+ containerData.height,
+ limited ? canvasData.height : containerData.height,
+ );
+
+ // The min/maxCropBoxWidth/Height must be less than container's width/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() {
+ const { options, containerData, cropBoxData } = this;
+
+ 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,
+ );
+
+ this.limitCropBox(false, true);
+
+ cropBoxData.left = Math.min(
+ Math.max(cropBoxData.left, cropBoxData.minLeft),
+ cropBoxData.maxLeft,
+ );
+ cropBoxData.top = Math.min(
+ Math.max(cropBoxData.top, cropBoxData.minTop),
+ cropBoxData.maxTop,
+ );
+ cropBoxData.oldLeft = cropBoxData.left;
+ cropBoxData.oldTop = cropBoxData.top;
+
+ if (options.movable && options.cropBoxMovable) {
+ // Turn to move the canvas when the crop box is equal to the container
+ setData(this.face, DATA_ACTION, cropBoxData.width >= containerData.width &&
+ cropBoxData.height >= containerData.height ? ACTION_MOVE : ACTION_ALL);
+ }
+
+ setStyle(this.cropBox, extend({
+ width: cropBoxData.width,
+ height: cropBoxData.height,
+ }, getTransforms({
+ translateX: cropBoxData.left,
+ translateY: cropBoxData.top,
+ })));
+
+ if (this.cropped && this.limited) {
+ this.limitCanvas(true, true);
+ }
+
+ if (!this.disabled) {
+ this.output();
+ }
+ },
+
+ output() {
+ this.preview();
+
+ if (this.complete) {
+ dispatchEvent(this.element, EVENT_CROP, this.getData());
+ }
+ },
+};