3

I'm working on trying to make an Angular directive that encapsulates the viewer.js functionality for the pdf.js project because I really like how their viewer looks, but I would like to be able to pass in variables from my own Angular bindings.

Now, there are two angular-pdf-like projects out there like Sayanee's project (https://github.com/sayanee/angularjs-pdf) which looks like it mostly provides the basic functionality at https://github.com/mozilla/pdf.js/blob/master/examples/text-selection/js/minimal.js and a Anrennmair's project at https://github.com/akrennmair/ng-pdfviewer

These pdf viewers really don't look very good, and I like how the pdf.js viewer shows the page after page view and lets you easily scroll through them. I don't need all the functionality of printing, bookmarks, attachments, saving, opening, etc so that should save at least some work, but my question is this:

How do I write this viewer as a directive? More specifically, in an answer to a previous question, the respondent said that the first GitHub project was poorly designed from an angular-way point of view. What's the proper way to do this? I would prefer to write it well the first time according to some best practices, but I've been unable to find anything clear about what those practices would be in this scope.

2 Answers 2

3

Basically you need to be restricted to the directive element. Use the template to add the canvas and div tags. Then call on them in the link function to render the pdf.

You could take this one step further and wrap the PDFJS and the render and load functions in an angular service and then inject that into the directive. That way the loading and rendering methods will sit in the service and the directive will just setup the template and call on them.

The Markup:

<pdf-viewer pdf-path="pathToYourPdf"></pdf-viewer>

The Directive: This is not actually a functional directive but, it should give you a general idea of how to achieve what you are looking for.

angular.module('myApp', [])
  .directive('pdfViewer', [

    function() {
      return {
        template: '<canvas></canvas><div></div>',
        replace: true,
        restrict: 'E',
        scope: {
          pdfPath: '='
        },
        link: function postLink(scope, iElement, iAttrs) {
          scope.pdfPath = iAttrs.$eval(pdfPath);

          scope.pdf = PDFJS.getDocument(scope.pdfPath);

          scope.pdf
            .then(renderPdf);

          var renderPdf = function() {
            service.pdf.getPage(1)
              .then(renderPage);
          };

          var renderPage = function(page) {
            var viewport = page.getViewport(scale);
            var canvas = iElement.find('canvas')[0];
            // Set the canvas height and width to the height and width of the viewport
            var context = canvas.getContext("2d");

            // The following few lines of code set up scaling on the context if we are on a HiDPI display
            var outputScale = getOutputScale(context);
            canvas.width = (Math.floor(viewport.width) * outputScale.sx) | 0;
            canvas.height = (Math.floor(viewport.height) * outputScale.sy) | 0;
            canvas.style.width = Math.floor(viewport.width) + 'px';
            canvas.style.height = Math.floor(viewport.height) + 'px';

            // Append the canvas to the pdf container div
            var $pdfContainer = iElement;
            iElement.css("height", canvas.style.height)
              .css("width", canvas.style.width);

            var canvasOffset = canvas.offset();

            var textLayerDiv = iElement.find('div')[0];

            textLayerDiv
              .addClass("textLayer")
              .css("height", canvas.style.height)
              .css("width", canvas.style.width)
              .offset({
                top: canvasOffset.top,
                left: canvasOffset.left
              });

            context._scaleX = outputScale.sx;
            context._scaleY = outputScale.sy;
            if (outputScale.scaled) {
              context.scale(outputScale.sx, outputScale.sy);
            }

            page.getTextContent()
              .then(function(textContent) {
                var textLayer = new TextLayerBuilder({
                  textLayerDiv: textLayerDiv,
                  viewport: viewport,
                  pageIndex: 0
                });

                textLayer.setTextContent(textContent);

                var renderContext = {
                  canvasContext: context,
                  viewport: viewport
                };

                page.render(renderContext);
              });
          };
        }
      };
    }
  ]);
Sign up to request clarification or add additional context in comments.

2 Comments

+1, good answer, should have helped the OP get started - useful to me - thanks! I must say - it grinds on me when people take time to answer a question and the OP doesn't take time to accept or even upvote!
Unfortunately, while I no doubt got a notification about this at the time, I really didn't remember to reply. My apologies. I wound up finding that the code available at github.com/jviereck/pdfListView was more towards what I was looking for (in that it doesn't present as a slide-show, but more as a scrollable PDF document as it appears within PDF.js).
-2

As mentioned in one of the comments, I found that the information available at https://github.com/jviereck/pdfListView was quite helpful in determining how to do this within an Angular context in a viewer that also looked optimal.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.