feat: Add PDF viewer and preview components with styling and functionality
- 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.
This commit is contained in:
108
ts_web/elements/dees-pdf-shared/PdfManager.ts
Normal file
108
ts_web/elements/dees-pdf-shared/PdfManager.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
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(),
|
||||
})),
|
||||
};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user