Annotation.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import React, { useEffect, useState } from 'react';
  2. import { AnnotationType, OnUpdateType } from '../constants/type';
  3. import AnnotationWrapper from '../components/AnnotationWrapper';
  4. import Highlight from '../components/Highlight';
  5. import Ink from '../components/Ink';
  6. import FreeText from '../components/FreeText';
  7. import StickyNote from '../components/StickyNote';
  8. import Shape from '../components/Shape';
  9. import Line from '../components/Line';
  10. import DeleteDialog from '../components/DeleteDialog';
  11. import useCursorPosition from '../hooks/useCursorPosition';
  12. import useStore from '../store';
  13. import useActions from '../actions';
  14. type Props = AnnotationType & {
  15. index: number;
  16. scale: number;
  17. };
  18. const Annotation: React.FC<Props> = ({
  19. obj_type,
  20. obj_attr,
  21. index,
  22. scale,
  23. }: Props) => {
  24. const [isCollapse, setCollapse] = useState(true);
  25. const [isEdit, setEdit] = useState(false);
  26. const [isCovered, setMouseOver] = useState(false);
  27. const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
  28. const [openDialog, setDialog] = useState(false);
  29. const [cursorPosition, ref] = useCursorPosition();
  30. const [{ viewport, annotations }, dispatch] = useStore();
  31. const { updateAnnots } = useActions(dispatch);
  32. const handleClick = (): void => {
  33. if (isCollapse && !isEdit) {
  34. setCollapse(false);
  35. setMousePosition({
  36. x: cursorPosition.x || 0,
  37. y: cursorPosition.y || 0,
  38. });
  39. }
  40. };
  41. const handleMouseOver = (): void => {
  42. setMouseOver(true);
  43. };
  44. const handleMouseOut = (): void => {
  45. setMouseOver(false);
  46. };
  47. const handleUpdate: OnUpdateType = (data) => {
  48. const newAttributes = {
  49. ...annotations[index].obj_attr,
  50. ...data,
  51. isInit: false,
  52. };
  53. annotations[index].obj_attr = newAttributes;
  54. updateAnnots(annotations);
  55. };
  56. const handleEdit = (): void => {
  57. setEdit(true);
  58. setCollapse(true);
  59. };
  60. const deleteDialogToggle = (): void => {
  61. setDialog(!openDialog);
  62. };
  63. const handleDelete = (): void => {
  64. annotations.splice(index, 1);
  65. setDialog(false);
  66. updateAnnots(annotations);
  67. };
  68. const handleBlur = (): void => {
  69. setCollapse(true);
  70. };
  71. const handleInputBlur = (): void => {
  72. setEdit(false);
  73. if (obj_type === 'FreeText' && !obj_attr.content) {
  74. handleDelete();
  75. }
  76. };
  77. const handleKeyDown = (e: React.KeyboardEvent): void => {
  78. if (e.keyCode === 46) {
  79. deleteDialogToggle();
  80. }
  81. };
  82. useEffect(() => {
  83. if (obj_type === 'FreeText' && !obj_attr.content) {
  84. setEdit(true);
  85. }
  86. }, [obj_type, obj_attr]);
  87. const Component = (type: string): React.ReactNode => {
  88. const childProps = {
  89. obj_type,
  90. obj_attr,
  91. scale,
  92. isCollapse,
  93. isCovered,
  94. mousePosition,
  95. onUpdate: handleUpdate,
  96. onDelete: deleteDialogToggle,
  97. viewport,
  98. onEdit: handleEdit,
  99. isEdit,
  100. onBlur: handleInputBlur,
  101. };
  102. switch (type) {
  103. case 'Ink':
  104. return <Ink {...childProps} />;
  105. case 'FreeText':
  106. return <FreeText {...childProps} />;
  107. case 'Text':
  108. return <StickyNote {...childProps} />;
  109. case 'Square':
  110. case 'Circle':
  111. return <Shape {...childProps} />;
  112. case 'Line':
  113. case 'Arrow':
  114. return <Line {...childProps} />;
  115. default:
  116. return <Highlight {...childProps} />;
  117. }
  118. };
  119. const wrapperProps = {
  120. onBlur: handleBlur,
  121. onMouseDown: handleClick,
  122. onMouseOver: handleMouseOver,
  123. onMouseOut: handleMouseOut,
  124. onKeyDown: handleKeyDown,
  125. };
  126. return (
  127. <AnnotationWrapper
  128. ref={ref}
  129. {...wrapperProps}
  130. >
  131. {Component(obj_type)}
  132. <DeleteDialog
  133. open={openDialog}
  134. onCancel={deleteDialogToggle}
  135. onDelete={handleDelete}
  136. />
  137. </AnnotationWrapper>
  138. );
  139. };
  140. export default Annotation;