Annotation.tsx 3.8 KB

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