index.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import React, { useState, useEffect } from 'react';
  2. import OuterRect from '../OuterRect';
  3. import {
  4. svgPath,
  5. bezierCommand,
  6. controlPoint,
  7. line,
  8. } from '../../helpers/svgBezierCurve';
  9. import { pointCalc, rectCalcWithPoint, calcViewBox } from '../../helpers/brush';
  10. import { AnnotationContainer } from '../../global/otherStyled';
  11. import { SVG } from './styled';
  12. const Ink: React.FC<AnnotationElementPropsType> = ({
  13. obj_attr: { position, bdcolor, bdwidth = 0, transparency },
  14. isCollapse,
  15. onUpdate,
  16. viewport,
  17. scale,
  18. id,
  19. }: AnnotationElementPropsType) => {
  20. const [points, setPoints] = useState<PointType[][]>([]);
  21. const [rect, setRect] = useState({ top: 0, left: 0, width: 0, height: 0 });
  22. const [moving, setMoving] = useState(false);
  23. const borderWidth = bdwidth * scale;
  24. const handleScaleOrMove = ({
  25. top,
  26. left,
  27. width = 0,
  28. height = 0,
  29. }: CoordType): void => {
  30. setMoving(true);
  31. setRect((currentRect) => {
  32. const rx = width / currentRect.width;
  33. const ry = height / currentRect.height;
  34. const dx = left - currentRect.left;
  35. const dy = currentRect.top - top;
  36. let disX = 0;
  37. let disY = 0;
  38. setPoints((currentPoint) => {
  39. const newRect = rectCalcWithPoint(currentPoint, borderWidth);
  40. disX = newRect.left - left;
  41. disY = newRect.top - top;
  42. const newPoints = (currentPoint as PointType[][])[0].map((ele) => {
  43. let x = (ele.x + dx) * rx;
  44. let y = (ele.y - dy) * ry;
  45. if (rx !== 1) {
  46. x = x - disX;
  47. }
  48. if (ry !== 1) {
  49. y = y - disY + 5;
  50. }
  51. return {
  52. x,
  53. y,
  54. };
  55. });
  56. return [newPoints];
  57. });
  58. return { top, left, width, height };
  59. });
  60. };
  61. const handleMouseUp = () => {
  62. setMoving(false);
  63. };
  64. useEffect(() => {
  65. const newPoints = pointCalc(
  66. position as PointType[][],
  67. viewport.height,
  68. scale,
  69. );
  70. const newRect = rectCalcWithPoint(newPoints, borderWidth);
  71. setPoints(newPoints);
  72. setRect(newRect);
  73. }, [viewport, scale]);
  74. useEffect(() => {
  75. if (!moving && points[0]) {
  76. const newPoints = (points as PointType[][])[0].map((ele) => ({
  77. x: ele.x / scale,
  78. y: (viewport.height - ele.y) / scale,
  79. }));
  80. onUpdate({
  81. position: [newPoints],
  82. });
  83. }
  84. }, [moving, points]);
  85. return (
  86. <>
  87. <AnnotationContainer
  88. id={id}
  89. top={`${rect.top}px`}
  90. left={`${rect.left}px`}
  91. width={`${rect.width}px`}
  92. height={`${rect.height}px`}
  93. >
  94. <SVG
  95. width={rect.width + borderWidth}
  96. height={rect.height + borderWidth}
  97. viewBox={calcViewBox(rect, borderWidth)}
  98. >
  99. {points.map((ele: PointType[], index: number) => {
  100. const key = `${id}_path_${index}`;
  101. return (
  102. <path
  103. key={key}
  104. d={svgPath(
  105. ele as PointType[],
  106. bezierCommand(controlPoint(line, 0.2)),
  107. )}
  108. fill="none"
  109. stroke={bdcolor}
  110. strokeWidth={borderWidth}
  111. strokeOpacity={transparency}
  112. />
  113. );
  114. })}
  115. </SVG>
  116. </AnnotationContainer>
  117. {!isCollapse ? (
  118. <OuterRect
  119. top={rect.top}
  120. left={rect.left}
  121. width={rect.width}
  122. height={rect.height}
  123. onMove={handleScaleOrMove}
  124. onScale={handleScaleOrMove}
  125. onMouseUp={handleMouseUp}
  126. />
  127. ) : (
  128. ''
  129. )}
  130. </>
  131. );
  132. };
  133. export default Ink;