Some test text!

UI customization

Contents

What option should I choose
App level customization
Config file
Example customizations in a React project

WebViewer is highly configurable and comes with a rich set of APIs which allow developers to customize and manipulate documents in many ways. This guide will show you the best place to make your customizations.

There are two ways of adding customization to WebViewer, the first way is by accessing the WebViewer instance within your app and the second is by using a config file, which is a stand-alone JavaScript file executed inside WebViewer's iframe.

linkWhat option should I choose

We'll start with a simple example Web App and show where you can make your customizations.

<!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
    <script src="/lib/webviewer.min.js"></script>
  </head>
  <body>
    <div id="viewer"></div>
    <script src="app.js"></script>
  </body>
</html>

linkApp level customization

Listen to events on the viewer element and call functions on the varructed WebViewer instance. Generally this is the recommended way to customize WebViewer within your app.

The only time where this will not work is if you are hosting the WebViewer lib folder on a different server from the rest of your app. This causes the iframe to not be accessible directly from your app because it's on a different origin.

// app.js
// Instantiate WebViewer
var viewerElement = document.getElementById('viewer');
var viewer = new PDFTron.WebViewer({
  path: 'lib',
  l: 'YOUR_LICENSE_KEY_HERE',
  initialDoc: '/files/webviewer-demo-annotated.pdf'
}, viewerElement);

viewerElement.addEventListener('ready', function() {
  var docViewer = viewer.getInstance().docViewer;

  docViewer.setMargin(20);
  docViewer.on('fitModeUpdated', function(e, fitMode) {
    console.log('fit mode changed');
  });

  viewerInstance.disableElement('searchButton');
  viewerInstance.setTheme('dark');
});

viewerElement.addEventListener('documentLoaded', function() {
  var viewerInstance = viewer.getInstance();
  var docViewer = viewerInstance.docViewer;
  var annotManager = docViewer.getAnnotationManager();
  // Access classes/namespaces defined in the WebViewer iframe
  var Annotations = viewerElement.querySelector('iframe').contentWindow.Annotations;

  // Add customization here
  // Draw rectangle annotation on first page
  var rectangle = new Annotations.RectangleAnnotation();
  rectangle.PageNumber = 1;
  rectangle.X = 100;
  rectangle.Y = 100;
  rectangle.Width = 250;
  rectangle.Height = 250;
  rectangle.Author = annotManager.getCurrentUser();
  annotManager.addAnnotation(rectangle);
  annotManager.drawAnnotations(rectangle.PageNumber);
})

linkConfig file

You can organize your custom code in a separate JavaScript file that is executed in the context of the iframe. In this way, you have direct access to the iframe window and document, and you can use WebViewer's global methods directly. More details about config files can be found here.

Config files are recommended when you are hosting the WebViewer lib folder on a separate server from your application. Since the config file is executed directly in the iframe there are no cross origin issues.

// app.js
// Instantiate WebViewer
var viewerElement = document.getElementById('viewer');
var viewer = new PDFTron.WebViewer({
  path: 'https://myotherserver.com/webviewer/lib',
  l: 'YOUR_LICENSE_KEY_HERE',
  initialDoc: '/files/webviewer-demo-annotated.pdf',
  config: 'config.js' // path/to/your/config.js
}, viewerElement);
// config.js executed inside the iframe
$(document).on('viewerLoaded', function() {
  var docViewer = readerControl.docViewer;
  var annotManager = docViewer.getAnnotationManager();

  // Add customization here
  docViewer.setMargin(20);
  docViewer.on('fitModeUpdated', function(e, fitMode) {
    console.log('fit mode changed');
  });

  readerControl.disableElement('searchButton');
  readerControl.setTheme('dark');
});

$(document).on('documentLoaded', function() {
  var docViewer = readerControl.docViewer;
  var annotManager = docViewer.getAnnotationManager();

  // Add customization here
  // Draw rectangle annotation on first page
  // "Annotations" can be directly accessed since we're inside the iframe
  var rectangle = new Annotations.RectangleAnnotation();
  rectangle.PageNumber = 1;
  rectangle.X = 100;
  rectangle.Y = 100;
  rectangle.Width = 250;
  rectangle.Height = 250;
  rectangle.Author = annotManager.getCurrentUser();
  annotManager.addAnnotation(rectangle);
  annotManager.drawAnnotations(rectangle.PageNumber);
})

linkExample customizations in a React project

Here is another example in a React app. This example uses both app level code and a config file to customize WebViewer and how you might make WebViewer objects accessible by other components in your app. A full, running React sample is also available on Github here https://github.com/PDFTron/webviewer-react-sample.

// WebViewerComponent.js
import React from 'react';

class WebViewer extends React.Component {
  viewer = React.createRef();
  getInstance()  { return this.myWebViewer.getInstance(); }
  getElement() { return this.viewer.current; }
  // Access WebViewer's iframe window for WebViewer classes
  getWindow() {
    return this.viewer.current.querySelector('iframe').contentWindow;
  }
  // Access WebViewer's iframe document
  getDocument() {
    return this.viewer.current.querySelector('iframe').contentDocument;
  }

  componentDidMount() {
    this.myWebViewer = new window.PDFTron.WebViewer({
      path: '/assets/webviewer',
      initialDoc: '/assets/files/webviewer-demo-annotated.pdf',
      config: '/config.js', // path/to/your/config.js
      l: 'YOUR_LICENSE_KEY_HERE',
    }, this.viewer.current);
  }

  render() {
    return (<div className="webviewer" ref={this.viewer}></div>);
  }
}

export default WebViewer;

This is our main React app, where we use code level customization to draw an annotation on the first page.

// App.js
import React from 'react';
import ReactDOM from 'react-dom';
import WebViewer from './WebViewerComponent';

class App extends React.Component {
  webviewer = React.createRef();
  componentDidMount() {
    this.webviewer.current.getElement()
        .addEventListener('documentLoaded', this.wvDocumentLoadedHandler);
  }

  wvDocumentLoadedHandler = () => {
    var viewerInstance = this.webviewer.current.getInstance();
    var docViewer = viewerInstance.docViewer;
    var annotManager = docViewer.getAnnotationManager();
    // Access classes defined in the WebViewer iframe
    var { Annotations } = this.webviewer.current.getWindow();

    // Add customization here
    // Draw rectangle annotation on first page
    var rectangle = new Annotations.RectangleAnnotation();
    rectangle.PageNumber = 1;
    rectangle.X = 100;
    rectangle.Y = 100;
    rectangle.Width = 250;
    rectangle.Height = 250;
    rectangle.Author = annotManager.getCurrentUser();
    annotManager.addAnnotation(rectangle);
    annotManager.drawAnnotations(rectangle.PageNumber);
  }

  render() {
    return (
      <div className="AppWV">
        <WebViewer ref={this.webviewer} />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));

And the config file:

// config.js executed within iframe
$(document).on('viewerLoaded', function() {
  var docViewer = readerControl.docViewer;
  var annotManager = docViewer.getAnnotationManager();

  // Add customization here
  docViewer.setMargin(20);
  docViewer.on('fitModeUpdated', function(e, fitMode) {
    console.log('fit mode changed');
  });

  readerControl.disableElement('searchButton');
  readerControl.setTheme('dark');
});

Get the answers you need: Support

Contents

What option should I choose
App level customization
Config file
Example customizations in a React project