UNPKG

@wiajs/ui

Version:

wia app ui packages

311 lines (310 loc) 15.3 kB
import { ACTION_ALL, ACTION_MOVE, CLASS_HIDDEN, DATA_ACTION, EVENT_CROP } from './constant'; import { getSize, getTransforms } from './util'; export default { render () { this.initContainer(); this.initCanvas(); this.initCropBox(); this.renderCanvas(); if (this.cropped) { this.renderCropBox(); } }, initContainer () { const { img, opt, container, cropper } = this; cropper.addClass(CLASS_HIDDEN); // 恢复原图,获得原图显示情况下,容器的高度、宽度 $(img).removeClass(CLASS_HIDDEN); const containerData = { width: Math.max(container.offsetWidth, Number(opt.minContainerWidth) || 200), height: Math.max(container.offsetHeight, Number(opt.minContainerHeight) || 100) }; this.containerData = containerData; cropper.css({ width: containerData.width, height: containerData.height }); $(img).addClass(CLASS_HIDDEN); cropper.removeClass(CLASS_HIDDEN); }, // Canvas (image wrapper) initCanvas () { const { containerData, imageData } = this; const { viewMode } = this.opt; 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 }; this.canvasData = canvasData; this.limited = viewMode === 1 || viewMode === 2; this.limitCanvas(true, true); canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth); canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight); canvasData.left = (containerData.width - canvasData.width) / 2; canvasData.top = (containerData.height - canvasData.height) / 2; canvasData.oldLeft = canvasData.left; canvasData.oldTop = canvasData.top; this.initialCanvasData = $.assign({}, canvasData); }, limitCanvas (sizeLimited, positionLimited) { const { opt, containerData, canvasData, cropBoxData } = this; const { viewMode } = opt; const { aspectRatio } = canvasData; const cropped = this.cropped && cropBoxData; if (sizeLimited) { let minCanvasWidth = Number(opt.minCanvasWidth) || 0; let minCanvasHeight = Number(opt.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 } = getSize({ aspect: aspectRatio, width: minCanvasWidth, height: minCanvasHeight })); canvasData.minWidth = minCanvasWidth; canvasData.minHeight = minCanvasHeight; canvasData.maxWidth = Infinity; canvasData.maxHeight = Infinity; } if (positionLimited) { if (viewMode > (cropped ? 0 : 1)) { 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) { const { canvasData, imageData } = this; 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; $(this.canvas).css($.assign({ 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); $.assign(imageData, { width, height, left: (canvasData.width - width) / 2, top: (canvasData.height - height) / 2 }); $(this.image).css($.assign({ width: imageData.width, height: imageData.height }, getTransforms($.assign({ translateX: imageData.left, translateY: imageData.top }, imageData)))); if (changed) { this.output(); } }, initCropBox () { const { opt, canvasData } = this; const aspectRatio = opt.aspectRatio || opt.initialAspectRatio; const autoCropArea = Number(opt.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 = $.assign({}, cropBoxData); }, limitCropBox (sizeLimited, positionLimited) { const { opt, containerData, canvasData, cropBoxData, limited } = this; const { aspectRatio } = opt; if (sizeLimited) { let minCropBoxWidth = Number(opt.minCropBoxWidth) || 0; let minCropBoxHeight = Number(opt.minCropBoxHeight) || 0; let maxCropBoxWidth = limited ? Math.min(containerData.width, canvasData.width, canvasData.width + canvasData.left, containerData.width - canvasData.left) : containerData.width; let maxCropBoxHeight = limited ? Math.min(containerData.height, canvasData.height, canvasData.height + canvasData.top, containerData.height - canvasData.top) : containerData.height; // The min/maxCropBoxWidth/Height must be less than container's width/height 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 { opt, 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 (opt.movable && opt.cropBoxMovable) { // Turn to move the canvas when the crop box is equal to the container this.face.data(DATA_ACTION, cropBoxData.width >= containerData.width && cropBoxData.height >= containerData.height ? ACTION_MOVE : ACTION_ALL); } this.cropBox.css($.assign({ 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(); // 触发组件事件 this.emit(`local::${EVENT_CROP} cropper${EVENT_CROP}`, this.el, this.getData()); // dispatchEvent(this.element, EVENT_CROP, this.getData()); } };