Easy Web PDF Viewer With jQuery And pdf.js - pdfjs-viewer
File Size: | 199 KB |
---|---|
Views Total: | 25914 |
Last Update: | |
Publish Date: | |
Official Website: | Go to website |
License: | MIT |
As web developers, we are always on the lookout for new ways to improve our user's experience. That's why I'm excited to share with you a new jQuery plugin called pdfjs-viewer.
This plugin is based on mozilla's pdf.js library, and provides a simple way for your users to view PDF documents directly in their web browser.
In this tutorial, I'll show you how to install and use the pdfjs-viewer jQuery plugin, as well as some of its features. So let's get started!
How to use it:
1. Load the necessary jQuery and pdf.js libraries in the document.
<script src="/path/to/cdn/jquery.min.js"></script> <script src="/path/to/cdn/pdf.min.js"></script>
2. Load the OPTIONAL Material Icons.
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons+Outlined" rel="stylesheet">
3. Load the pdfjs-viewer plugin's files.
<!-- Core --> <script src="/js/pdfjs-viewer.js"></script> <link rel="stylesheet" href="/css/pdfjs-viewer.css"> <!-- Optional Toolbar Stylesheet --> <link rel="stylesheet" href="/css/pdftoolbar.css">
4. Initialize the pdf.js library.
// Let's initialize the PDFjs library var pdfjsLib = window['pdfjs-dist/build/pdf']; // The workerSrc property shall be specified. pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.worker.min.js';
5. Emebd a PDF viewer in an HTML element you specify.
<div class="pdfjs-viewer"> ... </div>
var pdfViewer = new PDFjsViewer($('.pdfjs-viewer')); // load a PDF file pdfViewer.loadDocument('test.pdf');
<!-- Or Using pdf-document attribute --> <div id="viewer" class="pdfjs-viewer" pdf-document="test.pdf" initial-zoom="fit"> ... </div>
let pdfViewer = document.getElementById("viewer");
5. Add a custom toolbar to the PDF viewer.
<div class="row col-6 offset-md-3 pdfviewer p-0 row h-100"> <div class="pdfjs-toolbar text-center row m-0 p-0"> <div class="col-12 col-lg-6 my-1"> <button class="btn btn-secondary btn-sm btn-first" onclick="pdfViewer.first()"><i class="material-icons-outlined">skip_previous</i></button> <button class="btn btn-secondary btn-sm btn-prev" onclick="pdfViewer.prev(); return false;"><i class="material-icons-outlined">navigate_before</i></button> <span class="pageno"></span> <button class="btn btn-secondary btn-sm btn-next" onclick="pdfViewer.next(); return false;"><i class="material-icons-outlined">navigate_next</i></button> <button class="btn btn-secondary btn-sm btn-last" onclick="pdfViewer.last()"><i class="material-icons-outlined">skip_next</i></button> </div> <div class="col-12 col-lg-6 my-1"> <button class="btn btn-secondary btn-sm" onclick="pdfViewer.setZoom('out')"><i class="material-icons-outlined">zoom_out</i></button> <span class="zoomval">100%</span> <button class="btn btn-secondary btn-sm" onclick="pdfViewer.setZoom('in')"><i class="material-icons-outlined">zoom_in</i></button> <button class="btn btn-secondary btn-sm ms-3" onclick="pdfViewer.setZoom('width')"><i class="material-icons-outlined">swap_horiz</i></button> <button class="btn btn-secondary btn-sm" onclick="pdfViewer.setZoom('height')"><i class="material-icons-outlined">swap_vert</i></button> <button class="btn btn-secondary btn-sm" onclick="pdfViewer.setZoom('fit')"><i class="material-icons-outlined">fit_screen</i></button> </div> </div> <div class="pdfjs-viewer h-100" pdf-document="test.pdf" initial-zoom="fit" on-document-ready="pdfViewer = this.pdfViewer;"> </div> </div>
var pdfViewer;
6. This example shows how to create a fullscreen PDF viewer with thumbnail support.
<div class="pdfviewer"> <div class="pdfjs-toolbar"> <button class="pushed" onclick="togglethumbs(this);"><i class="material-icons-outlined">view_sidebar</i></button> <div class="v-sep"></div> <button onclick="pdfViewer.prev();"><i class="material-icons-outlined">arrow_upward</i></button> <div class="v-sep"></div> <button onclick="pdfViewer.next();"><i class="material-icons-outlined">arrow_downward</i></button> <input id="pageno" class="pageno" type="number" class="form-control form-control-sm d-inline w-auto" value="1" min="1" max="1000" onchange="pdfViewer.scrollToPage(parseInt(this.value))"> <span id="pagecount" class="pageno"></span> <div class="divider"></div> <button onclick="pdfViewer.setZoom('in')"><i class="material-icons-outlined">add</i></button> <div class="v-sep"></div> <button onclick="pdfViewer.setZoom('out')"><i class="material-icons-outlined">remove</i></button> <div class="dropdown"> <div class="dropdown-value" onclick="this.parentNode.classList.toggle('show');"> <span class="zoomval">100%</span> <i class="material-icons-outlined"> keyboard_arrow_down </i> </div> <div class="dropdown-content" onclick="this.parentNode.classList.toggle('show');"> <a href="#" onclick='pdfViewer.setZoom("width"); return false;'>Adjust width</a> <a href="#" onclick='pdfViewer.setZoom("height"); return false;'>Adjust height</a> <a href="#" onclick='pdfViewer.setZoom("fit"); return false;'>Fit page</a> <a href="#" onclick='pdfViewer.setZoom(0.5); return false;'>50%</a> <a href="#" onclick='pdfViewer.setZoom(0.75); return false;'>75%</a> <a href="#" onclick='pdfViewer.setZoom(1); return false;'>100%</a> <a href="#" onclick='pdfViewer.setZoom(1.25); return false;'>125%</a> <a href="#" onclick='pdfViewer.setZoom(1.5); return false;'>150%</a> <a href="#" onclick='pdfViewer.setZoom(2); return false;'>200%</a> <a href="#" onclick='pdfViewer.setZoom(3); return false;'>300%</a> <a href="#" onclick='pdfViewer.setZoom(4); return false;'>400%</a> </div> </div> <button id="hideselected" onclick="hideselected();"><i class="material-icons-outlined">block</i></button> <div class="divider"></div> <label class="button" for="opendoc"><i class="material-icons-outlined">file_open</i></label> <input id="opendoc" type="file" accept="application/pdf"> <a id="filedownload" class="button"><i class="material-icons-outlined">file_download</i></a> <div class="dropdown dropdown-right"> <div onclick="this.parentNode.classList.toggle('show');"> <button><i class="material-icons-outlined">keyboard_double_arrow_right</i></button> </div> <div class="dropdown-content" onclick="this.parentNode.classList.toggle('show');"> <a href="#" onclick='pdfViewer.scrollToPage(1); return false;'><i class="material-icons-outlined">vertical_align_top</i>First page</a> <a href="#" onclick='pdfViewer.scrollToPage(pdfViewer.pdf.numPages); return false;'><i class="material-icons-outlined">vertical_align_bottom</i>Last page</a> <div class="h-sep"></div> <a href="#" onclick='pdfViewer.rotate(-90, true); pdfThumbnails.rotate(-90, true).then(() => pdfThumbnails.setZoom("fit"));'><i class="material-icons-outlined">rotate_90_degrees_ccw</i>Rotate countrary clockwise</a> <a href="#" onclick='pdfViewer.rotate(90, true); pdfThumbnails.rotate(90, true).then(() => pdfThumbnails.setZoom("fit"));'><i class="material-icons-outlined">rotate_90_degrees_cw</i>Rotate clockwise</a> <div class="h-sep"></div> <a href="#" onclick='document.querySelector(".pdfjs-viewer").classList.remove("horizontal-scroll"); pdfViewer.refreshAll();'><i class="material-icons-outlined">more_vert</i>Vertical scroll</a> <a href="#" onclick='setHorizontal()'><i class="material-icons-outlined">more_horiz</i>Horizontal scroll</a> </div> </div> </div> <div class="pdfviewer-container"> <div class="thumbnails pdfjs-viewer"> </div> <div class="maindoc pdfjs-viewer"> <div class="pdfpage placeholder"> <p class="my-auto mx-auto">Cargue un fichero</p> </div> </div> </div> </div>
const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const PDFFILE = urlParams.get('doc')??"test.pdf"; function dataURItoBinArray(data) { // taken from: https://stackoverflow.com/a/11954337/14699733 var binary = atob(data); var array = []; for(var i = 0; i < binary.length; i++) { array.push(binary.charCodeAt(i)); } return new Uint8Array(array); } /** Function to load a PDF file using the input=file API */ document.querySelector("#opendoc").addEventListener("change", function(e) { let file = e.target; let reader = new FileReader(); reader.onload = async function() { await pdfViewer.loadDocument({data: dataURItoBinArray(reader.result.replace(/^data:.*;base64,/,""))}); await pdfThumbnails.loadDocument({data: dataURItoBinArray(reader.result.replace(/^data:.*;base64,/,""))}).then(() => pdfThumbnails.setZoom("fit")); } if (file.files.length > 0) { reader.readAsDataURL(file.files[0]); document.querySelector('#filedownload').download = document.querySelector('#opendoc').files[0].name; } }); /** Sets the document in horizontal scroll by changing the class for the pages container and refreshing the document * so that the pages may be displayed in horizontal scroll if they were not visible before */ function setHorizontal() { document.querySelector(".maindoc").classList.add("horizontal-scroll"); pdfViewer.refreshAll(); } /** Toggles the visibility of the thumbnails */ function togglethumbs(el) { if (el.classList.contains('pushed')) { el.classList.remove('pushed'); document.querySelector('.thumbnails').classList.add('hide'); } else { el.classList.add('pushed'); document.querySelector('.thumbnails').classList.remove('hide'); } } /** Toggles hiding the current page */ function hideselected() { let $selected = pdfThumbnails.$container.find('.selected'); let i = $selected.data('page'); $selected.toggleClass('hidden'); pdfViewer.$container.find('.pdfpage[data-page="' + i + '"]').toggleClass('hidden'); pdfViewer.scrollToPage(i); } /** Now create the PDFjsViewer object in the DIV */ let pdfViewer = new PDFjsViewer($('.maindoc'), { zoomValues: [ 0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4 ], /** Update the zoom value in the toolbar */ onZoomChange: function(zoom) { zoom = parseInt(zoom * 10000) / 100; $('.zoomval').text(zoom + '%'); }, /** Update the active page */ onActivePageChanged: function(page) { let pageno = $(page).data('page'); let pagetotal = this.getPageCount(); if (! $(page).hasClass('hidden')) { pdfThumbnails.setActivePage(pageno); $('#pageno').val(pageno); $('#pageno').attr('max', pagetotal); $('#pagecount').text('de ' + pagetotal); } }, /** zoom to fit when the document is loaded and create the object if wanted to be downloaded */ onDocumentReady: function () { pdfViewer.setZoom('fit'); pdfViewer.pdf.getData().then(function(data) { document.querySelector('#filedownload').href = URL.createObjectURL(new Blob([data], {type: 'application/pdf'})); document.querySelector('#filedownload').target = '_blank'; }); } }); /** Load the initial PDF file */ pdfViewer.loadDocument(PDFFILE).then(function() { document.querySelector('#filedownload').download = PDFFILE; }); /** Create the thumbnails */ let pdfThumbnails = new PDFjsViewer($('.thumbnails'), { zoomFillArea: 0.7, onNewPage: function(page, i) { $('<div class="numbering">').text(i).appendTo(page); page.on('click', function() { pdfThumbnails.setActivePage(page.data('page')); if (!pdfViewer.isPageVisible(page.data('page'))) { pdfViewer.scrollToPage(page.data('page')); } }) }, onDocumentReady: function() { this.setZoom('fit'); } }); pdfThumbnails.setActivePage = function(pageno) { this.$container.find('.pdfpage').removeClass('selected'); let $npage = this.$container.find('.pdfpage[data-page="' + pageno + '"]').addClass('selected'); $('#hideselected').removeClass('pushed'); if ($npage.hasClass('hidden')) $('#hideselected').addClass('pushed'); if (!this.isPageVisible(pageno)) { this.scrollToPage(pageno); } }.bind(pdfThumbnails); pdfThumbnails.loadDocument(PDFFILE);
7. All default options and callbacks.
let pdfViewer = new PDFjsViewer($('.pdfpages'), { // Fraction of the area of the page that has to be visible to be considered that it is visible visibleThreshold: 0.5, // Number of pages to load appart from the currently visible one (to enable fast scrolling) extraPagesToLoad: 3, // The class used for each page (the div that wraps the content of the page) pageClass: "pdfpage", // The class used for the content of each page (the div that contains the page) contentClass: "content-wrapper", // Posible zoom values to iterate over using "in" and "out" zoomValues: [ 0.25, 0.5, 0.75, 1, 1.25, 1.50, 2, 4, 8 ], // Percentage of the container that will be filled with the page zoomFillArea: 0.95, // Enhance the resolution for the pages renderingScale: 1.5, // Function called when a document has been loaded and its structure has been created onDocumentReady: () => {}, // Function called when a new page is created (it is binded to the object, and receives a jQuery object as parameter) onNewPage: (page, i) => {}, // Function called when a page is rendered onPageRender: (page, i) => {}, // Function called when the zoom level changes (it receives the zoom level) onZoomChange: (zoomlevel) => {}, // Function called whenever the active page is changed (the active page is the one that is shown in the viewer) onActivePageChanged: (page, i) => {}, // Function called to get the content of an empty page emptyContent: () => $('<div class="loader"></div>'), // Function called to obtain a page that shows an error when the document could not be loaded (returns a jQuery object) errorPage: () => { $(`<div class="placeholder"></div>`).addClass(this.settings.pageClass).append($(`<p class="m-auto"></p>`).text("could not load document")) }, });
8. API methods.
// load a PDF file and returns a promise // the document can be either an url or a bin array. pdfViewer.loadDocument(document); // force re-init pdfViewer.forceViewerInitialization(); // refresh all pages pdfViewer.refreshAll(); // get the active page pdfViewer.getActivePage(); // go to the first page pdfViewer.first(); // go to the last page pdfViewer.last(); // go to the next page pdfViewer.next(); // back to the previous page pdfViewer.prev(); // get the number of pages pdfViewer.getPageCount(); // retrieve all the pages of the document pdfViewer.getPages(); // go to a specific page pdfViewer.scrollToPage(i); // check if the page is visible isPageVisible(i); // set zoom level // it is possible to use a float value which represents a fraction or a keyword 'in', 'out', 'width', 'height' or 'fit' pdfViewer.setZoom(zoom); // get the current zoom level pdfViewer.getZoom(); // rotate the pages pdfViewer.rotate(deg, accumulate = false);
Changelog:
v2.0.0 (2024-11-15)
- change the cleaning method of the pages from empty() to html("") to try to solve one reported bug when generating some pages
- use plain HTML objects in callbacks instead of jQuery objects. The library still depends on jQuery (or a jQuery-compatible lib), and is compatible with jQuery.
- support for nojquery in the library (and prioritize the use over jQuery)
v1.1.2 (2024-02-17)
- includes the renderingScale option to enhance the resolution for the pages
- bugfixes
This awesome jQuery plugin is developed by dealfonso. For more Advanced Usages, please check the demo page or visit the official website.