markup.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import { ANNOTATION_TYPE } from '../constants';
  2. import { parseAnnotationObject, appendUserIdAndDate } from './annotation';
  3. type GetMarkupWithSelectionFunc = ({
  4. color,
  5. type,
  6. opacity,
  7. scale,
  8. }: {
  9. color: string;
  10. type: string;
  11. opacity: number;
  12. scale: number;
  13. textLayer: HTMLElement;
  14. }) => AnnotationType | null;
  15. export const getMarkupWithSelection: GetMarkupWithSelectionFunc = ({
  16. color,
  17. type,
  18. opacity,
  19. scale,
  20. textLayer,
  21. }) => {
  22. const selection: Selection | null = document.getSelection();
  23. if (!selection || selection.isCollapsed) return null;
  24. const {
  25. startContainer,
  26. startOffset,
  27. endContainer,
  28. endOffset,
  29. } = selection.getRangeAt(0);
  30. const startElement = startContainer.parentNode as HTMLElement;
  31. const endElement = endContainer.parentNode as HTMLElement;
  32. const startPage = startElement?.parentNode?.parentNode as HTMLElement;
  33. const startPageNum = parseInt(
  34. startPage.getAttribute('data-page-num') as string,
  35. 10,
  36. );
  37. const pageHeight = startPage.offsetHeight;
  38. const startCloneEle = startElement.cloneNode(true) as HTMLElement;
  39. const endCloneEle = endElement.cloneNode(true) as HTMLElement;
  40. const startText = startElement.innerText.substring(0, startOffset);
  41. const endText = endElement.innerText.substring(endOffset);
  42. startCloneEle.innerText = startText;
  43. endCloneEle.innerText = endText;
  44. textLayer.appendChild(startCloneEle);
  45. textLayer.appendChild(endCloneEle);
  46. const startExtraWidth = startCloneEle.getBoundingClientRect().width;
  47. const endExtraWidth = endCloneEle.getBoundingClientRect().width;
  48. textLayer.removeChild(startCloneEle);
  49. textLayer.removeChild(endCloneEle);
  50. const info: AnnotationType = {
  51. obj_type: '',
  52. obj_attr: {
  53. page: 0,
  54. bdcolor: '',
  55. position: [],
  56. transparency: 0,
  57. },
  58. };
  59. const position: PositionType[] = [];
  60. const startRect = startElement.getBoundingClientRect();
  61. const endRect = endElement.getBoundingClientRect();
  62. // left to right and up to down select
  63. let startX = startElement.offsetLeft + startExtraWidth;
  64. let startY = startElement.offsetTop;
  65. let endX = endElement.offsetLeft + endRect.width - endExtraWidth;
  66. let endY = endElement.offsetTop + endRect.height;
  67. if (startX > endX && startY >= endY) {
  68. // right to left and down to up select
  69. startX = endElement.offsetLeft + startExtraWidth;
  70. startY = endElement.offsetTop;
  71. endX = startElement.offsetLeft + startRect.width - endExtraWidth;
  72. endY = startElement.offsetTop + startRect.height;
  73. }
  74. const textElements = Array.prototype.slice.call(textLayer.childNodes);
  75. let inRange = false;
  76. textElements.forEach((ele: HTMLElement) => {
  77. const { height, width } = ele.getBoundingClientRect();
  78. const { offsetTop, offsetLeft } = ele;
  79. const top = offsetTop;
  80. const left = offsetLeft;
  81. const right = offsetLeft + width;
  82. const bottom = offsetTop + height;
  83. const coords = {
  84. top,
  85. bottom,
  86. left,
  87. right,
  88. };
  89. if (startElement === ele && endElement === ele) {
  90. // in same element
  91. coords.left = startX;
  92. coords.right = endX;
  93. position.push(coords);
  94. } else if (startElement === ele) {
  95. // in start element
  96. coords.left = startX;
  97. position.push(coords);
  98. inRange = true;
  99. } else if (endElement === ele) {
  100. // in end element
  101. coords.right = endX;
  102. position.push(coords);
  103. inRange = false;
  104. } else if (inRange) {
  105. // middle element
  106. position.push(coords);
  107. }
  108. });
  109. for (let i = 1; i < position.length; i += 1) {
  110. if (
  111. position[i].top >= position[i - 1].top - 4 &&
  112. position[i].bottom <= position[i - 1].bottom + 4
  113. ) {
  114. position[i - 1].right = position[i].left;
  115. }
  116. }
  117. info.obj_type = ANNOTATION_TYPE[type];
  118. info.obj_attr = {
  119. page: startPageNum,
  120. bdcolor: color,
  121. position,
  122. transparency: opacity,
  123. };
  124. return appendUserIdAndDate(parseAnnotationObject(info, pageHeight, scale));
  125. };
  126. export default getMarkupWithSelection;