npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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-js

Note: 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 map
  • config - Viewer configuration with tile URL and image info
  • mapOptions - Optional map options (center, zoom, etc.)

Throws:

  • Error if container is not provided or invalid
  • Error if config is not provided or invalid
  • Error if tileUrl is missing
  • Error if 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:

  • Error if 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 object
  • options - Optional focus options
    • zoom?: 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 text
  • options.description?: string - Marker description
  • options.href?: string - Link URL (optional)
  • options.target?: string - Link target (optional)
  • options.showLabel?: boolean - Show label/tooltip
  • options.id?: string - Custom marker ID (auto-generated if not provided)
  • options.iconType?: 'pin-gray' | 'pin-yellow' - Icon type for the marker
  • options.referenceId?: string - Reference ID for linking to external systems
  • options.draggable?: boolean - Enable dragging for this specific marker
  • options.editable?: boolean - Enable editing for this specific marker
  • options.deletable?: boolean - Enable deleting for this specific marker

Returns: The created marker

Throws:

  • Error if neither position nor imageCoords is provided
  • Error if 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 ID
  • updates - 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 ID
  • position - 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 import
  • options - Import options
    • clearExisting?: 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 markers
  • config.selectable?: boolean - Enable selecting markers
  • config.showTooltips?: boolean - Show tooltips on hover
  • config.showPopups?: boolean - Show popups on click
  • config.multiSelect?: boolean - Allow multiple marker selection
  • config.showEditButton?: boolean - Show edit button in popups
  • config.showDeleteButton?: boolean - Show delete button in popups
  • config.onEdit?: (marker: Marker) => Promise<Marker | null> - Custom edit handler
  • config.onDelete?: (marker: Marker) => Promise<boolean> - Custom delete handler
  • config.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 object
  • options - Optional focus options
    • zoom?: number - Target zoom level
    • animate?: 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 level
  • options.animate?: boolean - Whether to animate the zoom (default: true)

Throws:

  • Error if 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 element
  • zoomController - Zoom controller instance
  • options - Optional configuration
    • position?: 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 icon
  • pin-gray.png - Gray pin icon
  • pin-yellow.png - Yellow pin icon
  • pin-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 location

Customizing 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);
});