choerodon-ui
Version:
An enterprise-class UI design language and React-based implementation
576 lines (500 loc) • 19.3 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _objectSpread from "@babel/runtime/helpers/objectSpread2";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
var _excluded = ["beforeUpload", "accept"];
import _regeneratorRuntime from "@babel/runtime/regenerator";
import React, { forwardRef, useCallback, useContext, useRef, useState } from 'react';
import Cropper from 'react-easy-crop';
import isFunction from 'lodash/isFunction';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import Modal from '../modal';
import defaultLocale from '../locale-provider/default';
import Button from '../button';
import ButtonGroup from '../button/ButtonGroup';
import Upload from '../upload';
import AvatarUploader from './avatarUpload';
import { ShapeCroper } from './enum';
import ConfigContext from '../config-provider/ConfigContext'; // ssr
if (typeof window !== 'undefined') {
// 兼容ie11 remove 方法
(function (arr) {
arr.forEach(function (item) {
// eslint-disable-next-line no-prototype-builtins
if (item.hasOwnProperty('remove')) {
return;
}
Object.defineProperty(item, 'remove', {
configurable: true,
enumerable: true,
writable: true,
value: function remove() {
if (this.parentNode === null) {
return;
}
this.parentNode.removeChild(this);
}
});
}); // 兼容IE
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
value: function value(callback, type, quality) {
var _this = this;
setTimeout(function () {
var binStr = atob(_this.toDataURL(type, quality).split(',')[1]);
var len = binStr.length;
var arrArray = new Uint8Array(len);
for (var i = 0; i < len; i++) {
arrArray[i] = binStr.charCodeAt(i);
}
callback(new Blob([arrArray], {
type: type || 'image/png'
}));
});
}
});
}
})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
}
var MIN_ZOOM = 1;
var MAX_ZOOM = 3;
var ZOOM_STEP = 0.1;
export { ShapeCroper };
var EasyCrop = /*#__PURE__*/forwardRef(function (props, ref) {
var src = props.src,
aspect = props.aspect,
shape = props.shape,
grid = props.grid,
hasZoom = props.hasZoom,
zoomVal = props.zoomVal,
rotateVal = props.rotateVal,
setZoomVal = props.setZoomVal,
setRotateVal = props.setRotateVal,
onComplete = props.onComplete,
prefixCls = props.prefixCls;
var _useState = useState({
x: 0,
y: 0
}),
_useState2 = _slicedToArray(_useState, 2),
crop = _useState2[0],
setCrop = _useState2[1];
var onCropComplete = useCallback(function (_croppedArea, croppedAreaPixels) {
croppedAreaPixels.zoom = zoomVal || 0;
croppedAreaPixels.rotate = rotateVal || 0;
onComplete(croppedAreaPixels);
}, [onComplete, zoomVal, rotateVal]);
return /*#__PURE__*/React.createElement(Cropper, {
ref: ref,
image: src,
aspect: aspect,
cropShape: shape,
showGrid: grid,
zoomWithScroll: hasZoom,
crop: crop,
zoom: zoomVal,
rotation: rotateVal,
onCropChange: setCrop,
onZoomChange: setZoomVal,
onRotationChange: setRotateVal,
onCropComplete: onCropComplete,
classes: {
containerClassName: "".concat(prefixCls, "-container"),
mediaClassName: "".concat(prefixCls, "-media")
}
});
}); // 图片转化为canvas
var imageToCanvas = function imageToCanvas(image) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
if (ctx) {
ctx.drawImage(image, 0, 0);
return canvas;
}
return undefined;
};
var ImgCrop = /*#__PURE__*/forwardRef(function ImgCrop(props, ref) {
var aspect = props.aspect,
shape = props.shape,
grid = props.grid,
zoom = props.zoom,
rotate = props.rotate,
_props$rotateStep = props.rotateStep,
rotateStep = _props$rotateStep === void 0 ? 90 : _props$rotateStep,
beforeCrop = props.beforeCrop,
modalTitle = props.modalTitle,
modalWidth = props.modalWidth,
modalOk = props.modalOk,
modalCancel = props.modalCancel,
modalVisible = props.modalVisible,
children = props.children,
onModalCancel = props.onCancel,
onModalOk = props.onOk,
imageSrc = props.src,
serverCrop = props.serverCrop,
modalProps = props.modalProps,
cropContent = props.cropContent,
onCropComplete = props.onCropComplete,
customizePrefixCls = props.prefixCls;
var _useContext = useContext(ConfigContext),
getPrefixCls = _useContext.getPrefixCls;
var prefixCls = getPrefixCls('image-crop', customizePrefixCls);
var prefixClsMedia = "".concat(prefixCls, "-media");
var hasZoom = zoom === true;
var hasRotate = rotate === true;
var _useState3 = useState(''),
_useState4 = _slicedToArray(_useState3, 2),
src = _useState4[0],
setSrc = _useState4[1];
var _useState5 = useState(1),
_useState6 = _slicedToArray(_useState5, 2),
zoomVal = _useState6[0],
setZoomVal = _useState6[1];
var _useState7 = useState(0),
_useState8 = _slicedToArray(_useState7, 2),
rotateVal = _useState8[0],
setRotateVal = _useState8[1];
var beforeUploadRef = React.useRef(); // 返回上传组件的上传之前的钩子函数
var fileRef = React.useRef(); // 记录文件的参数
var resolveRef = useRef(); // 返回文件上传的成功数据的方法
var rejectRef = useRef(); // 返回失败数据的方法
var cropPixelsRef = React.useRef();
var imageCropCanvas = function imageCropCanvas(naturalModalImg) {
var naturalWidth = naturalModalImg.naturalWidth,
naturalHeight = naturalModalImg.naturalHeight;
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
if (ctx) {
// create a max canvas to cover the source image after rotated
var maxLen = Math.sqrt(Math.pow(naturalWidth, 2) + Math.pow(naturalHeight, 2));
canvas.width = maxLen;
canvas.height = maxLen; // rotate the image
if (hasRotate && rotateVal > 0 && rotateVal < 360) {
var halfMax = maxLen / 2;
ctx.translate(halfMax, halfMax);
ctx.rotate(rotateVal * Math.PI / 180);
ctx.translate(-halfMax, -halfMax);
} // draw the source image in the center of the max canvas
var left = (maxLen - naturalWidth) / 2;
var top = (maxLen - naturalHeight) / 2;
ctx.drawImage(naturalModalImg, left, top); // shrink the max canvas to the crop area size, then align two center points
var maxImgData = ctx.getImageData(0, 0, maxLen, maxLen);
if (cropPixelsRef && cropPixelsRef.current) {
var _cropPixelsRef$curren = cropPixelsRef.current,
width = _cropPixelsRef$curren.width,
height = _cropPixelsRef$curren.height,
x = _cropPixelsRef$curren.x,
y = _cropPixelsRef$curren.y;
canvas.width = width;
canvas.height = height; // get the new image
ctx.putImageData(maxImgData, -left - x, -top - y);
return canvas;
}
}
};
/**
* Upload
*/
var renderUpload = useCallback(function () {
var upload = Array.isArray(children) ? children[0] : children;
if (upload && upload.props && upload.type === Upload) {
var _upload$props = upload.props,
beforeUpload = _upload$props.beforeUpload,
accept = _upload$props.accept,
restUploadProps = _objectWithoutProperties(_upload$props, _excluded);
beforeUploadRef.current = beforeUpload;
return _objectSpread(_objectSpread({}, upload), {}, {
props: _objectSpread(_objectSpread({}, restUploadProps), {}, {
accept: accept || 'image/*',
beforeUpload: function beforeUpload(file, fileList) {
return new Promise(function (resolve, reject) {
if (beforeCrop && !beforeCrop(file, fileList)) {
reject();
return;
}
fileRef.current = file;
resolveRef.current = resolve;
rejectRef.current = reject;
var reader = new FileReader();
if (reader) {
reader.addEventListener('load', function () {
if (reader.result && typeof reader.result === 'string') {
setSrc(reader.result);
}
});
if (file instanceof Blob) {
reader.readAsDataURL(file);
}
}
});
}
})
});
}
if (imageSrc && typeof window !== 'undefined') {
var newimage = new Image();
newimage.src = imageSrc;
newimage.crossOrigin = 'anonymous';
newimage.onload = function () {
var canvas = imageToCanvas(newimage);
if (canvas) {
if (isFunction(onModalOk) && canvas) {
setSrc(canvas.toDataURL());
}
}
};
}
}, [beforeCrop, children]);
/**
* EasyCrop
*/
var onComplete = useCallback(function (croppedAreaPixels) {
cropPixelsRef.current = croppedAreaPixels;
if (isFunction(onCropComplete)) {
var naturalModalImg = document.querySelector(".".concat(prefixClsMedia));
var canvas = serverCrop ? imageToCanvas(naturalModalImg) : imageCropCanvas(naturalModalImg);
if (canvas) {
canvas.toBlob(function (blob) {
var area = {};
if (cropPixelsRef.current) {
area = cropPixelsRef.current;
}
onCropComplete({
url: canvas.toDataURL(),
blob: blob,
area: area
});
});
}
}
}, [rotateVal, hasRotate]);
/**
* Controls
*/
var MIN_ROTATE = 0;
var MAX_ROTATE = 360;
var isMinZoom = zoomVal <= MIN_ZOOM;
var isMaxZoom = zoomVal >= MAX_ZOOM;
var isMinRotate = rotateVal === MIN_ROTATE;
var isMaxRotate = rotateVal >= MAX_ROTATE;
var subZoomVal = useCallback(function () {
if (!isMinZoom) setZoomVal(zoomVal - ZOOM_STEP);
}, [isMinZoom, zoomVal]);
var addZoomVal = useCallback(function () {
if (!isMaxZoom) setZoomVal(zoomVal + ZOOM_STEP);
}, [isMaxZoom, zoomVal]);
var addRotateVal = useCallback(function () {
if (!isMaxRotate) {
setRotateVal(rotateVal + rotateStep);
} else {
setRotateVal(MIN_ROTATE + rotateStep);
}
}, [isMaxRotate, rotateVal]);
var initVal = useCallback(function () {
if (!isMinZoom || !isMinRotate) {
setZoomVal(MIN_ZOOM);
setRotateVal(MIN_ROTATE);
}
}, [zoomVal, rotateVal]);
/**
* Modal
*/
var closeModal = useCallback(function () {
setSrc('');
setZoomVal(1);
setRotateVal(0);
}, []);
var onClose = useCallback(function () {
closeModal();
if (isFunction(onModalCancel)) {
onModalCancel();
}
}, []);
var onOk = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
var naturalModalImg, canvas, _fileRef$current, type, name, uid;
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
onClose();
naturalModalImg = document.querySelector(".".concat(prefixClsMedia));
if (naturalModalImg) {
if (naturalModalImg && naturalModalImg instanceof HTMLImageElement) {
canvas = serverCrop ? imageToCanvas(naturalModalImg) : imageCropCanvas(naturalModalImg);
if (fileRef.current && canvas) {
_fileRef$current = fileRef.current, type = _fileRef$current.type, name = _fileRef$current.name, uid = _fileRef$current.uid;
canvas.toBlob( /*#__PURE__*/function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(blob) {
var newFile, res, passedFile, passedFileType;
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
newFile = blob;
if (!newFile) {
_context.next = 30;
break;
}
newFile.lastModifiedDate = Date.now();
newFile.name = name;
newFile.uid = uid;
newFile.imageCropArea = cropPixelsRef.current;
if (!(resolveRef && rejectRef && resolveRef.current && rejectRef.current)) {
_context.next = 30;
break;
}
if (!(typeof beforeUploadRef.current !== 'function')) {
_context.next = 9;
break;
}
return _context.abrupt("return", resolveRef.current(newFile));
case 9:
res = beforeUploadRef.current(newFile, [newFile]);
if (!(typeof res !== 'boolean' && !res)) {
_context.next = 13;
break;
}
console.error('beforeUpload must return a boolean or Promise');
return _context.abrupt("return");
case 13:
if (!(res === true)) {
_context.next = 15;
break;
}
return _context.abrupt("return", resolveRef.current(newFile));
case 15:
if (!(res === false)) {
_context.next = 17;
break;
}
return _context.abrupt("return", rejectRef.current('not upload'));
case 17:
if (!(res && typeof res.then === 'function')) {
_context.next = 30;
break;
}
_context.prev = 18;
_context.next = 21;
return res;
case 21:
passedFile = _context.sent;
passedFileType = Object.prototype.toString.call(passedFile);
if (passedFileType === '[object File]' || passedFileType === '[object Blob]') newFile = passedFile;
resolveRef.current(newFile);
_context.next = 30;
break;
case 27:
_context.prev = 27;
_context.t0 = _context["catch"](18);
rejectRef.current(_context.t0);
case 30:
case "end":
return _context.stop();
}
}
}, _callee, null, [[18, 27]]);
}));
return function (_x) {
return _ref2.apply(this, arguments);
};
}(), type, 0.4);
}
if (isFunction(onModalOk) && canvas) {
canvas.toBlob(function (blob) {
var area = {};
if (cropPixelsRef.current) {
area = cropPixelsRef.current;
}
onModalOk({
url: canvas.toDataURL(),
blob: blob,
area: area
});
});
}
}
}
case 3:
case "end":
return _context2.stop();
}
}
}, _callee2);
})), [hasRotate, onClose, rotateVal]);
var RenderCrop = /*#__PURE__*/React.createElement(EasyCrop, {
ref: ref,
src: src,
aspect: aspect,
shape: shape,
grid: grid,
hasZoom: hasZoom,
zoomVal: zoomVal,
rotateVal: rotateVal,
setZoomVal: setZoomVal,
setRotateVal: setRotateVal,
onComplete: onComplete,
prefixCls: prefixCls
});
var title = modalProps && modalProps.title || modalTitle;
var cancelButtonProps = {
funcType: 'raised'
};
var okButtonProps = {
funcType: 'raised',
type: 'primary'
};
return /*#__PURE__*/React.createElement(LocaleReceiver, {
componentName: "imageCrop",
defaultLocale: defaultLocale.imageCrop
}, function (locale) {
return /*#__PURE__*/React.createElement(React.Fragment, null, renderUpload(), src && modalVisible && /*#__PURE__*/React.createElement(Modal, _extends({
visible: modalVisible,
wrapClassName: "".concat(prefixCls, "-modal"),
title: title || (locale && locale.editImage ? locale.editImage : 'Edit image'),
width: modalWidth,
destroyOnClose: true,
maskClosable: false,
onCancel: onClose,
onOk: onOk,
cancelButtonProps: cancelButtonProps,
okButtonProps: okButtonProps,
okText: modalOk,
cancelText: modalCancel
}, modalProps), cropContent ? cropContent(RenderCrop) : RenderCrop, /*#__PURE__*/React.createElement("div", {
className: "".concat(prefixCls, "-control")
}, hasZoom && /*#__PURE__*/React.createElement(ButtonGroup, null, /*#__PURE__*/React.createElement(Button, {
funcType: "raised",
icon: "zoom_in",
onClick: addZoomVal,
disabled: isMaxZoom
}), /*#__PURE__*/React.createElement(Button, {
funcType: "raised",
icon: "zoom_out",
onClick: subZoomVal,
disabled: isMinZoom
})), hasRotate && /*#__PURE__*/React.createElement(Button, {
funcType: "raised",
icon: rotateStep === 90 ? 'play_90' : 'rotate_right',
onClick: addRotateVal
}), hasZoom && /*#__PURE__*/React.createElement(Button, {
funcType: "raised",
onClick: initVal
}, "1:1"))));
});
});
ImgCrop.displayName = 'ImgCrop';
ImgCrop.defaultProps = {
shape: ShapeCroper.rect,
grid: false,
zoom: true,
rotate: false,
modalWidth: 600,
modalVisible: true,
serverCrop: false
};
ImgCrop.AvatarUploader = AvatarUploader;
export default ImgCrop;
//# sourceMappingURL=index.js.map