FreeTextTool.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import React, { useEffect, useState, useCallback } from 'react';
  2. import { ANNOTATION_TYPE } from '../constants';
  3. import Icon from '../components/Icon';
  4. import Button from '../components/Button';
  5. import ExpansionPanel from '../components/ExpansionPanel';
  6. import FreeTextOption from '../components/FreeTextOption';
  7. import { getAbsoluteCoordinate } from '../helpers/position';
  8. import {
  9. parseAnnotationObject,
  10. appendUserIdAndDate,
  11. } from '../helpers/annotation';
  12. import useActions from '../actions';
  13. import useStore from '../store';
  14. type Props = {
  15. title: string;
  16. isActive: boolean;
  17. onClick: () => void;
  18. };
  19. const HighlightTool: React.FC<Props> = ({
  20. title,
  21. isActive,
  22. onClick,
  23. }: Props) => {
  24. const [data, setData] = useState({
  25. fontName: 'Helvetica',
  26. fontSize: 18,
  27. align: 'left',
  28. fontStyle: '',
  29. color: '#FBB705',
  30. opacity: 100,
  31. });
  32. const [{ viewport, scale }, dispatch] = useStore();
  33. const { addAnnots } = useActions(dispatch);
  34. const setDataState = (obj: OptionPropsType): void => {
  35. setData((prev) => ({
  36. ...prev,
  37. ...obj,
  38. }));
  39. };
  40. const addFreeText = (
  41. pageEle: HTMLElement,
  42. event: MouseEvent | TouchEvent,
  43. attributes: OptionPropsType,
  44. ): void => {
  45. const {
  46. fontStyle,
  47. fontName,
  48. fontSize = 0,
  49. opacity,
  50. color,
  51. align,
  52. } = attributes;
  53. const pageNum = pageEle.getAttribute('data-page-num') || 0;
  54. const coordinate = getAbsoluteCoordinate(pageEle, event);
  55. const annotData = {
  56. obj_type: ANNOTATION_TYPE.freetext,
  57. obj_attr: {
  58. page: pageNum as number,
  59. position: {
  60. top: coordinate.y,
  61. left: coordinate.x,
  62. bottom: coordinate.y + fontSize * scale,
  63. right: coordinate.x + 30,
  64. },
  65. transparency: opacity,
  66. fontname: fontStyle ? `${fontName}-${fontStyle}` : fontName,
  67. fontsize: fontSize,
  68. textcolor: color,
  69. align,
  70. content: '',
  71. },
  72. };
  73. const freeText = appendUserIdAndDate(
  74. parseAnnotationObject(annotData, viewport.height, scale),
  75. );
  76. addAnnots([freeText]);
  77. };
  78. const handleMouseDown = useCallback(
  79. (event: MouseEvent | TouchEvent): void => {
  80. const pageEle = (event.target as HTMLElement).parentNode as HTMLElement;
  81. if (pageEle.hasAttribute('data-page-num')) {
  82. addFreeText(pageEle, event, data);
  83. }
  84. },
  85. [data, viewport, scale],
  86. );
  87. useEffect(() => {
  88. const pdfViewer = document.getElementById('pdf_viewer') as HTMLDivElement;
  89. if (isActive && pdfViewer) {
  90. pdfViewer.addEventListener('mousedown', handleMouseDown);
  91. pdfViewer.addEventListener('touchstart', handleMouseDown);
  92. }
  93. return (): void => {
  94. if (pdfViewer) {
  95. pdfViewer.removeEventListener('mousedown', handleMouseDown);
  96. pdfViewer.removeEventListener('touchstart', handleMouseDown);
  97. }
  98. };
  99. }, [isActive, handleMouseDown]);
  100. const Label = (
  101. <Button
  102. shouldFitContainer
  103. align="left"
  104. onClick={onClick}
  105. isActive={isActive}
  106. >
  107. <Icon glyph="text" style={{ marginRight: '10px' }} />
  108. {title}
  109. </Button>
  110. );
  111. return (
  112. <ExpansionPanel label={Label} isActive={isActive} showBottomBorder>
  113. <FreeTextOption {...data} setDataState={setDataState} />
  114. </ExpansionPanel>
  115. );
  116. };
  117. export default HighlightTool;