useClips.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = exports.FontGap = void 0;
  7. var _react = _interopRequireDefault(require("react"));
  8. var _toList = _interopRequireDefault(require("../_util/toList"));
  9. const FontGap = exports.FontGap = 3;
  10. const prepareCanvas = (width, height, ratio = 1) => {
  11. const canvas = document.createElement('canvas');
  12. const ctx = canvas.getContext('2d');
  13. const realWidth = width * ratio;
  14. const realHeight = height * ratio;
  15. canvas.setAttribute('width', `${realWidth}px`);
  16. canvas.setAttribute('height', `${realHeight}px`);
  17. ctx.save();
  18. return [ctx, canvas, realWidth, realHeight];
  19. };
  20. // Get boundary of rotated text
  21. const getRotatePos = (x, y, angle) => {
  22. const targetX = x * Math.cos(angle) - y * Math.sin(angle);
  23. const targetY = x * Math.sin(angle) + y * Math.cos(angle);
  24. return [targetX, targetY];
  25. };
  26. /**
  27. * Get the clips of text content.
  28. * This is a lazy hook function since SSR no need this
  29. */
  30. const useClips = () => {
  31. // Get single clips
  32. const getClips = (content, rotate, ratio, width, height, font, gapX, gapY) => {
  33. // ================= Text / Image =================
  34. const [ctx, canvas, contentWidth, contentHeight] = prepareCanvas(width, height, ratio);
  35. if (content instanceof HTMLImageElement) {
  36. // Image
  37. ctx.drawImage(content, 0, 0, contentWidth, contentHeight);
  38. } else {
  39. // Text
  40. const {
  41. color,
  42. fontSize,
  43. fontStyle,
  44. fontWeight,
  45. fontFamily,
  46. textAlign
  47. } = font;
  48. const mergedFontSize = Number(fontSize) * ratio;
  49. ctx.font = `${fontStyle} normal ${fontWeight} ${mergedFontSize}px/${height}px ${fontFamily}`;
  50. ctx.fillStyle = color;
  51. ctx.textAlign = textAlign;
  52. ctx.textBaseline = 'top';
  53. const contents = (0, _toList.default)(content);
  54. contents === null || contents === void 0 ? void 0 : contents.forEach((item, index) => {
  55. ctx.fillText(item !== null && item !== void 0 ? item : '', contentWidth / 2, index * (mergedFontSize + FontGap * ratio));
  56. });
  57. }
  58. // ==================== Rotate ====================
  59. const angle = Math.PI / 180 * Number(rotate);
  60. const maxSize = Math.max(width, height);
  61. const [rCtx, rCanvas, realMaxSize] = prepareCanvas(maxSize, maxSize, ratio);
  62. // Copy from `ctx` and rotate
  63. rCtx.translate(realMaxSize / 2, realMaxSize / 2);
  64. rCtx.rotate(angle);
  65. if (contentWidth > 0 && contentHeight > 0) {
  66. rCtx.drawImage(canvas, -contentWidth / 2, -contentHeight / 2);
  67. }
  68. let left = 0;
  69. let right = 0;
  70. let top = 0;
  71. let bottom = 0;
  72. const halfWidth = contentWidth / 2;
  73. const halfHeight = contentHeight / 2;
  74. const points = [[0 - halfWidth, 0 - halfHeight], [0 + halfWidth, 0 - halfHeight], [0 + halfWidth, 0 + halfHeight], [0 - halfWidth, 0 + halfHeight]];
  75. points.forEach(([x, y]) => {
  76. const [targetX, targetY] = getRotatePos(x, y, angle);
  77. left = Math.min(left, targetX);
  78. right = Math.max(right, targetX);
  79. top = Math.min(top, targetY);
  80. bottom = Math.max(bottom, targetY);
  81. });
  82. const cutLeft = left + realMaxSize / 2;
  83. const cutTop = top + realMaxSize / 2;
  84. const cutWidth = right - left;
  85. const cutHeight = bottom - top;
  86. // ================ Fill Alternate ================
  87. const realGapX = gapX * ratio;
  88. const realGapY = gapY * ratio;
  89. const filledWidth = (cutWidth + realGapX) * 2;
  90. const filledHeight = cutHeight + realGapY;
  91. const [fCtx, fCanvas] = prepareCanvas(filledWidth, filledHeight);
  92. const drawImg = (targetX = 0, targetY = 0) => {
  93. fCtx.drawImage(rCanvas, cutLeft, cutTop, cutWidth, cutHeight, targetX, targetY, cutWidth, cutHeight);
  94. };
  95. drawImg();
  96. drawImg(cutWidth + realGapX, -cutHeight / 2 - realGapY / 2);
  97. drawImg(cutWidth + realGapX, +cutHeight / 2 + realGapY / 2);
  98. return [fCanvas.toDataURL(), filledWidth / ratio, filledHeight / ratio];
  99. };
  100. return _react.default.useCallback(getClips, []);
  101. };
  102. var _default = exports.default = useClips;