]> git.parisson.com Git - pdf.js.git/commitdiff
Added a new multi-page viewer that uses lazy loading to display pages in a scrolling...
authorJustin D'Arcangelo <justindarc@gmail.com>
Sat, 18 Jun 2011 08:33:13 +0000 (04:33 -0400)
committerJustin D'Arcangelo <justindarc@gmail.com>
Sat, 18 Jun 2011 08:33:13 +0000 (04:33 -0400)
multi-page-viewer.css [new file with mode: 0644]
multi-page-viewer.html [new file with mode: 0644]
multi-page-viewer.js [new file with mode: 0644]

diff --git a/multi-page-viewer.css b/multi-page-viewer.css
new file mode 100644 (file)
index 0000000..488b10b
--- /dev/null
@@ -0,0 +1,50 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
+/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
+
+body {
+    font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;
+    margin: 0px;
+    padding: 0px;
+}
+
+canvas {
+    box-shadow: 0px 4px 10px #000;
+    -moz-box-shadow: 0px 4px 10px #000;
+    -webkit-box-shadow: 0px 4px 10px #000;
+}
+
+span {
+    font-size: 0.8em;
+}
+
+.page {
+    width: 816px;
+    height: 1056px;
+    margin: 10px auto;
+}
+
+#controls {
+    background-color: #eee;
+    border-bottom: 1px solid #666;
+    padding: 4px 0px 0px 10px;
+    position:fixed;
+    left: 0px;
+    top: 0px;
+    height: 28px;
+    width: 100%;
+    box-shadow: 0px 2px 8px #000;
+    -moz-box-shadow: 0px 2px 8px #000;
+    -webkit-box-shadow: 0px 2px 8px #000;
+}
+
+#pageNumber {
+    margin: 0px 0px 0px 10px;
+    text-align: right;
+}
+
+#viewer {
+    background-color: #929292;
+    margin: 32px 0px 0px;
+    padding: 8px 0px;
+    width: 100%;
+}
diff --git a/multi-page-viewer.html b/multi-page-viewer.html
new file mode 100644 (file)
index 0000000..a166f7f
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>pdf.js Multi-Page Viewer</title>
+<link rel="stylesheet" href="multi-page-viewer.css" type="text/css" media="screen" charset="utf-8"/>
+<script type="text/javascript" src="pdf.js"></script>
+<script type="text/javascript" src="fonts.js"></script>
+<script type="text/javascript" src="glyphlist.js"></script>
+<script type="text/javascript" src="multi-page-viewer.js"></script>
+</head>
+<body>
+    <div id="controls">
+        <button id="previousPageButton">Previous</button>
+        <button id="nextPageButton">Next</button>
+        <input type="text" id="pageNumber" value="1" size="2"/>
+        <span>/</span>
+        <span id="numPages">--</span>
+    </div>
+    <div id="viewer"></div>
+</body>
+</html>
diff --git a/multi-page-viewer.js b/multi-page-viewer.js
new file mode 100644 (file)
index 0000000..20d2e37
--- /dev/null
@@ -0,0 +1,261 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
+/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
+
+var PDFViewer = {
+    queryParams: {},
+
+    element: null,
+
+    pageNumberInput: null,
+
+    pdf: null,
+
+    url: 'compressed.tracemonkey-pldi-09.pdf',
+    pageNumber: 1,
+    numberOfPages: 1,
+
+    scale: 1.0,
+
+    pageWidth: function() {
+        return 816 * PDFViewer.scale;
+    },
+
+    pageHeight: function() {
+        return 1056 * PDFViewer.scale;
+    },
+    
+    lastPagesDrawn: [],
+    
+    visiblePages: function() {  
+        var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins.      
+        var windowTop = window.pageYOffset;
+        var windowBottom = window.pageYOffset + window.innerHeight;
+        var pageStartIndex = Math.floor(windowTop / pageHeight);
+        var pageStopIndex = Math.ceil(windowBottom / pageHeight);
+
+        var pages = [];  
+
+        for (var i = pageStartIndex; i <= pageStopIndex; i++) {
+            pages.push(i + 1);
+        }
+
+        return pages;
+    },
+  
+    createPage: function(num) {
+        var anchor = document.createElement('a');
+        anchor.name = '' + num;
+    
+        var div = document.createElement('div');
+        div.id = 'pageContainer' + num;
+        div.className = 'page';    
+        
+        PDFViewer.element.appendChild(anchor);
+        PDFViewer.element.appendChild(div);
+    },
+    
+    removePage: function(num) {
+        var div = document.getElementById('pageContainer' + num);
+        
+        if (div && div.hasChildNodes()) {
+            while (div.childNodes.length > 0) {
+                div.removeChild(div.firstChild);
+            }
+        }
+    },
+
+    drawPage: function(num) {
+        if (PDFViewer.pdf) {
+            var page = PDFViewer.pdf.getPage(num);
+            var div = document.getElementById('pageContainer' + num);
+            
+            if (div && !div.hasChildNodes()) {
+                var canvas = document.createElement('canvas');
+                canvas.id = 'page' + num;
+                canvas.mozOpaque = true;
+
+                // Canvas dimensions must be specified in CSS pixels. CSS pixels
+                // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi.
+                canvas.width = 816;
+                canvas.height = 1056;
+
+                var ctx = canvas.getContext('2d');
+                ctx.save();
+                ctx.fillStyle = 'rgb(255, 255, 255)';
+                ctx.fillRect(0, 0, canvas.width, canvas.height);
+                ctx.restore();
+
+                var gfx = new CanvasGraphics(ctx);
+                var fonts = [];
+        
+                // page.compile will collect all fonts for us, once we have loaded them
+                // we can trigger the actual page rendering with page.display
+                page.compile(gfx, fonts);
+            
+                // This should be called when font loading is complete
+                page.display(gfx);
+                
+                div.appendChild(canvas);
+            }
+        }
+    },
+  
+    goToPage: function(num) {
+        if (0 <= num && num <= PDFViewer.numberOfPages) {
+            PDFViewer.pageNumber = num;
+        }
+    
+        PDFViewer.pageNumberInput.value = PDFViewer.pageNumber;
+        document.location.hash = PDFViewer.pageNumber;
+    },
+  
+    goToPreviousPage: function() {
+        if (PDFViewer.pageNumber > 1) {
+            --PDFViewer.pageNumber;
+        }
+    
+        PDFViewer.goToPage(PDFViewer.pageNumber);
+    },
+  
+    goToNextPage: function() {
+        if (PDFViewer.pageNumber < PDFViewer.numberOfPages) {
+            ++PDFViewer.pageNumber;
+        }
+    
+        PDFViewer.goToPage(PDFViewer.pageNumber);
+    },
+  
+    open: function(url) {
+        PDFViewer.url = url;
+        document.title = url;
+    
+        var req = new XMLHttpRequest();
+        req.open('GET', url);
+        req.mozResponseType = req.responseType = 'arraybuffer';
+        req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200;
+    
+        req.onreadystatechange = function() {
+            if (req.readyState === 4 && req.status === req.expected) {
+                var data = req.mozResponseArrayBuffer ||
+                    req.mozResponse ||
+                    req.responseArrayBuffer ||
+                    req.response;
+
+                PDFViewer.pdf = new PDFDoc(new Stream(data));
+                PDFViewer.numberOfPages = PDFViewer.pdf.numPages;
+                document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString();
+          
+                for (var i = 1; i <= PDFViewer.numberOfPages; i++) {
+                    PDFViewer.createPage(i);
+                }
+
+                if (PDFViewer.numberOfPages > 0) {
+                    PDFViewer.drawPage(1);
+                }
+            }
+        };
+    
+        req.send(null);
+    }
+};
+
+window.onload = function() {
+
+    // Parse the URL query parameters into a cached object.
+    PDFViewer.queryParams = function() {
+        var qs = window.location.search.substring(1);
+        var kvs = qs.split('&');
+        var params = {};
+        for (var i = 0; i < kvs.length; ++i) {
+            var kv = kvs[i].split('=');
+            params[unescape(kv[0])] = unescape(kv[1]);
+        }
+        
+        return params;
+    }();
+
+    PDFViewer.element = document.getElementById('viewer');
+
+    PDFViewer.pageNumberInput = document.getElementById('pageNumber');
+    PDFViewer.pageNumberInput.onkeydown = function(evt) {
+        var charCode = evt.charCode || evt.keyCode;
+
+        // Up arrow key.
+        if (charCode === 38) {
+            PDFViewer.goToNextPage();
+            this.select();
+        }
+        
+        // Down arrow key.
+        else if (charCode === 40) {
+            PDFViewer.goToPreviousPage();
+            this.select();
+        }
+
+        // All other non-numeric keys (excluding Left arrow, Right arrow,
+        // Backspace, and Delete keys).
+        else if ((charCode < 48 || charCode > 57) &&
+            charCode !== 8 &&   // Backspace
+            charCode !== 46 &&  // Delete
+            charCode !== 37 &&  // Left arrow
+            charCode !== 39     // Right arrow
+        ) {
+            return false;
+        }
+
+        return true;
+    };
+    PDFViewer.pageNumberInput.onkeyup = function(evt) {
+        var charCode = evt.charCode || evt.keyCode;
+
+        // All numeric keys, Backspace, and Delete.
+        if ((charCode >= 48 && charCode <= 57) ||
+            charCode === 8 ||   // Backspace
+            charCode === 46     // Delete
+        ) {
+            PDFViewer.goToPage(this.value);
+        }
+        
+        this.focus();
+    };
+
+    var previousPageButton = document.getElementById('previousPageButton');
+    previousPageButton.onclick = PDFViewer.goToPreviousPage;
+    
+    var nextPageButton = document.getElementById('nextPageButton');
+    nextPageButton.onclick = PDFViewer.goToNextPage;
+
+    PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber;
+    PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url);
+
+    window.onscroll = function(evt) {
+        var lastPagesDrawn = PDFViewer.lastPagesDrawn;
+        var visiblePages = PDFViewer.visiblePages();
+        
+        var pagesToDraw = [];
+        var pagesToKeep = [];
+        var pagesToRemove = [];
+        
+        var i;
+
+        // Determine which visible pages were not previously drawn.
+        for (i = 0; i < visiblePages.length; i++) {
+            if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) {
+                pagesToDraw.push(visiblePages[i]);
+                PDFViewer.drawPage(visiblePages[i]);
+            } else {
+                pagesToKeep.push(visiblePages[i]);
+            }
+        }
+
+        // Determine which previously drawn pages are no longer visible.
+        for (i = 0; i < lastPagesDrawn.length; i++) {
+            if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) {
+                pagesToRemove.push(lastPagesDrawn[i]);
+                PDFViewer.removePage(lastPagesDrawn[i]);
+            }
+        }
+        
+        PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep);
+    };
+};