FreeTextTools.tsx 3.2 KB

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