/** * @preserve AngularJS PDF viewer directive using pdf.js. * * https://github.com/akrennmair/ng-pdfviewer * * MIT license */ angular .module("ngPDFViewer", []) .factory("RecursionHelper", [ "$compile", function($compile) { return { /** * Manually compiles the element, fixing the recursion loop. * @param element * @param [link] A post-link function, or an object with function(s) registered via pre and post properties. * @returns An object containing the linking functions. */ compile: function(element, link) { // Normalize the link parameter if (angular.isFunction(link)) { link = { post: link }; } // Break the recursion loop by removing the contents var contents = element.contents().remove(); var compiledContents; return { pre: link && link.pre ? link.pre : null, /** * Compiles and re-adds the contents */ post: function(scope, element) { // Compile the contents if (!compiledContents) { compiledContents = $compile(contents); } // Re-add the compiled contents to the element compiledContents(scope, function(clone) { element.append(clone); }); // Call the post-linking function, if any if (link && link.post) { link.post.apply(null, arguments); } }, }; }, }; }, ]) .directive("pdfpageviewer", [ function() { return { restrict: "E", template: "", scope: { onPageLoad: "=", page: "=", pdfDoc: "=", }, controller: [ "$scope", "$element", function($scope, $element) { $scope.scale = 1.0; const canvas = $element.find("canvas")[0]; $scope.$watch("pdfDoc", (pdfDoc) => { if (pdfDoc) { $scope.renderPage($scope.page); } }); $scope.renderPage = async function(num) { const page = await $scope.pdfDoc.getPage(num); const ratio = $element[0].clientWidth / page.getViewport(1.0).width; const viewport = page.getViewport(ratio); canvas.height = viewport.height; canvas.width = viewport.width; const ctx = canvas.getContext("2d"); await page.render({ canvasContext: ctx, viewport: viewport }); if ($scope.onPageLoad) { $scope.$apply(function() { $scope.onPageLoad({ page: $scope.page, total: $scope.pdfDoc.numPages, }); }); } return true; }; }, ], }; }, ]) .directive("pdfviewer", [ "RecursionHelper", function(RecursionHelper) { var instance_id = null; return { restrict: "E", template: "", scope: { onPageLoad: "&", loadProgress: "&", src: "@", id: "=", }, compile: function(element) { return RecursionHelper.compile(element); }, controller: [ "$scope", function($scope) { $scope.pdfDoc = null; $scope.scale = 1.0; $scope.documentProgress = function(progressData) { if ($scope.loadProgress) { $scope.loadProgress({ state: "loading", loaded: progressData.loaded, total: progressData.total, }); } }; $scope.loadPDF = function(path) { PDFJS.getDocument(path, null, null, $scope.documentProgress).then( function(_pdfDoc) { $scope.$apply(() => { $scope.pdfDoc = _pdfDoc; }); if ($scope.loadProgress) { $scope.loadProgress({ state: "finished", loaded: 0, total: 0, }); } }, function(message, exception) { console.log("PDF load error: " + message); if ($scope.loadProgress) { $scope.loadProgress({ state: "error", loaded: 0, total: 0, }); } } ); }; $scope.$on("pdfviewer.nextPage", function(evt, id) { if (id !== instance_id) { return; } if ($scope.pageNum < $scope.pdfDoc.numPages) { $scope.pageNum++; $scope.renderPage($scope.pageNum); } }); $scope.$on("pdfviewer.prevPage", function(evt, id) { if (id !== instance_id) { return; } if ($scope.pageNum > 1) { $scope.pageNum--; $scope.renderPage($scope.pageNum); } }); $scope.$on("pdfviewer.gotoPage", function(evt, id, page) { if (id !== instance_id) { return; } if (page >= 1 && page <= $scope.pdfDoc.numPages) { $scope.pageNum = page; $scope.renderPage($scope.pageNum); } }); $scope.$watch("src", () => { $scope.loadPDF($scope.src); }); }, ], }; }, ]) .service("PDFViewerService", [ "$rootScope", function($rootScope) { var svc = {}; svc.nextPage = function() { $rootScope.$broadcast("pdfviewer.nextPage"); }; svc.prevPage = function() { $rootScope.$broadcast("pdfviewer.prevPage"); }; svc.Instance = function(id) { var instance_id = id; return { prevPage: function() { $rootScope.$broadcast("pdfviewer.prevPage", instance_id); }, nextPage: function() { $rootScope.$broadcast("pdfviewer.nextPage", instance_id); }, gotoPage: function(page) { $rootScope.$broadcast("pdfviewer.gotoPage", instance_id, page); }, }; }; return svc; }, ]);