index.tsx 3.6 KB

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