Sliding ctx window for string matching highlighting
This commit is contained in:
parent
28fe51c80d
commit
d4b4ad8187
1 changed files with 29 additions and 10 deletions
|
|
@ -199,7 +199,7 @@ export function PDFProvider({ children }: { children: ReactNode }) {
|
||||||
return bestMatch;
|
return bestMatch;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Highlight matching text in the PDF viewer
|
// Highlight matching text in the PDF viewer with sliding context window
|
||||||
const highlightPattern = useCallback((text: string, pattern: string, containerRef: React.RefObject<HTMLDivElement>) => {
|
const highlightPattern = useCallback((text: string, pattern: string, containerRef: React.RefObject<HTMLDivElement>) => {
|
||||||
clearHighlights();
|
clearHighlights();
|
||||||
|
|
||||||
|
|
@ -215,7 +215,27 @@ export function PDFProvider({ children }: { children: ReactNode }) {
|
||||||
text: (node.textContent || '').trim(),
|
text: (node.textContent || '').trim(),
|
||||||
})).filter((node) => node.text.length > 0);
|
})).filter((node) => node.text.length > 0);
|
||||||
|
|
||||||
const bestMatch = findBestTextMatch(allText, cleanPattern, cleanPattern.length * 2);
|
// Calculate the visible area of the container
|
||||||
|
const containerRect = container.getBoundingClientRect();
|
||||||
|
const visibleTop = container.scrollTop;
|
||||||
|
const visibleBottom = visibleTop + containerRect.height;
|
||||||
|
|
||||||
|
// Find nodes within the visible area and a buffer zone
|
||||||
|
const bufferSize = containerRect.height; // One screen height buffer
|
||||||
|
const visibleNodes = allText.filter(({ element }) => {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
const elementTop = rect.top - containerRect.top + container.scrollTop;
|
||||||
|
return elementTop >= (visibleTop - bufferSize) && elementTop <= (visibleBottom + bufferSize);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Search for the best match within the visible area first
|
||||||
|
let bestMatch = findBestTextMatch(visibleNodes, cleanPattern, cleanPattern.length * 2);
|
||||||
|
|
||||||
|
// If no good match found in visible area, search the entire document
|
||||||
|
if (bestMatch.rating < 0.3) {
|
||||||
|
bestMatch = findBestTextMatch(allText, cleanPattern, cleanPattern.length * 2);
|
||||||
|
}
|
||||||
|
|
||||||
const similarityThreshold = bestMatch.lengthDiff < cleanPattern.length * 0.3 ? 0.3 : 0.5;
|
const similarityThreshold = bestMatch.lengthDiff < cleanPattern.length * 0.3 ? 0.3 : 0.5;
|
||||||
|
|
||||||
if (bestMatch.rating >= similarityThreshold) {
|
if (bestMatch.rating >= similarityThreshold) {
|
||||||
|
|
@ -225,18 +245,17 @@ export function PDFProvider({ children }: { children: ReactNode }) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (bestMatch.elements.length > 0) {
|
if (bestMatch.elements.length > 0) {
|
||||||
setTimeout(() => {
|
const element = bestMatch.elements[0];
|
||||||
const element = bestMatch.elements[0];
|
const elementRect = element.getBoundingClientRect();
|
||||||
const container = containerRef.current;
|
const elementTop = elementRect.top - containerRect.top + container.scrollTop;
|
||||||
if (!container || !element) return;
|
|
||||||
|
|
||||||
const containerRect = container.getBoundingClientRect();
|
// Only scroll if the element is outside the visible area
|
||||||
const elementRect = element.getBoundingClientRect();
|
if (elementTop < visibleTop || elementTop > visibleBottom) {
|
||||||
container.scrollTo({
|
container.scrollTo({
|
||||||
top: container.scrollTop + (elementRect.top - containerRect.top) - containerRect.height / 2,
|
top: elementTop - containerRect.height / 3, // Position the highlight in the top third
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
});
|
});
|
||||||
}, 100);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [clearHighlights, findBestTextMatch]);
|
}, [clearHighlights, findBestTextMatch]);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue