Add comprehensive PDF reader enhancements
- pdf-page-sizes.ts: Dynamic page sizing and layout detection - pdf-rotation.ts: Page rotation with orientation detection - pdf-minimap.ts: Thumbnail minimap for navigation - pdf-dual-page.ts: Dual page spread support - pdf-links.ts: Clickable link handling - pdf-clipbooard.ts: Copy to clipboard functionality - pdf-bookmarks.ts: Bookmark management - pdf-outline.ts: Document outline/TOC integration - pdf-text-selection.ts: Text selection and highlighting - page-cache.ts: PDF page caching system - pdf-search.ts: Full-text search within PDF - pdf-navigation.ts: Navigation controls and history - annotation-layer.ts: PDF annotation rendering - text-layer-renderer.ts: Text layer overlay rendering - pdfjs-wrapper.ts: PDF.js wrapper with utilities
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
// Annotation layer for rendering highlights and notes on PDFs
|
||||
// Procedural style: Functions, not classes
|
||||
|
||||
interface PDFHighlight {
|
||||
id: string;
|
||||
pageNumber: number;
|
||||
rects: DOMRect[];
|
||||
text: string;
|
||||
color: string;
|
||||
noteId?: string;
|
||||
}
|
||||
|
||||
const highlights = new Map<string, HTMLElement>();
|
||||
|
||||
export function renderPDFHighlights(
|
||||
container: HTMLElement,
|
||||
highlightList: PDFHighlight[],
|
||||
): void {
|
||||
// Clear existing highlights
|
||||
clearPDFHighlights(container);
|
||||
|
||||
for (const highlight of highlightList) {
|
||||
renderSinglePDFHighlight(container, highlight);
|
||||
}
|
||||
}
|
||||
|
||||
function renderSinglePDFHighlight(
|
||||
container: HTMLElement,
|
||||
highlight: PDFHighlight,
|
||||
): void {
|
||||
const overlay = document.createElement("div");
|
||||
overlay.className = "pdf-highlight-annotation";
|
||||
overlay.dataset.highlightId = highlight.id;
|
||||
overlay.style.backgroundColor = parseColor(highlight.color);
|
||||
|
||||
// Position highlight rectangles
|
||||
for (const rect of highlight.rects) {
|
||||
const rectDiv = document.createElement("div");
|
||||
rectDiv.className = "pdf-highlight-rect";
|
||||
rectDiv.style.left = `${rect.left}px`;
|
||||
rectDiv.style.top = `${rect.top}px`;
|
||||
rectDiv.style.width = `${rect.width}px`;
|
||||
rectDiv.style.height = `${rect.height}px`;
|
||||
|
||||
overlay.appendChild(rectDiv);
|
||||
}
|
||||
|
||||
// Add click handler for note popup
|
||||
if (highlight.noteId) {
|
||||
overlay.style.cursor = "pointer";
|
||||
overlay.addEventListener("click", () => {
|
||||
showNotePopup(highlight);
|
||||
});
|
||||
}
|
||||
|
||||
// Add hover effect
|
||||
overlay.addEventListener("mouseenter", () => {
|
||||
overlay.style.opacity = "0.8";
|
||||
});
|
||||
|
||||
overlay.addEventListener("mouseleave", () => {
|
||||
overlay.style.opacity = "0.5";
|
||||
});
|
||||
|
||||
container.appendChild(overlay);
|
||||
highlights.set(highlight.id, overlay);
|
||||
}
|
||||
|
||||
function parseColor(color: string): string {
|
||||
if (color.startsWith("#")) {
|
||||
const hex = color.slice(1);
|
||||
const r = parseInt(hex.slice(0, 2), 16);
|
||||
const g = parseInt(hex.slice(2, 4), 16);
|
||||
const b = parseInt(hex.slice(4, 6), 16);
|
||||
return `rgba(${r}, ${g}, ${b}, 0.4)`;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
function showNotePopup(highlight: PDFHighlight): void {
|
||||
console.log("Show note for highlight:", highlight.id);
|
||||
}
|
||||
|
||||
export function clearPDFHighlights(container: HTMLElement): void {
|
||||
highlights.forEach((element) => element.remove());
|
||||
highlights.clear();
|
||||
}
|
||||
|
||||
export function removePDFHighlight(highlightId: string): void {
|
||||
const element = highlights.get(highlightId);
|
||||
if (element) {
|
||||
element.remove();
|
||||
highlights.delete(highlightId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user