From 97ddea37b4364f609fb47b49ffbafd0ac73be2f9 Mon Sep 17 00:00:00 2001 From: Oleksandr Danylchenko Date: Thu, 21 Nov 2024 18:15:18 +0200 Subject: [PATCH 1/3] Revert "Refactoring + removed unused API args" This reverts commit 945c09db538bf6bedfe4740be14bdeb872b275bf. --- .../TextAnnotationPopup/TextAnnotationPopup.tsx | 16 ++++++---------- .../src/state/TextAnnotationStore.ts | 2 +- .../src/state/TextAnnotatorState.ts | 11 ++++++++++- .../text-annotator/src/state/spatialTree.ts | 17 +++++++++++------ .../text-annotator/src/utils/normalizeRects.ts | 9 +++++++++ 5 files changed, 37 insertions(+), 18 deletions(-) create mode 100644 packages/text-annotator/src/utils/normalizeRects.ts diff --git a/packages/text-annotator-react/src/TextAnnotationPopup/TextAnnotationPopup.tsx b/packages/text-annotator-react/src/TextAnnotationPopup/TextAnnotationPopup.tsx index f0493149..6372624c 100644 --- a/packages/text-annotator-react/src/TextAnnotationPopup/TextAnnotationPopup.tsx +++ b/packages/text-annotator-react/src/TextAnnotationPopup/TextAnnotationPopup.tsx @@ -2,6 +2,7 @@ import { ReactNode, useEffect, useMemo, useRef, useState } from 'react'; import { useAnnotator, useSelection } from '@annotorious/react'; import { NOT_ANNOTATABLE_CLASS, + denormalizeRectWithOffset, toDomRectList, type TextAnnotation, type TextAnnotator, @@ -49,12 +50,6 @@ export interface TextAnnotationPopupContentProps { } -const toViewportBounds = (annotationBounds: DOMRect, container: HTMLElement): DOMRect => { - const { left, top, right, bottom } = annotationBounds; - const containerBounds = container.getBoundingClientRect(); - return new DOMRect(left + containerBounds.left, top + containerBounds.top, right - left, bottom - top); -} - export const TextAnnotationPopup = (props: TextAnnotationPopupProps) => { const r = useAnnotator(); @@ -107,16 +102,17 @@ export const TextAnnotationPopup = (props: TextAnnotationPopupProps) => { if (isOpen && annotation?.id) { refs.setPositionReference({ getBoundingClientRect: () => { - // Annotation bounds are relative to the document element const bounds = r.state.store.getAnnotationBounds(annotation.id); return bounds - ? toViewportBounds(bounds, r.element) + ? denormalizeRectWithOffset(bounds, r.element.getBoundingClientRect()) : new DOMRect(); }, getClientRects: () => { const rects = r.state.store.getAnnotationRects(annotation.id); - const viewportRects = rects.map(rect => toViewportBounds(rect, r.element)); - return toDomRectList(viewportRects); + const denormalizedRects = rects.map((rect) => + denormalizeRectWithOffset(rect, r.element.getBoundingClientRect()) + ); + return toDomRectList(denormalizedRects); } }); } else { diff --git a/packages/text-annotator/src/state/TextAnnotationStore.ts b/packages/text-annotator/src/state/TextAnnotationStore.ts index 185f0154..da5b5fdc 100644 --- a/packages/text-annotator/src/state/TextAnnotationStore.ts +++ b/packages/text-annotator/src/state/TextAnnotationStore.ts @@ -13,7 +13,7 @@ export interface TextAnnotationStore getAnnotationRects(id: string): DOMRect[]; - getAnnotationBounds(id: string): DOMRect | undefined; + getAnnotationBounds(id: string, hintX?: number, hintY?: number, buffer?: number): DOMRect | undefined; getAnnotationRects(id: string): DOMRect[]; diff --git a/packages/text-annotator/src/state/TextAnnotatorState.ts b/packages/text-annotator/src/state/TextAnnotatorState.ts index 90301c21..e4b74775 100644 --- a/packages/text-annotator/src/state/TextAnnotatorState.ts +++ b/packages/text-annotator/src/state/TextAnnotatorState.ts @@ -114,9 +114,18 @@ export const createTextAnnotatorState = { + const getAnnotationBounds = (id: string, x?: number, y?: number, buffer = 5): DOMRect | undefined => { const rects = tree.getAnnotationRects(id); if (rects.length === 0) return; + + if (x && y) { + const match = rects.find(({ top, right, bottom, left }) => + x >= left - buffer && x <= right + buffer && y >= top - buffer && y <= bottom + buffer); + + // Preferred bounds: the rectangle + if (match) return match; + } + return tree.getAnnotationBounds(id); } diff --git a/packages/text-annotator/src/state/spatialTree.ts b/packages/text-annotator/src/state/spatialTree.ts index 72552c7b..118ba853 100644 --- a/packages/text-annotator/src/state/spatialTree.ts +++ b/packages/text-annotator/src/state/spatialTree.ts @@ -1,7 +1,12 @@ import RBush from 'rbush'; import type { Store } from '@annotorious/core'; import type { TextAnnotation, TextAnnotationTarget } from '../model'; -import { isRevived, reviveSelector, mergeClientRects } from '../utils'; +import { + isRevived, + reviveSelector, + mergeClientRects, + normalizeRectWithOffset +} from '../utils'; import type { AnnotationRects } from './TextAnnotationStore'; interface IndexedHighlightRect { @@ -37,11 +42,11 @@ export const createSpatialTree = (store: Store, con return Array.from(revivedRange.getClientRects()); }); - const merged = mergeClientRects(rects) - // Offset the merged client rects so that coords - // are relative to the parent container - .map(({ left, top, right, bottom }) => - new DOMRect(left - offset.left, top - offset.top, right - left, bottom - top)); + /** + * Offset the merged client rects so that coords + * are relative to the parent container + */ + const merged = mergeClientRects(rects).map(rect => normalizeRectWithOffset(rect, offset)); return merged.map(rect => { const { x, y, width, height } = rect; diff --git a/packages/text-annotator/src/utils/normalizeRects.ts b/packages/text-annotator/src/utils/normalizeRects.ts new file mode 100644 index 00000000..461f222f --- /dev/null +++ b/packages/text-annotator/src/utils/normalizeRects.ts @@ -0,0 +1,9 @@ +export const normalizeRectWithOffset = (rect: DOMRect, offset: DOMRect): DOMRect => { + const { left, top, right, bottom } = rect; + return new DOMRect(left - offset.left, top - offset.top, right - left, bottom - top); +}; + +export const denormalizeRectWithOffset = (rect: DOMRect, offset: DOMRect): DOMRect => { + const { left, top, right, bottom } = rect; + return new DOMRect(left + offset.left, top + offset.top, right - left, bottom - top); +} From 8ad4fae1cf9193227369381bff350124cdaced6c Mon Sep 17 00:00:00 2001 From: Oleksandr Danylchenko Date: Thu, 21 Nov 2024 18:19:43 +0200 Subject: [PATCH 2/3] Simplified `getAnnotationBounds` --- .../src/state/TextAnnotationStore.ts | 2 +- .../text-annotator/src/state/TextAnnotatorState.ts | 14 ++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/text-annotator/src/state/TextAnnotationStore.ts b/packages/text-annotator/src/state/TextAnnotationStore.ts index da5b5fdc..185f0154 100644 --- a/packages/text-annotator/src/state/TextAnnotationStore.ts +++ b/packages/text-annotator/src/state/TextAnnotationStore.ts @@ -13,7 +13,7 @@ export interface TextAnnotationStore getAnnotationRects(id: string): DOMRect[]; - getAnnotationBounds(id: string, hintX?: number, hintY?: number, buffer?: number): DOMRect | undefined; + getAnnotationBounds(id: string): DOMRect | undefined; getAnnotationRects(id: string): DOMRect[]; diff --git a/packages/text-annotator/src/state/TextAnnotatorState.ts b/packages/text-annotator/src/state/TextAnnotatorState.ts index e4b74775..b2168c3d 100644 --- a/packages/text-annotator/src/state/TextAnnotatorState.ts +++ b/packages/text-annotator/src/state/TextAnnotatorState.ts @@ -114,19 +114,9 @@ export const createTextAnnotatorState = { + const getAnnotationBounds = (id: string): DOMRect | undefined => { const rects = tree.getAnnotationRects(id); - if (rects.length === 0) return; - - if (x && y) { - const match = rects.find(({ top, right, bottom, left }) => - x >= left - buffer && x <= right + buffer && y >= top - buffer && y <= bottom + buffer); - - // Preferred bounds: the rectangle - if (match) return match; - } - - return tree.getAnnotationBounds(id); + return rects.length > 0 ? tree.getAnnotationBounds(id) : undefined; } const getIntersecting = ( From 98532a3c042efe9523d5b008d80710f3d7b0453b Mon Sep 17 00:00:00 2001 From: Oleksandr Danylchenko Date: Thu, 21 Nov 2024 18:43:27 +0200 Subject: [PATCH 3/3] Renamed to the `toParentBounds` & `toViewportBounds` --- .../src/TextAnnotationPopup/TextAnnotationPopup.tsx | 6 +++--- packages/text-annotator/src/state/spatialTree.ts | 4 ++-- packages/text-annotator/src/utils/index.ts | 2 +- .../src/utils/{normalizeRects.ts => rectsToBounds.ts} | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) rename packages/text-annotator/src/utils/{normalizeRects.ts => rectsToBounds.ts} (60%) diff --git a/packages/text-annotator-react/src/TextAnnotationPopup/TextAnnotationPopup.tsx b/packages/text-annotator-react/src/TextAnnotationPopup/TextAnnotationPopup.tsx index 6372624c..f452359a 100644 --- a/packages/text-annotator-react/src/TextAnnotationPopup/TextAnnotationPopup.tsx +++ b/packages/text-annotator-react/src/TextAnnotationPopup/TextAnnotationPopup.tsx @@ -2,7 +2,7 @@ import { ReactNode, useEffect, useMemo, useRef, useState } from 'react'; import { useAnnotator, useSelection } from '@annotorious/react'; import { NOT_ANNOTATABLE_CLASS, - denormalizeRectWithOffset, + toViewportBounds, toDomRectList, type TextAnnotation, type TextAnnotator, @@ -104,13 +104,13 @@ export const TextAnnotationPopup = (props: TextAnnotationPopupProps) => { getBoundingClientRect: () => { const bounds = r.state.store.getAnnotationBounds(annotation.id); return bounds - ? denormalizeRectWithOffset(bounds, r.element.getBoundingClientRect()) + ? toViewportBounds(bounds, r.element.getBoundingClientRect()) : new DOMRect(); }, getClientRects: () => { const rects = r.state.store.getAnnotationRects(annotation.id); const denormalizedRects = rects.map((rect) => - denormalizeRectWithOffset(rect, r.element.getBoundingClientRect()) + toViewportBounds(rect, r.element.getBoundingClientRect()) ); return toDomRectList(denormalizedRects); } diff --git a/packages/text-annotator/src/state/spatialTree.ts b/packages/text-annotator/src/state/spatialTree.ts index 118ba853..d742fb5f 100644 --- a/packages/text-annotator/src/state/spatialTree.ts +++ b/packages/text-annotator/src/state/spatialTree.ts @@ -5,7 +5,7 @@ import { isRevived, reviveSelector, mergeClientRects, - normalizeRectWithOffset + toParentBounds } from '../utils'; import type { AnnotationRects } from './TextAnnotationStore'; @@ -46,7 +46,7 @@ export const createSpatialTree = (store: Store, con * Offset the merged client rects so that coords * are relative to the parent container */ - const merged = mergeClientRects(rects).map(rect => normalizeRectWithOffset(rect, offset)); + const merged = mergeClientRects(rects).map(rect => toParentBounds(rect, offset)); return merged.map(rect => { const { x, y, width, height } = rect; diff --git a/packages/text-annotator/src/utils/index.ts b/packages/text-annotator/src/utils/index.ts index 5d536dd2..599fc737 100644 --- a/packages/text-annotator/src/utils/index.ts +++ b/packages/text-annotator/src/utils/index.ts @@ -14,4 +14,4 @@ export * from './reviveSelector'; export * from './reviveTarget'; export * from './splitAnnotatableRanges'; export * from './trimRangeToContainer'; - +export * from './rectsToBounds'; diff --git a/packages/text-annotator/src/utils/normalizeRects.ts b/packages/text-annotator/src/utils/rectsToBounds.ts similarity index 60% rename from packages/text-annotator/src/utils/normalizeRects.ts rename to packages/text-annotator/src/utils/rectsToBounds.ts index 461f222f..ba9fd14a 100644 --- a/packages/text-annotator/src/utils/normalizeRects.ts +++ b/packages/text-annotator/src/utils/rectsToBounds.ts @@ -1,9 +1,9 @@ -export const normalizeRectWithOffset = (rect: DOMRect, offset: DOMRect): DOMRect => { +export const toParentBounds = (rect: DOMRect, offset: DOMRect): DOMRect => { const { left, top, right, bottom } = rect; return new DOMRect(left - offset.left, top - offset.top, right - left, bottom - top); }; -export const denormalizeRectWithOffset = (rect: DOMRect, offset: DOMRect): DOMRect => { +export const toViewportBounds = (rect: DOMRect, offset: DOMRect): DOMRect => { const { left, top, right, bottom } = rect; return new DOMRect(left + offset.left, top + offset.top, right - left, bottom - top); }