Annotation.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import React, { useEffect, useState } from 'react';
  2. import AnnotationWrapper from '../components/AnnotationWrapper';
  3. import Highlight from '../components/Highlight';
  4. import Ink from '../components/Ink';
  5. import FreeText from '../components/FreeText';
  6. import StickyNote from '../components/StickyNote';
  7. import Shape from '../components/Shape';
  8. import Line from '../components/Line';
  9. import DeleteDialog from '../components/DeleteDialog';
  10. import useCursorPosition from '../hooks/useCursorPosition';
  11. import useStore from '../store';
  12. import useActions from '../actions';
  13. type Props = AnnotationType & {
  14. index: number;
  15. scale: number;
  16. };
  17. const Annotation: React.FC<Props> = ({
  18. id,
  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.key === 'Delete') {
  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 childProps = {
  88. id,
  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. const wrapperProps = {
  103. onBlur: handleBlur,
  104. onMouseDown: handleClick,
  105. onMouseOver: handleMouseOver,
  106. onMouseOut: handleMouseOut,
  107. onKeyDown: handleKeyDown,
  108. };
  109. return (
  110. <AnnotationWrapper ref={ref} {...wrapperProps}>
  111. {((): React.ReactNode => {
  112. switch (obj_type) {
  113. case 'Ink':
  114. return <Ink {...childProps} />;
  115. case 'FreeText':
  116. return <FreeText {...childProps} />;
  117. case 'Text':
  118. return <StickyNote {...childProps} />;
  119. case 'Square':
  120. case 'Circle':
  121. return <Shape {...childProps} />;
  122. case 'Line':
  123. case 'Arrow':
  124. return <Line {...childProps} />;
  125. default:
  126. return <Highlight {...childProps} />;
  127. }
  128. })()}
  129. {openDialog && (
  130. <DeleteDialog onCancel={deleteDialogToggle} onDelete={handleDelete} />
  131. )}
  132. </AnnotationWrapper>
  133. );
  134. };
  135. export default Annotation;