index.tsx 3.8 KB

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