FreeTextTools.tsx 3.3 KB

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