watermark2.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var vue = require('vue');
  4. var core = require('@vueuse/core');
  5. var watermark = require('./watermark.js');
  6. var utils = require('./utils.js');
  7. var useClips = require('./useClips.js');
  8. var pluginVue_exportHelper = require('../../../_virtual/plugin-vue_export-helper.js');
  9. var shared = require('@vue/shared');
  10. var types = require('../../../utils/types.js');
  11. const _sfc_main = vue.defineComponent({
  12. ...{
  13. name: "ElWatermark"
  14. },
  15. __name: "watermark",
  16. props: watermark.watermarkProps,
  17. setup(__props) {
  18. const style = {
  19. position: "relative"
  20. };
  21. const props = __props;
  22. const fontGap = vue.computed(() => {
  23. var _a, _b;
  24. return (_b = (_a = props.font) == null ? void 0 : _a.fontGap) != null ? _b : 3;
  25. });
  26. const color = vue.computed(() => {
  27. var _a, _b;
  28. return (_b = (_a = props.font) == null ? void 0 : _a.color) != null ? _b : "rgba(0,0,0,.15)";
  29. });
  30. const fontSize = vue.computed(() => {
  31. var _a, _b;
  32. return (_b = (_a = props.font) == null ? void 0 : _a.fontSize) != null ? _b : 16;
  33. });
  34. const fontWeight = vue.computed(() => {
  35. var _a, _b;
  36. return (_b = (_a = props.font) == null ? void 0 : _a.fontWeight) != null ? _b : "normal";
  37. });
  38. const fontStyle = vue.computed(() => {
  39. var _a, _b;
  40. return (_b = (_a = props.font) == null ? void 0 : _a.fontStyle) != null ? _b : "normal";
  41. });
  42. const fontFamily = vue.computed(() => {
  43. var _a, _b;
  44. return (_b = (_a = props.font) == null ? void 0 : _a.fontFamily) != null ? _b : "sans-serif";
  45. });
  46. const textAlign = vue.computed(() => {
  47. var _a, _b;
  48. return (_b = (_a = props.font) == null ? void 0 : _a.textAlign) != null ? _b : "center";
  49. });
  50. const textBaseline = vue.computed(() => {
  51. var _a, _b;
  52. return (_b = (_a = props.font) == null ? void 0 : _a.textBaseline) != null ? _b : "hanging";
  53. });
  54. const gapX = vue.computed(() => props.gap[0]);
  55. const gapY = vue.computed(() => props.gap[1]);
  56. const gapXCenter = vue.computed(() => gapX.value / 2);
  57. const gapYCenter = vue.computed(() => gapY.value / 2);
  58. const offsetLeft = vue.computed(() => {
  59. var _a, _b;
  60. return (_b = (_a = props.offset) == null ? void 0 : _a[0]) != null ? _b : gapXCenter.value;
  61. });
  62. const offsetTop = vue.computed(() => {
  63. var _a, _b;
  64. return (_b = (_a = props.offset) == null ? void 0 : _a[1]) != null ? _b : gapYCenter.value;
  65. });
  66. const getMarkStyle = () => {
  67. const markStyle = {
  68. zIndex: props.zIndex,
  69. position: "absolute",
  70. left: 0,
  71. top: 0,
  72. width: "100%",
  73. height: "100%",
  74. pointerEvents: "none",
  75. backgroundRepeat: "repeat"
  76. };
  77. let positionLeft = offsetLeft.value - gapXCenter.value;
  78. let positionTop = offsetTop.value - gapYCenter.value;
  79. if (positionLeft > 0) {
  80. markStyle.left = `${positionLeft}px`;
  81. markStyle.width = `calc(100% - ${positionLeft}px)`;
  82. positionLeft = 0;
  83. }
  84. if (positionTop > 0) {
  85. markStyle.top = `${positionTop}px`;
  86. markStyle.height = `calc(100% - ${positionTop}px)`;
  87. positionTop = 0;
  88. }
  89. markStyle.backgroundPosition = `${positionLeft}px ${positionTop}px`;
  90. return markStyle;
  91. };
  92. const containerRef = vue.shallowRef(null);
  93. const watermarkRef = vue.shallowRef();
  94. const stopObservation = vue.ref(false);
  95. const destroyWatermark = () => {
  96. if (watermarkRef.value) {
  97. watermarkRef.value.remove();
  98. watermarkRef.value = void 0;
  99. }
  100. };
  101. const appendWatermark = (base64Url, markWidth) => {
  102. var _a;
  103. if (containerRef.value && watermarkRef.value) {
  104. stopObservation.value = true;
  105. watermarkRef.value.setAttribute(
  106. "style",
  107. utils.getStyleStr({
  108. ...getMarkStyle(),
  109. backgroundImage: `url('${base64Url}')`,
  110. backgroundSize: `${Math.floor(markWidth)}px`
  111. })
  112. );
  113. (_a = containerRef.value) == null ? void 0 : _a.append(watermarkRef.value);
  114. setTimeout(() => {
  115. stopObservation.value = false;
  116. });
  117. }
  118. };
  119. const getMarkSize = (ctx) => {
  120. let defaultWidth = 120;
  121. let defaultHeight = 64;
  122. let space = 0;
  123. const { image, content, width, height, rotate } = props;
  124. if (!image && ctx.measureText) {
  125. ctx.font = `${Number(fontSize.value)}px ${fontFamily.value}`;
  126. const contents = shared.isArray(content) ? content : [content];
  127. let maxWidth = 0;
  128. let maxHeight = 0;
  129. contents.forEach((item) => {
  130. const {
  131. width: width2,
  132. fontBoundingBoxAscent,
  133. fontBoundingBoxDescent,
  134. actualBoundingBoxAscent,
  135. actualBoundingBoxDescent
  136. } = ctx.measureText(item);
  137. const height2 = types.isUndefined(fontBoundingBoxAscent) ? actualBoundingBoxAscent + actualBoundingBoxDescent : fontBoundingBoxAscent + fontBoundingBoxDescent;
  138. if (width2 > maxWidth)
  139. maxWidth = Math.ceil(width2);
  140. if (height2 > maxHeight)
  141. maxHeight = Math.ceil(height2);
  142. });
  143. defaultWidth = maxWidth;
  144. defaultHeight = maxHeight * contents.length + (contents.length - 1) * fontGap.value;
  145. const angle = Math.PI / 180 * Number(rotate);
  146. space = Math.ceil(Math.abs(Math.sin(angle) * defaultHeight) / 2);
  147. defaultWidth += space;
  148. }
  149. return [width != null ? width : defaultWidth, height != null ? height : defaultHeight, space];
  150. };
  151. const getClips = useClips["default"]();
  152. const renderWatermark = () => {
  153. const canvas = document.createElement("canvas");
  154. const ctx = canvas.getContext("2d");
  155. const image = props.image;
  156. const content = props.content;
  157. const rotate = props.rotate;
  158. if (ctx) {
  159. if (!watermarkRef.value) {
  160. watermarkRef.value = document.createElement("div");
  161. }
  162. const ratio = utils.getPixelRatio();
  163. const [markWidth, markHeight, space] = getMarkSize(ctx);
  164. const drawCanvas = (drawContent) => {
  165. const [textClips, clipWidth] = getClips(
  166. drawContent || "",
  167. rotate,
  168. ratio,
  169. markWidth,
  170. markHeight,
  171. {
  172. color: color.value,
  173. fontSize: fontSize.value,
  174. fontStyle: fontStyle.value,
  175. fontWeight: fontWeight.value,
  176. fontFamily: fontFamily.value,
  177. fontGap: fontGap.value,
  178. textAlign: textAlign.value,
  179. textBaseline: textBaseline.value
  180. },
  181. gapX.value,
  182. gapY.value,
  183. space
  184. );
  185. appendWatermark(textClips, clipWidth);
  186. };
  187. if (image) {
  188. const img = new Image();
  189. img.onload = () => {
  190. drawCanvas(img);
  191. };
  192. img.onerror = () => {
  193. drawCanvas(content);
  194. };
  195. img.crossOrigin = "anonymous";
  196. img.referrerPolicy = "no-referrer";
  197. img.src = image;
  198. } else {
  199. drawCanvas(content);
  200. }
  201. }
  202. };
  203. vue.onMounted(() => {
  204. renderWatermark();
  205. });
  206. vue.watch(
  207. () => props,
  208. () => {
  209. renderWatermark();
  210. },
  211. {
  212. deep: true,
  213. flush: "post"
  214. }
  215. );
  216. vue.onBeforeUnmount(() => {
  217. destroyWatermark();
  218. });
  219. const onMutate = (mutations) => {
  220. if (stopObservation.value) {
  221. return;
  222. }
  223. mutations.forEach((mutation) => {
  224. if (utils.reRendering(mutation, watermarkRef.value)) {
  225. destroyWatermark();
  226. renderWatermark();
  227. }
  228. });
  229. };
  230. core.useMutationObserver(containerRef, onMutate, {
  231. attributes: true,
  232. subtree: true,
  233. childList: true
  234. });
  235. return (_ctx, _cache) => {
  236. return vue.openBlock(), vue.createElementBlock(
  237. "div",
  238. {
  239. ref_key: "containerRef",
  240. ref: containerRef,
  241. style: vue.normalizeStyle([style])
  242. },
  243. [
  244. vue.renderSlot(_ctx.$slots, "default")
  245. ],
  246. 4
  247. );
  248. };
  249. }
  250. });
  251. var Watermark = /* @__PURE__ */ pluginVue_exportHelper["default"](_sfc_main, [["__file", "/home/runner/work/element-plus/element-plus/packages/components/watermark/src/watermark.vue"]]);
  252. exports["default"] = Watermark;
  253. //# sourceMappingURL=watermark2.js.map