choerodon-ui
Version:
An enterprise-class UI design language and React-based implementation
277 lines (246 loc) • 10.1 kB
JavaScript
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import React, { memo, useContext, useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import isElement from 'lodash/isElement';
import classNames from 'classnames';
import ConfigContext from '../config-provider/ConfigContext';
/**
* 返回当前显示设备的物理像素分辨率与CSS像素分辨率之比
*
* @param context
*/
var getPixelRatio = function getPixelRatio(context) {
if (!context) {
return 1;
}
var backingStore = context.backingStorePixelRatio || context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1;
return (window.devicePixelRatio || 1) / backingStore;
};
var WaterMark = /*#__PURE__*/memo(function (props) {
var enable = props.enable,
removeable = props.removeable,
children = props.children,
className = props.className,
markClassName = props.markClassName,
zIndex = props.zIndex,
gapX = props.gapX,
gapY = props.gapY,
width = props.width,
height = props.height,
rotate = props.rotate,
image = props.image,
content = props.content,
offsetLeft = props.offsetLeft,
offsetTop = props.offsetTop,
markStyle = props.markStyle,
customizePrefixCls = props.prefixCls,
getContainer = props.getContainer;
var _markStyle$fontSize = markStyle.fontSize,
fontSize = _markStyle$fontSize === void 0 ? 16 : _markStyle$fontSize,
_markStyle$fontWeight = markStyle.fontWeight,
fontWeight = _markStyle$fontWeight === void 0 ? 'normal' : _markStyle$fontWeight,
_markStyle$fontFamily = markStyle.fontFamily,
fontFamily = _markStyle$fontFamily === void 0 ? 'sans-serif' : _markStyle$fontFamily,
_markStyle$color = markStyle.color,
color = _markStyle$color === void 0 ? 'rgba(0,0,0,.15)' : _markStyle$color,
_markStyle$fontStyle = markStyle.fontStyle,
fontStyle = _markStyle$fontStyle === void 0 ? 'normal' : _markStyle$fontStyle,
_markStyle$opacity = markStyle.opacity,
opacity = _markStyle$opacity === void 0 ? 0.8 : _markStyle$opacity;
var _useContext = useContext(ConfigContext),
getPrefixCls = _useContext.getPrefixCls;
var prefixCls = getPrefixCls('watermark', customizePrefixCls);
var wrapperCls = classNames("".concat(prefixCls, "-wrapper"), className);
var waterMakrCls = classNames(prefixCls, markClassName);
var _useState = useState(''),
_useState2 = _slicedToArray(_useState, 2),
base64Url = _useState2[0],
setBase64Url = _useState2[1];
var wrapperRef = useRef(null);
var waterMarkRef = useRef();
var mutation = useRef(null);
useEffect(function () {
canvasWM(mutationObserver);
}, [enable, gapX, gapY, offsetLeft, offsetTop, rotate, width, height, image, content]);
useEffect(function () {
if (wrapperRef.current && !removeable && enable) {
var wrapperDom = getContainer && isElement(getContainer()) ? getContainer() : wrapperRef.current;
var appendChild = function appendChild(e) {
var event = e || window.event;
setTimeout(function () {
if (!wrapperDom.getElementsByClassName(prefixCls).length && event && event.target) {
wrapperDom.appendChild(event.target);
}
});
}; // 监听浏览器控制台强行移除节点
wrapperDom.addEventListener('DOMNodeRemoved', function (e) {
return appendChild(e);
});
return wrapperDom.removeEventListener('DOMNodeRemoved', function (e) {
return appendChild(e);
});
}
}, [wrapperRef, removeable, enable]);
var mutationObserver = function mutationObserver(imgSrc) {
if (wrapperRef.current && !removeable) {
var wrapperDom = getContainer && isElement(getContainer()) ? getContainer() : wrapperRef.current; // 监听浏览器控制台样式变化
var styleStr = "position: absolute !important; left: 0px !important; top: 0px !important; width: 100% !important; height: 100% !important; z-index: ".concat(zIndex, " !important; pointer-events: none !important; background-repeat: repeat !important; background-size: ").concat(gapX + width, "px !important; background-image: url(\"").concat(imgSrc, "\") !important; opacity: ").concat(opacity, " !important; visibility: visible !important; display: block !important; transform: scale(1) !important;");
var MutationObserver = window.MutationObserver;
if (mutation.current) {
mutation.current.disconnect();
mutation.current = null;
}
if (MutationObserver && !mutation.current) {
mutation.current = new MutationObserver(function (mutationsList) {
var wmInstance = wrapperDom.querySelector(".".concat(prefixCls));
var newStyle = wmInstance && wmInstance.getAttribute('style');
var observe = mutationsList.find(function (_ref) {
var target = _ref.target;
return target && target.contains(wmInstance) || target.contains(wrapperDom);
});
if (observe && wmInstance && newStyle !== styleStr) {
wmInstance.setAttribute('style', styleStr);
}
});
mutation.current.observe(wrapperDom, {
attributes: true,
subtree: true,
childList: true
});
}
}
};
var canvasWM = function canvasWM(callback) {
if (enable) {
// 绘制水印
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var ratio = getPixelRatio(ctx);
var canvasWidth = "".concat((gapX + width) * ratio, "px");
var canvasHeight = "".concat((gapY + height) * ratio, "px");
var canvasOffsetLeft = offsetLeft || gapX / 2;
var canvasOffsetTop = offsetTop || gapY / 2;
canvas.setAttribute('width', canvasWidth);
canvas.setAttribute('height', canvasHeight);
if (ctx) {
// 旋转字符 rotate
var markWidth = width * ratio;
var markHeight = height * ratio; // 确定旋转中心
var centerX = markWidth / 2 + canvasOffsetLeft * ratio;
var centerY = markHeight / 2 + canvasOffsetTop * ratio;
ctx.translate(centerX, centerY);
ctx.rotate(Math.PI / 180 * Number(rotate));
if (image) {
var img = new Image();
img.crossOrigin = 'anonymous';
img.referrerPolicy = 'no-referrer';
img.src = image;
img.onload = function () {
ctx.drawImage(img, -markWidth / 2, -markHeight / 2, markWidth, markHeight);
callback(canvas.toDataURL());
setBase64Url(canvas.toDataURL());
};
} else if (content) {
var markSize = Number(fontSize) * ratio;
ctx.font = "".concat(fontStyle, " normal ").concat(fontWeight, " ").concat(markSize, "px ").concat(fontFamily);
ctx.fillStyle = color; // 计算文本的长度
drawText({
content: content,
ctx: ctx,
canvasWidth: markWidth,
markHeight: markHeight,
fontHeight: markSize
});
setBase64Url(canvas.toDataURL());
callback(canvas.toDataURL());
}
} else {
console.error('当前环境不支持Canvas');
}
}
};
/**
*
* @param content 文本
* @param ctx 绘制上下文
* @param canvasWidth 绘制宽度
* @param markHeight 水印高度
* @param fontHeight 字体高度
*/
var drawText = function drawText(_ref2) {
var content = _ref2.content,
ctx = _ref2.ctx,
canvasWidth = _ref2.canvasWidth,
markHeight = _ref2.markHeight,
fontHeight = _ref2.fontHeight;
var lastSubStrIndex = 0;
var lineWidth = 0;
var initHeight = fontHeight;
for (var i = 0; i < content.length; i++) {
var _ctx$measureText = ctx.measureText(content[i]),
_width = _ctx$measureText.width;
lineWidth += _width;
if (lineWidth > canvasWidth - _width) {
ctx.fillText(content.substring(lastSubStrIndex, i), 0 - canvasWidth / 2, initHeight - markHeight / 2);
initHeight += fontHeight;
lineWidth = 0;
lastSubStrIndex = i;
}
if (i === content.length - 1) {
ctx.fillText(content.substring(lastSubStrIndex, i + 1), 0 - canvasWidth / 2, initHeight - markHeight / 2);
}
}
};
var renderCanvas = useMemo(function () {
return enable ? /*#__PURE__*/React.createElement('div', {
className: waterMakrCls,
ref: waterMarkRef.current ? waterMarkRef : undefined,
style: {
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%',
zIndex: zIndex,
pointerEvents: 'none',
backgroundRepeat: 'repeat',
backgroundSize: "".concat(gapX + width, "px"),
backgroundImage: "url('".concat(base64Url, "')"),
opacity: opacity
}
}) : null;
}, [enable, waterMakrCls, gapX, width, base64Url, zIndex]);
var getWMContainer = useMemo(function () {
var container = getContainer && getContainer();
if (container && isElement(container)) {
container.style.setProperty('position', container.style.position || 'relative');
return /*#__PURE__*/createPortal(renderCanvas, container);
}
return renderCanvas;
}, [getContainer, renderCanvas]);
return /*#__PURE__*/React.createElement("div", {
className: wrapperCls,
ref: wrapperRef
}, children, getWMContainer);
});
WaterMark.displayName = 'WaterMark';
WaterMark.defaultProps = {
enable: true,
removeable: false,
zIndex: 9,
gapX: 212,
gapY: 222,
width: 120,
height: 64,
rotate: -22,
markStyle: {
fontStyle: 'normal',
fontWeight: 'normal',
color: 'rgba(0,0,0,.15)',
fontSize: 16,
fontFamily: 'sans-serif',
opacity: 0.8
}
};
export default WaterMark;
//# sourceMappingURL=WaterMark.js.map