Writing a directive for an existing javascript object the “Angular” way

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.

Answers


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

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.


Need Your Help


About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.