- Implemented DeesPdfViewer for full-featured PDF viewing with toolbar and sidebar navigation. - Created DeesPdfPreview for lightweight PDF previews. - Introduced PdfManager for managing PDF document loading and caching. - Added CanvasPool for efficient canvas management. - Developed utility functions for performance monitoring and file size formatting. - Established styles for viewer and preview components to enhance UI/UX. - Included demo examples for showcasing PDF viewer capabilities.
108 lines
2.7 KiB
TypeScript
108 lines
2.7 KiB
TypeScript
import { domtools } from '@design.estate/dees-element';
|
|
|
|
interface CachedDocument {
|
|
url: string;
|
|
document: any;
|
|
lastAccessed: number;
|
|
refCount: number;
|
|
}
|
|
|
|
export class PdfManager {
|
|
private static cache = new Map<string, CachedDocument>();
|
|
private static maxCacheSize = 10;
|
|
private static pdfjsLib: any;
|
|
private static initialized = false;
|
|
|
|
public static async initialize() {
|
|
if (this.initialized) return;
|
|
|
|
// @ts-ignore
|
|
this.pdfjsLib = await import('https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.379/+esm');
|
|
this.pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.379/build/pdf.worker.mjs';
|
|
|
|
this.initialized = true;
|
|
}
|
|
|
|
public static async loadDocument(url: string): Promise<any> {
|
|
await this.initialize();
|
|
|
|
// Check cache first
|
|
const cached = this.cache.get(url);
|
|
if (cached) {
|
|
cached.lastAccessed = Date.now();
|
|
cached.refCount++;
|
|
return cached.document;
|
|
}
|
|
|
|
// Load new document
|
|
const loadingTask = this.pdfjsLib.getDocument(url);
|
|
const document = await loadingTask.promise;
|
|
|
|
// Add to cache with LRU eviction if needed
|
|
if (this.cache.size >= this.maxCacheSize) {
|
|
this.evictLeastRecentlyUsed();
|
|
}
|
|
|
|
this.cache.set(url, {
|
|
url,
|
|
document,
|
|
lastAccessed: Date.now(),
|
|
refCount: 1,
|
|
});
|
|
|
|
return document;
|
|
}
|
|
|
|
public static releaseDocument(url: string) {
|
|
const cached = this.cache.get(url);
|
|
if (cached) {
|
|
cached.refCount--;
|
|
if (cached.refCount <= 0) {
|
|
// Don't immediately remove, keep for potential reuse
|
|
cached.refCount = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static evictLeastRecentlyUsed() {
|
|
let oldestTime = Infinity;
|
|
let oldestKey: string | null = null;
|
|
|
|
for (const [key, value] of this.cache.entries()) {
|
|
// Only evict if not currently in use
|
|
if (value.refCount === 0 && value.lastAccessed < oldestTime) {
|
|
oldestTime = value.lastAccessed;
|
|
oldestKey = key;
|
|
}
|
|
}
|
|
|
|
if (oldestKey) {
|
|
const cached = this.cache.get(oldestKey);
|
|
if (cached?.document) {
|
|
cached.document.destroy?.();
|
|
}
|
|
this.cache.delete(oldestKey);
|
|
}
|
|
}
|
|
|
|
public static clearCache() {
|
|
for (const cached of this.cache.values()) {
|
|
if (cached.document) {
|
|
cached.document.destroy?.();
|
|
}
|
|
}
|
|
this.cache.clear();
|
|
}
|
|
|
|
public static getCacheStats() {
|
|
return {
|
|
size: this.cache.size,
|
|
maxSize: this.maxCacheSize,
|
|
entries: Array.from(this.cache.entries()).map(([url, data]) => ({
|
|
url,
|
|
refCount: data.refCount,
|
|
lastAccessed: new Date(data.lastAccessed).toISOString(),
|
|
})),
|
|
};
|
|
}
|
|
} |