antd-watermark
Version:
watermark ui component for react
249 lines (206 loc) • 9.45 kB
JavaScript
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var _useMutationObserver2 = _interopRequireDefault(require("./useMutationObserver"));
var _utils = require("./utils");
/**
* Base size of the canvas, 1 for parallel layout and 2 for alternate layout
* Only alternate layout is currently supported
*/
var BaseSize = 2;
var FontGap = 3;
var Watermark = function Watermark(props) {
var _offset$, _offset$2;
var _props$zIndex = props.zIndex,
zIndex = _props$zIndex === void 0 ? 9 : _props$zIndex,
_props$rotate = props.rotate,
rotate = _props$rotate === void 0 ? -22 : _props$rotate,
width = props.width,
height = props.height,
image = props.image,
content = props.content,
_props$font = props.font,
font = _props$font === void 0 ? {} : _props$font,
style = props.style,
className = props.className,
_props$gap = props.gap,
gap = _props$gap === void 0 ? [100, 100] : _props$gap,
offset = props.offset,
children = props.children;
var _font$color = font.color,
color = _font$color === void 0 ? 'rgba(0,0,0,.15)' : _font$color,
_font$fontSize = font.fontSize,
fontSize = _font$fontSize === void 0 ? 16 : _font$fontSize,
_font$fontWeight = font.fontWeight,
fontWeight = _font$fontWeight === void 0 ? 'normal' : _font$fontWeight,
_font$fontStyle = font.fontStyle,
fontStyle = _font$fontStyle === void 0 ? 'normal' : _font$fontStyle,
_font$fontFamily = font.fontFamily,
fontFamily = _font$fontFamily === void 0 ? 'sans-serif' : _font$fontFamily;
var _gap = (0, _slicedToArray2.default)(gap, 2),
gapX = _gap[0],
gapY = _gap[1];
var gapXCenter = gapX / 2;
var gapYCenter = gapY / 2;
var offsetLeft = (_offset$ = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _offset$ !== void 0 ? _offset$ : gapXCenter;
var offsetTop = (_offset$2 = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _offset$2 !== void 0 ? _offset$2 : gapYCenter;
var getMarkStyle = function getMarkStyle() {
var markStyle = {
zIndex: zIndex,
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%',
pointerEvents: 'none',
backgroundRepeat: 'repeat'
};
/** Calculate the style of the offset */
var positionLeft = offsetLeft - gapXCenter;
var positionTop = offsetTop - gapYCenter;
if (positionLeft > 0) {
markStyle.left = "".concat(positionLeft, "px");
markStyle.width = "calc(100% - ".concat(positionLeft, "px)");
positionLeft = 0;
}
if (positionTop > 0) {
markStyle.top = "".concat(positionTop, "px");
markStyle.height = "calc(100% - ".concat(positionTop, "px)");
positionTop = 0;
}
markStyle.backgroundPosition = "".concat(positionLeft, "px ").concat(positionTop, "px");
return markStyle;
};
var containerRef = (0, _react.useRef)(null);
var watermarkRef = (0, _react.useRef)();
var _useMutationObserver = (0, _useMutationObserver2.default)(),
createObserver = _useMutationObserver.createObserver,
destroyObserver = _useMutationObserver.destroyObserver,
reRendering = _useMutationObserver.reRendering;
var destroyWatermark = function destroyWatermark() {
if (watermarkRef.current) {
watermarkRef.current.remove();
watermarkRef.current = undefined;
}
};
var appendWatermark = function appendWatermark(base64Url, markWidth) {
if (containerRef.current && watermarkRef.current) {
var _containerRef$current;
destroyObserver();
watermarkRef.current.setAttribute('style', (0, _utils.getStyleStr)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, getMarkStyle()), {}, {
backgroundImage: "url('".concat(base64Url, "')"),
backgroundSize: "".concat((gapX + markWidth) * BaseSize, "px")
})));
(_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.append(watermarkRef.current);
createObserver(containerRef.current, function (mutations) {
mutations.forEach(function (mutation) {
if (reRendering(mutation, watermarkRef.current)) {
destroyWatermark(); // eslint-disable-next-line @typescript-eslint/no-use-before-define
renderWatermark();
}
});
});
}
};
/**
* Get the width and height of the watermark. The default values are as follows
* Image: [120, 64]; Content: It's calculated by content;
*/
var getMarkSize = function getMarkSize(ctx) {
var defaultWidth = 120;
var defaultHeight = 64;
if (!image && ctx.measureText) {
ctx.font = "".concat(Number(fontSize), "px ").concat(fontFamily);
var contents = Array.isArray(content) ? content : [content];
var widths = contents.map(function (item) {
return ctx.measureText(item).width;
});
defaultWidth = Math.ceil(Math.max.apply(Math, (0, _toConsumableArray2.default)(widths)));
defaultHeight = Number(fontSize) * contents.length + (contents.length - 1) * FontGap;
}
return [width !== null && width !== void 0 ? width : defaultWidth, height !== null && height !== void 0 ? height : defaultHeight];
};
var fillTexts = function fillTexts(ctx, drawX, drawY, drawWidth, drawHeight) {
var ratio = (0, _utils.getPixelRatio)();
var mergedFontSize = Number(fontSize) * ratio;
ctx.font = "".concat(fontStyle, " normal ").concat(fontWeight, " ").concat(mergedFontSize, "px/").concat(drawHeight, "px ").concat(fontFamily);
ctx.fillStyle = color;
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
ctx.translate(drawWidth / 2, 0);
var contents = Array.isArray(content) ? content : [content];
contents === null || contents === void 0 ? void 0 : contents.forEach(function (item, index) {
ctx.fillText(item !== null && item !== void 0 ? item : '', drawX, drawY + index * (mergedFontSize + FontGap * ratio));
});
};
var renderWatermark = function renderWatermark() {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
if (ctx) {
if (!watermarkRef.current) {
watermarkRef.current = document.createElement('div');
}
var ratio = (0, _utils.getPixelRatio)();
var _getMarkSize = getMarkSize(ctx),
_getMarkSize2 = (0, _slicedToArray2.default)(_getMarkSize, 2),
markWidth = _getMarkSize2[0],
markHeight = _getMarkSize2[1];
var canvasWidth = (gapX + markWidth) * ratio;
var canvasHeight = (gapY + markHeight) * ratio;
canvas.setAttribute('width', "".concat(canvasWidth * BaseSize, "px"));
canvas.setAttribute('height', "".concat(canvasHeight * BaseSize, "px"));
var drawX = gapX * ratio / 2;
var drawY = gapY * ratio / 2;
var drawWidth = markWidth * ratio;
var drawHeight = markHeight * ratio;
var rotateX = (drawWidth + gapX * ratio) / 2;
var rotateY = (drawHeight + gapY * ratio) / 2;
/** Alternate drawing parameters */
var alternateDrawX = drawX + canvasWidth;
var alternateDrawY = drawY + canvasHeight;
var alternateRotateX = rotateX + canvasWidth;
var alternateRotateY = rotateY + canvasHeight;
ctx.save();
(0, _utils.rotateWatermark)(ctx, rotateX, rotateY, rotate);
if (image) {
var img = new Image();
img.onload = function () {
ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight);
/** Draw interleaved pictures after rotation */
ctx.restore();
(0, _utils.rotateWatermark)(ctx, alternateRotateX, alternateRotateY, rotate);
ctx.drawImage(img, alternateDrawX, alternateDrawY, drawWidth, drawHeight);
appendWatermark(canvas.toDataURL(), markWidth);
};
img.crossOrigin = 'anonymous';
img.referrerPolicy = 'no-referrer';
img.src = image;
} else {
fillTexts(ctx, drawX, drawY, drawWidth, drawHeight);
/** Fill the interleaved text after rotation */
ctx.restore();
(0, _utils.rotateWatermark)(ctx, alternateRotateX, alternateRotateY, rotate);
fillTexts(ctx, alternateDrawX, alternateDrawY, drawWidth, drawHeight);
appendWatermark(canvas.toDataURL(), markWidth);
}
}
};
(0, _react.useEffect)(renderWatermark, [rotate, zIndex, width, height, image, content, color, fontSize, fontWeight, fontStyle, fontFamily, gapX, gapY, offsetLeft, offsetTop]);
return /*#__PURE__*/_react.default.createElement("div", {
ref: containerRef,
className: className,
style: (0, _objectSpread2.default)({
position: 'relative'
}, style)
}, children);
};
var _default = Watermark;
exports.default = _default;