index.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import React, { useState, useEffect } from 'react';
  2. import { v4 as uuidv4 } from 'uuid';
  3. import Outer from '../OuterRectForLine';
  4. import { parsePositionForBackend } from '../../helpers/position';
  5. import { AnnotationContainer } from '../../global/otherStyled';
  6. import { SVG } from './styled';
  7. const getActualPoint = (
  8. { start, end }: LinePositionType,
  9. h: number,
  10. s: number,
  11. ): LinePositionType => {
  12. const x1 = start.x * s;
  13. const y1 = h - start.y * s;
  14. const x2 = end.x * s;
  15. const y2 = h - end.y * s;
  16. return {
  17. start: {
  18. x: x1,
  19. y: y1,
  20. },
  21. end: {
  22. x: x2,
  23. y: y2,
  24. },
  25. };
  26. };
  27. const rectCalc = ({ start, end }: LinePositionType): HTMLCoordinateType => {
  28. return {
  29. top: start.y < end.y ? start.y : end.y,
  30. left: start.x < end.x ? start.x : end.x,
  31. width: Math.abs(end.x - start.x),
  32. height: Math.abs(end.y - start.y),
  33. };
  34. };
  35. const Line: React.FC<AnnotationElementPropsType> = ({
  36. id,
  37. obj_type,
  38. obj_attr: { bdcolor = '', bdwidth = 0, transparency = 0, position, is_arrow },
  39. scale,
  40. viewport,
  41. isCollapse,
  42. onUpdate,
  43. }: AnnotationElementPropsType) => {
  44. const [startPoint, setStartPoint] = useState({ x: 0, y: 0 });
  45. const [endPoint, setEndPoint] = useState({ x: 0, y: 0 });
  46. const [rect, setRect] = useState({ top: 0, left: 0, width: 0, height: 0 });
  47. const [moving, setMoving] = useState(false);
  48. const uuid = uuidv4();
  49. const actualbdwidth = bdwidth * scale;
  50. const handleMove = ({
  51. start: moveStart,
  52. end: moveEnd,
  53. }: LinePositionType): void => {
  54. setMoving(true);
  55. setStartPoint(moveStart);
  56. setEndPoint(moveEnd);
  57. const newRect = rectCalc({ start: moveStart, end: moveEnd });
  58. if (is_arrow) {
  59. setRect({
  60. top: newRect.top - actualbdwidth * 2,
  61. left: newRect.left - actualbdwidth * 2,
  62. width: newRect.width + actualbdwidth * 4,
  63. height: newRect.height + actualbdwidth * 4,
  64. });
  65. } else {
  66. setRect({
  67. top: newRect.top - actualbdwidth / 2,
  68. left: newRect.left - actualbdwidth / 2,
  69. width: newRect.width + actualbdwidth,
  70. height: newRect.height + actualbdwidth,
  71. });
  72. }
  73. };
  74. const handleMouseUp = () => {
  75. setMoving(false);
  76. };
  77. useEffect(() => {
  78. if (!moving && startPoint.x) {
  79. const newPosition = {
  80. start: {
  81. x: startPoint.x,
  82. y: startPoint.y,
  83. },
  84. end: {
  85. x: endPoint.x,
  86. y: endPoint.y,
  87. },
  88. };
  89. onUpdate({
  90. position: parsePositionForBackend(
  91. obj_type,
  92. newPosition,
  93. viewport.height,
  94. scale,
  95. ),
  96. });
  97. }
  98. }, [moving, startPoint, endPoint]);
  99. useEffect(() => {
  100. const { start, end } = getActualPoint(
  101. position as LinePositionType,
  102. viewport.height,
  103. scale,
  104. );
  105. setStartPoint(start);
  106. setEndPoint(end);
  107. const initRect = rectCalc({ start, end });
  108. if (is_arrow) {
  109. setRect({
  110. top: initRect.top - actualbdwidth * 2,
  111. left: initRect.left - actualbdwidth * 2,
  112. width: initRect.width + actualbdwidth * 4,
  113. height: initRect.height + actualbdwidth * 4,
  114. });
  115. } else {
  116. setRect({
  117. top: initRect.top - actualbdwidth / 2,
  118. left: initRect.left - actualbdwidth / 2,
  119. width: initRect.width + actualbdwidth,
  120. height: initRect.height + actualbdwidth,
  121. });
  122. }
  123. }, [viewport, scale]);
  124. return (
  125. <>
  126. <AnnotationContainer
  127. id={id}
  128. top={`${rect.top}px`}
  129. left={`${rect.left}px`}
  130. width={`${rect.width}px`}
  131. height={`${rect.height}px`}
  132. >
  133. <SVG
  134. width={rect.width}
  135. height={rect.height}
  136. viewBox={`${rect.left} ${rect.top} ${rect.width} ${rect.height}`}
  137. >
  138. {is_arrow ? (
  139. <defs>
  140. <marker
  141. id={uuid}
  142. markerWidth={actualbdwidth * 2}
  143. markerHeight={actualbdwidth * 3}
  144. refX={3}
  145. refY={2}
  146. orient="auto"
  147. markerUnits="strokeWidth"
  148. >
  149. <polyline
  150. points="0.25,0.5 3.25,2 0.25,3.5 3.25,2 -0.25,2"
  151. stroke={bdcolor}
  152. strokeWidth={1}
  153. fill="none"
  154. strokeDasharray={100}
  155. />
  156. </marker>
  157. </defs>
  158. ) : null}
  159. <line
  160. x1={startPoint.x}
  161. y1={startPoint.y}
  162. x2={endPoint.x}
  163. y2={endPoint.y}
  164. stroke={bdcolor}
  165. strokeWidth={actualbdwidth}
  166. strokeOpacity={transparency}
  167. markerEnd={is_arrow ? `url(#${uuid})` : ''}
  168. />
  169. </SVG>
  170. </AnnotationContainer>
  171. {!isCollapse ? (
  172. <Outer
  173. top={rect.top}
  174. left={rect.left}
  175. width={rect.width}
  176. height={rect.height}
  177. start={startPoint}
  178. end={endPoint}
  179. onMove={handleMove}
  180. onMouseUp={handleMouseUp}
  181. />
  182. ) : (
  183. ''
  184. )}
  185. </>
  186. );
  187. };
  188. export default Line;