@edgepdf/viewer-js
v0.3.2
Published
EdgePDF Viewer - JavaScript library for viewing PDF documents with interactive markers and zoom controls
Readme
@edgepdf/viewer-js
A powerful, self-contained JavaScript library for viewing large PDF documents in the browser. Provides smooth navigation, zoom controls, and interactive marker management without requiring any external dependencies.
Installation
npm install @edgepdf/viewer-js
# or
pnpm add @edgepdf/viewer-js
# or
yarn add @edgepdf/viewer-jsNote: All dependencies are bundled with this library. CSS styles are automatically injected when you import the library - no manual CSS import needed!
Features
- ⚡ Zero Configuration: Works out of the box with sensible defaults
- 📦 Self-Contained: All dependencies bundled - no external CSS or scripts needed
- 🎯 Precise Control: Programmatic zoom, pan, and focus capabilities
- 📍 Rich Markers: Support for draggable, editable markers with tooltips and custom icons
- 🔄 Data Management: Import/export marker data for persistence
- 🎨 Customizable: Flexible API for styling and behavior customization
- 📱 Touch-Friendly: Full support for touch gestures on mobile devices
- ♿ Accessible: Keyboard navigation and ARIA labels included
Quick Start
Basic Example
import { EdgePdfViewer } from '@edgepdf/viewer-js';
import type { ViewerConfig } from '@edgepdf/types';
// Get container
const container = document.getElementById('map-container');
// Configure viewer
const config: ViewerConfig = {
tileUrl: 'https://example.com/tiles/{z}/{x}/{y}.png',
imageInfo: {
width: 2000,
height: 3000,
tileSize: 256,
maxZoom: 5,
minZoom: 0,
},
};
// Create and initialize viewer
const viewer = new EdgePdfViewer({ container, config });
viewer.initialize();
// Access marker manager
const markerManager = viewer.getMarkerManager();
if (markerManager) {
// Create a marker
const marker = markerManager.createMarker({
position: [1500, 1000], // [y, x] coordinates
label: 'My Marker',
});
}
// Cleanup when done
viewer.dispose();With Custom Map Options
import { EdgePdfViewer } from '@edgepdf/viewer-js';
import type { ViewerConfig, MapOptions } from '@edgepdf/types';
const config: ViewerConfig = {
tileUrl: 'https://example.com/tiles/{z}/{x}/{y}.png',
imageInfo: {
width: 2000,
height: 3000,
tileSize: 256,
maxZoom: 5,
minZoom: 0,
},
};
const mapOptions: MapOptions = {
center: [1500, 1000], // [y, x] in pixel coordinates
zoom: 2,
minZoom: 0,
maxZoom: 5,
};
const viewer = new EdgePdfViewer({
container: document.getElementById('map-container'),
config,
mapOptions,
});
viewer.initialize();API Reference
EdgePdfViewer
Main class for initializing and managing interactive map instances for PDF viewing.
Constructor
new EdgePdfViewer(options: {
container: HTMLElement;
config: ViewerConfig;
mapOptions?: MapOptions;
})Parameters:
container- HTML element that will contain the mapconfig- Viewer configuration with tile URL and image infomapOptions- Optional map options (center, zoom, etc.)
Throws:
Errorif container is not provided or invalidErrorif config is not provided or invalidErrorif tileUrl is missingErrorif imageInfo is missing
Methods
initialize(): void
Initializes the viewer and prepares it for displaying the PDF document. Call this method after creating the viewer instance.
Throws:
Errorif initialization fails
getMap(): L.Map | null
Gets the map instance.
Returns: The map instance, or null if not initialized
isInitialized(): boolean
Checks if the map is initialized.
Returns: true if map is initialized, false otherwise
getTileLayerManager(): TileLayerManager | null
Gets the tile layer manager instance.
Returns: The tile layer manager, or null if not created
getCoordinateMapper(): CoordinateMapper | null
Gets the coordinate mapper instance.
Returns: The coordinate mapper, or null if not created
getZoomController(): ZoomController | null
Gets the zoom controller instance.
Returns: The zoom controller, or null if not created
getMarkerManager(): MarkerManager | null
Gets the marker manager instance.
Returns: The marker manager, or null if not created
focusMarker(markerOrId: string | Marker, options?: FocusOptions): boolean
Focuses on a marker by panning and zooming to its position.
Parameters:
markerOrId- Marker ID string or Marker objectoptions- Optional focus optionszoom?: number- Target zoom level (uses marker's zoom or default if not provided)animate?: boolean- Whether to animate the transition (default: true)duration?: number- Animation duration in seconds (default: 0.5)offsetLeft?: number- Pixel offset to move focus marker to the left (default: 0)offsetRight?: number- Pixel offset to move focus marker to the right (default: 0)offsetTop?: number- Pixel offset to move focus marker upward (default: 0)offsetBottom?: number- Pixel offset to move focus marker downward (default: 0)
Returns: true if focus was successful, false if marker not found or viewer not initialized
Example:
// Focus with offset to account for overlay
viewer.focusMarker('marker-123', { offsetLeft: 100, offsetTop: 50 });dispose(): void
Disposes of the map instance and cleans up resources. This should be called when the viewer is no longer needed to prevent memory leaks and event listener issues.
MarkerManager
Manages markers on the interactive map. Access via viewer.getMarkerManager().
Methods
createMarker(options: CreateMarkerOptions): Marker
Creates a new marker from coordinates.
Parameters:
options.position?: ViewerCoords- Map coordinates [y, x]options.imageCoords?: ImageCoords- Image pixel coordinates {x, y}options.label?: string- Marker label/tooltip textoptions.description?: string- Marker descriptionoptions.href?: string- Link URL (optional)options.target?: string- Link target (optional)options.showLabel?: boolean- Show label/tooltipoptions.id?: string- Custom marker ID (auto-generated if not provided)options.iconType?: 'pin-gray' | 'pin-yellow'- Icon type for the markeroptions.referenceId?: string- Reference ID for linking to external systemsoptions.draggable?: boolean- Enable dragging for this specific markeroptions.editable?: boolean- Enable editing for this specific markeroptions.deletable?: boolean- Enable deleting for this specific marker
Returns: The created marker
Throws:
Errorif neither position nor imageCoords is providedErrorif coordinates are invalid or out of bounds
getMarker(id: string): Marker | null
Gets a marker by ID.
Returns: The marker, or null if not found
getAllMarkers(): Marker[]
Gets all markers.
Returns: Array of all markers
getMarkerCount(): number
Gets the total number of markers.
Returns: Number of markers
hasMarker(id: string): boolean
Checks if a marker exists.
Returns: true if marker exists, false otherwise
updateMarker(id: string, updates: Partial<Marker>): boolean
Updates a marker's properties.
Parameters:
id- Marker IDupdates- Partial marker object with properties to update
Returns: true if marker was updated, false if not found
updateMarkerPosition(id: string, position: ViewerCoords): boolean
Updates a marker's position.
Parameters:
id- Marker IDposition- New map coordinates [y, x]
Returns: true if marker was updated, false if not found
updateMarkerIcon(id: string, iconType: 'pin-gray' | 'pin-yellow'): boolean
Updates the icon type for a specific marker.
Returns: true if marker was updated, false if not found
updateAllMarkerIcons(iconType: 'pin-gray' | 'pin-yellow'): void
Updates all markers to use a new icon type.
removeMarker(id: string): boolean
Removes a marker by ID.
Returns: true if marker was removed, false if not found
removeAllMarkers(): void
Removes all markers.
deleteMarker(id: string): boolean
Deletes a marker by ID (triggers delete event).
Returns: true if marker was deleted, false if not found
exportMarkers(): MarkerData
Exports all markers as JSON data.
Returns: MarkerData object containing all markers and metadata
importMarkers(data: MarkerData, options?: ImportOptions): ImportResult
Imports markers from MarkerData.
Parameters:
data- MarkerData object to importoptions- Import optionsclearExisting?: boolean- If true, removes all existing markers before import (default: false)validateCoordinates?: boolean- If true, validates coordinates are within bounds (default: true)
Returns: Import result with success status and details
setInteractionConfig(config: Partial<MarkerInteractionConfig>): void
Sets marker interaction configuration.
Parameters:
config.draggable?: boolean- Enable dragging markersconfig.selectable?: boolean- Enable selecting markersconfig.showTooltips?: boolean- Show tooltips on hoverconfig.showPopups?: boolean- Show popups on clickconfig.multiSelect?: boolean- Allow multiple marker selectionconfig.showEditButton?: boolean- Show edit button in popupsconfig.showDeleteButton?: boolean- Show delete button in popupsconfig.onEdit?: (marker: Marker) => Promise<Marker | null>- Custom edit handlerconfig.onDelete?: (marker: Marker) => Promise<boolean>- Custom delete handlerconfig.onActiveMarkerChange?: (marker: Marker | null) => void- Active marker change callback
getInteractionConfig(): MarkerInteractionConfig
Gets the current interaction configuration.
Returns: Current interaction configuration
selectMarker(id: string): boolean
Selects a marker.
Returns: true if marker was selected, false if not found
deselectMarker(id: string): boolean
Deselects a marker.
Returns: true if marker was deselected, false if not found
deselectAllMarkers(): void
Deselects all markers.
getSelectionState(): MarkerSelectionState
Gets the current selection state.
Returns: Selection state object with selected IDs and count
isMarkerSelected(id: string): boolean
Checks if a marker is selected.
Returns: true if marker is selected, false otherwise
setActiveMarker(id: string | null): boolean
Sets the active marker (for popup management).
Returns: true if active marker was set, false if marker not found
getActiveMarker(): Marker | null
Gets the currently active marker.
Returns: The active marker, or null if no marker is active
focusMarker(markerOrId: string | Marker, options?: FocusOptions): boolean
Focuses on a marker by panning and zooming to its position.
Parameters:
markerOrId- Marker ID string or Marker objectoptions- Optional focus optionszoom?: number- Target zoom levelanimate?: boolean- Whether to animate (default: true)duration?: number- Animation duration in seconds (default: 0.5)offsetLeft?: number- Pixel offset to move focus marker to the left (default: 0)offsetRight?: number- Pixel offset to move focus marker to the right (default: 0)offsetTop?: number- Pixel offset to move focus marker upward (default: 0)offsetBottom?: number- Pixel offset to move focus marker downward (default: 0)
Returns: true if focus was successful, false if marker not found
Example:
// Focus with offset to account for overlay
markerManager.focusMarker('marker-123', { offsetLeft: 100, offsetTop: 50 });setDefaultIconType(iconType: 'pin-gray' | 'pin-yellow'): void
Sets the default icon type for new markers.
getDefaultIconType(): 'pin-gray' | 'pin-yellow'
Gets the current default icon type.
Returns: Current default icon type
setIconBasePath(basePath: string): void
Sets the base path for marker icons.
Example:
// Use library's built-in icons (default)
markerManager.setIconBasePath('./images/');
// Use custom icons from public folder
markerManager.setIconBasePath('/');
// Use icons from a CDN
markerManager.setIconBasePath('https://cdn.example.com/icons/');getIconBasePath(): string
Gets the current base path for marker icons.
Returns: The current icon base path
on(eventType: MarkerEventType, callback: (event: MarkerEvent) => void): () => void
Registers an event listener.
Parameters:
eventType- Event type: 'click' | 'dragstart' | 'drag' | 'dragend' | 'edit' | 'delete'callback- Callback function
Returns: Unsubscribe function
Example:
const unsubscribe = markerManager.on('click', (event) => {
console.log('Marker clicked:', event.marker.id);
});
// Later, to unsubscribe:
unsubscribe();off(eventType: MarkerEventType, callback: (event: MarkerEvent) => void): void
Unregisters an event listener.
removeAllListeners(eventType?: MarkerEventType): void
Removes all event listeners for a specific event type, or all events if no type is provided.
dispose(): void
Disposes of the marker manager and cleans up resources.
ZoomController
Manages zoom state and operations. Access via viewer.getZoomController().
Methods
zoomIn(options?: { animate?: boolean }): boolean
Zooms in by one level.
Parameters:
options.animate?: boolean- Whether to animate the zoom (default: true)
Returns: true if zoomed in, false if already at max zoom
zoomOut(options?: { animate?: boolean }): boolean
Zooms out by one level.
Parameters:
options.animate?: boolean- Whether to animate the zoom (default: true)
Returns: true if zoomed out, false if already at min zoom
setZoom(zoom: number, options?: { animate?: boolean }): void
Sets a specific zoom level.
Parameters:
zoom- Target zoom leveloptions.animate?: boolean- Whether to animate the zoom (default: true)
Throws:
Errorif zoom is not a finite number
getZoom(): number
Gets the current zoom level.
Returns: Current zoom level
getZoomState(): ZoomState
Gets the current zoom state.
Returns: Zoom state object with currentZoom, minZoom, maxZoom
getMinZoom(): number
Gets the minimum zoom level.
Returns: Minimum zoom level
getMaxZoom(): number
Gets the maximum zoom level.
Returns: Maximum zoom level
canZoomIn(): boolean
Checks if can zoom in.
Returns: true if can zoom in, false otherwise
canZoomOut(): boolean
Checks if can zoom out.
Returns: true if can zoom out, false otherwise
onZoomChange(listener: (state: ZoomState) => void): () => void
Registers a zoom change listener.
Returns: Unsubscribe function
removeAllListeners(): void
Removes all zoom change listeners.
dispose(): void
Disposes of the zoom controller and cleans up resources.
Utility Functions
createZoomControls(container: HTMLElement, zoomController: ZoomController, options?: ZoomControlsOptions): HTMLElement
Creates zoom control buttons (zoom in/out) in the specified container.
Parameters:
container- Container elementzoomController- Zoom controller instanceoptions- Optional configurationposition?: ZoomControlsPosition- Position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' (default: 'top-right')
Returns: The created controls element
Configuration
ViewerConfig
interface ViewerConfig {
tileUrl: string; // Tile URL template with {z}, {x}, {y} placeholders
imageInfo: ImageInfo; // Image metadata
onPinsUpdate?: (pins: Marker[]) => void; // Optional callback for marker updates
originalImagePath?: string; // Optional original image path
}ImageInfo
interface ImageInfo {
width: number; // Original image width in pixels
height: number; // Original image height in pixels
tileSize: number; // Tile size in pixels (default: 256)
maxZoom: number; // Maximum zoom level
minZoom: number; // Minimum zoom level
}MapOptions
interface MapOptions {
center?: [number, number]; // Initial center coordinates [y, x]
zoom?: number; // Initial zoom level
minZoom?: number; // Minimum zoom level
maxZoom?: number; // Maximum zoom level
bounds?: {
southwest: [number, number];
northeast: [number, number];
};
}Marker Icons
The library includes built-in pin icons that are automatically available in the dist/images/ folder:
pin.png- Default pin iconpin-gray.png- Gray pin iconpin-yellow.png- Yellow pin iconpin-gray-selected.png- Gray pin (selected state)pin-yellow-selected.png- Yellow pin (selected state)
Using Built-in Icons
By default, the MarkerManager uses ./images/ as the icon base path. To use the built-in icons:
const viewer = new EdgePdfViewer({ container, config });
viewer.initialize();
const markerManager = viewer.getMarkerManager();
// Icons are automatically loaded from the library's dist/images/ folder
// No configuration needed if serving from the library locationCustomizing Icons
To use custom icons, copy the icon files from node_modules/@edgepdf/viewer-js/dist/images/ to your public folder, customize them, and set the icon base path:
const markerManager = viewer.getMarkerManager();
// Option 1: Serve from your public folder (recommended for customization)
markerManager.setIconBasePath('/'); // Icons in public/ folder
// Option 2: Use a CDN
markerManager.setIconBasePath('https://cdn.example.com/icons/');
// Option 3: Use relative path
markerManager.setIconBasePath('./assets/icons/');Note: Icon files must be named exactly as listed above (e.g., pin.png, pin-gray.png, etc.) for the library to find them.
Available Icon Types
type IconType = 'pin-gray' | 'pin-yellow';Coordinate System
The viewer uses a simple pixel-based coordinate system for positioning markers:
- Format:
[y, x]- array with vertical position first, horizontal position second - Range: X from 0 to image width, Y from 0 to image height
- Origin: Top-left corner at
[0, 0]
Note: You can also use image pixel coordinates {x, y} when creating markers - the viewer will automatically convert them to the appropriate format.
Examples
Working with Markers
const viewer = new EdgePdfViewer({ container, config });
viewer.initialize();
const markerManager = viewer.getMarkerManager();
if (!markerManager) return;
// Create a marker
const marker = markerManager.createMarker({
position: [1500, 1000],
label: 'My Marker',
description: 'This is a marker description',
iconType: 'pin-yellow',
});
// Update marker
markerManager.updateMarker(marker.id, {
label: 'Updated Label',
description: 'Updated description',
});
// Listen to marker events
markerManager.on('click', (event) => {
console.log('Marker clicked:', event.marker);
});
markerManager.on('dragend', (event) => {
console.log('Marker dragged to:', event.marker.position);
});
// Export markers
const markerData = markerManager.exportMarkers();
console.log(JSON.stringify(markerData, null, 2));
// Import markers
markerManager.importMarkers(markerData, {
clearExisting: true,
validateCoordinates: true,
});Working with Zoom
const viewer = new EdgePdfViewer({ container, config });
viewer.initialize();
const zoomController = viewer.getZoomController();
if (!zoomController) return;
// Zoom in
zoomController.zoomIn();
// Zoom out
zoomController.zoomOut();
// Set specific zoom level
zoomController.setZoom(3);
// Get zoom state
const zoomState = zoomController.getZoomState();
console.log('Current zoom:', zoomState.currentZoom);
console.log('Min zoom:', zoomState.minZoom);
console.log('Max zoom:', zoomState.maxZoom);
// Listen to zoom changes
zoomController.onZoomChange((state) => {
console.log('Zoom changed to:', state.currentZoom);
});