This tutorial shows how to create a NodeJS Web application with TypeScript that uses the LEADTOOLS SDK to load a document in the HTML5 JavaScript Document Viewer.
Overview | |
---|---|
Summary | This tutorial covers how to use LEADTOOLS Document Viewer SDK technology in a NodeJS Web Application with TypeScript. |
Completion Time | 15 minutes |
Visual Studio Project | Download tutorial project (30 KB) |
Platform | NodeJS NPM Project |
IDE | Visual Studio Code - Client |
Runtime License | Download LEADTOOLS |
Try it in another language |
|
Get familiar with the basic steps of creating a project by reviewing the Add References and Set a License - NodeJS and TypeScript tutorial before working on the Display Files in the Document Viewer - NodeJS and TypeScript tutorial.
The tutorial uses a text editor such as Visual Studio Code to create and modify the necessary script files.
Execute commands in this tutorial using PowerShell/CommandPrompt (if using Windows) or a terminal window (if using a Unix-based system).
Start with a copy of the project created in the Add References and Set a License - NodeJS and TypeScript tutorial. If that project is unavailable, follow the steps in that tutorial to create it.
Make sure that the required dependencies are installed by running the npm install
command.
Rename lt.MyModule
in the .\ts\App\SetLicense.ts
and the .\ts\Index.ts
scripts to lt.DocumentViewer
.
The references needed depend upon the purpose of the project. References can be added by .js
files located at <INSTALL_DIR>\LEADTOOLS22\Bin\JS
.
For this project, the following references are needed:
Leadtools.Annotations.Automation.js
Leadtools.Annotations.Designers.js
Leadtools.Annotations.Engine.js
Leadtools.Annotations.Rendering.JavaScript.js
Leadtools.js
Leadtools.Controls.js
Leadtools.Document.js
Leadtools.Document.Viewer.js
Copy these files to the project's .\site\Common
folder.
For a complete list of which JS files are required for your application, refer to Files to be Included with your Application
In addition, the following type definition files are needed for use with TypeScript:
Leadtools.Annotations.Automation.d.ts
Leadtools.Annotations.Designers.d.ts
Leadtools.Annotations.Engine.d.ts
Leadtools.Controls.d.ts
Leadtools.d.ts
Leadtools.Document.d.ts
Leadtools.Document.Viewer.d.ts
These can be found in the same folder as the .js
files at <INSTALL_DIR>\LEADTOOLS22\Bin\JS
Copy these files to the project's .\leadtools_modules\@types
folder.
The Leadtools.Document.d.ts
type definition script also requires jQuery type definitions, these are included in the toolkit at <INSTALL_DIR>\LEADTOOLS22\Bin\JS\ThirdParty\jquery
.
Copy the jquery.d.ts
file to the project's .\leadtools_modules\@types
folder and place it in a ThirdParty\jquery
sub-folder.
After copying the type definition script files, edit the .\ts\tsconfig.json
file and add the files to the types
value:
{
"compilerOptions": {
"target": "es5",
"module": "none",
"outDir": "../site",
"types": [
"../leadtools_modules/@types/Leadtools.Annotations.Automation",
"../leadtools_modules/@types/Leadtools.Annotations.Designers",
"../leadtools_modules/@types/Leadtools.Annotations.Engine",
"../leadtools_modules/@types/Leadtools.Controls",
"../leadtools_modules/@types/Leadtools",
"../leadtools_modules/@types/Leadtools.Document",
"../leadtools_modules/@types/Leadtools.Document.Viewer",
"../leadtools_modules/@types/ThirdParty/jquery/jquery"
]
}
}
The License unlocks the features needed for the project. It must be set before any toolkit function is called. For details including tutorials for different platforms, refer to Setting a Runtime License.
There are two types of runtime licenses:
Copy and paste the LEADTOOLS.lic.txt
license file into the .\site\LEADTOOLS
folder. Note that the licenses ending in .txt
are for JavaScript. The license files that do not end in .txt
are for server and desktop applications. The license files can be found in the following directory: <INSTALL_DIR>\LEADTOOLS22\Support\Common\License
Replace the key value from the LEADTOOLS.lic.key.txt
file in the .\ts\App\SetLicense.ts
script.
With the project created, dependencies added, and the license set, coding can begin.
Open the .\site\Index.html
file in an editor. Use the following lines to import the JS files and attach the dependencies to the Index.html
page.
<!-- External .js files -->
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<!-- Leadtools .js files -->
<script src="Common/Leadtools.js"></script>
<script src="Common/Leadtools.Controls.js"></script>
<script src="Common/Leadtools.Annotations.Engine.js"></script>
<script src="Common/Leadtools.Annotations.Designers.js"></script>
<script src="Common/Leadtools.Annotations.Rendering.JavaScript.js"></script>
<script src="Common/Leadtools.Annotations.Automation.js"></script>
<script src="Common/Leadtools.Document.js"></script>
<script src="Common/Leadtools.Document.Viewer.js"></script>
<!-- DocumentViewer .js fies -->
<script src="App/SetLicense.js"></script>
<script src="App/DocumentViewerApp.js"></script>
<script src="Index.js"></script>
Add the HTML elements that will be used as containers for the following components of the document viewer:
thumbnailsControl
, which holds the thumbnails part of the document viewerbookmarksControl
, which holds the bookmarks part of the document viewerimageViewerContainer
, which holds the view part of the document viewerIn addition, add a navigationbar
element that will contain buttons to toggle between the thumbnail and bookmark containers.
<div id="navigationbar" class="navigationbar">
<button id="showThumbnails" class="navigationbarBtn">
<span class="icon thumbnailsIcon"></span>
</button>
<button id="showBookmarks" class="navigationbarBtn">
<span class="icon bookmarksIcon"></span>
</button>
</div>
<div id="thumbnailsControl" class="affectedContainers">
<div class="controlHeader">
<label>Pages</label>
</div>
<div id="thumbnails">
</div>
</div>
<div id="bookmarksControl" class="affectedContainers">
<div class="controlHeader">
<label>Bookmarks</label>
</div>
<div id="bookmarks">
</div>
</div>
<div id="imageViewerContainer" class="affectedContainers">
<!-- The viewer will be dynamically created inside imageViewerDiv -->
<div id="imageViewerDiv">
</div>
</div>
The affectedContainers
class is used for selecting elements that will adjust their display according to the size of the browser window. The navigationbar
class is used in a similar way to adjust the display of the imageViewerContainer
when the bookmark or thumbnails controls are toggled.
Create a CSS
folder in the site
directory and create a new style sheet CSS file called documentViewer.css.
Use this file to specify the display styles for the HTML elements of the document viewer using the code below:
/* Document Viewer styles
-------------------------------------------------- */
body {
height: 100%;
background: white;
overflow: hidden;
color: #4D5F82;
height: 100%;
margin: 0;
-webkit-text-size-adjust: none;
font-family: helvetica;
font-size: 10pt;
margin-bottom: 60px;
display: block;
}
.navigationbar {
overflow: hidden;
position: fixed;
background-color: #DFE1E5;
display: block;
width: 40px;
left: 0px;
bottom: 0px;
top: 0px;
border-right: 1px solid;
border-right-color: #D4D6DB;
-webkit-box-shadow: 2px 0px 7px rgba(0, 0, 0, 0.3);
box-shadow: 2px 0px 7px rgba(0, 0, 0, 0.3);
z-index: 1;
}
.navigationbar .icon {
width: 34px;
}
.navigationbarBtn {
padding: 7px 0px 8px 0px;
width: 100%;
background-color: transparent;
border: 1px solid transparent;
border-right: 0;
outline: none;
width: 39px;
height: 45px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.activeNavigationbarBtn {
background-color: #D4D6DB;
border-color: darkgray;
}
.icon {
position: relative;
display: inline-block;
background-repeat: no-repeat;
background-position: center;
width: 35px;
height: 25px;
top: 3px;
}
.thumbnailsIcon {
background-image: url("../resources/images/icons/Thumbnails.png");
}
.bookmarksIcon {
background-image: url("../resources/images/icons/Bookmarks.png");
}
#imageViewerContainer {
overflow: hidden;
position: fixed;
display: block;
left: 0px;
right: 0px;
bottom: 0px;
top: 0px;
}
#imageViewerDiv {
position: relative;
width: 100%;
height: 100%;
background-color: #C2C2C2;
}
#thumbnailsControl, #bookmarksControl {
width: 195px;
background-color: #D4D6DB;
z-index: 1;
position: fixed;
left: 39px;
bottom: 0px;
top: 0px;
-webkit-box-shadow: 5px 4px 5px -5px #333;
box-shadow: 5px 4px 5px -5px #333;
border: 1px solid darkgray;
display: none;
}
#thumbnailsControl > .controlHeader, #bookmarksControl > .controlHeader {
padding: inherit;
text-align: inherit;
padding-top: 13px;
padding-left: 5px;
}
#thumbnails, #bookmarks {
overflow: hidden;
top: 43px;
left: 5px;
right: 5px;
bottom: 5px;
position: absolute !important;
border: 1px solid darkgray;
}
#thumbnails {
background-color: #fafdff;
}
#bookmarks {
background-color: white;
overflow: auto !important;
font: normal normal 12px/20px Helvetica, Arial, sans-serif;
}
Link this CSS file to be used in the Pages/index.chtml
file:
<!-- DocumentViewer stylesheet -->
<link rel="stylesheet" href="~/CSS/documentviewer.css" />
The navigationbar
element uses an icon image for each button contained for toggling the display of the thumbnail or bookmark containers.
Create a Resources
folder under the site
directory of the project then create the Images\Icons
sub-folders.
Add the Bookmarks.png
and Thumbnails.png
icon images to this folder. These images can be found at <INSTALL_DIR>\LEADTOOLS22\Examples\Common\JS\Resources\Images\Icons
Create a DocumentViewerApp.ts
file in the .\ts\App
folder.
Declare and export a new DocumentViewerApp
class which will contain the properties and functions used for the configuration and operation of the document viewer web app.
Use the code below to define the public and private properties of the DocumentViewerApp
as well as configure the constructor.
module lt.DocumentViewer {
export class DocumentViewerApp {
// Document viewer
private _documentViewer: lt.Document.Viewer.DocumentViewer = null;
// HTML Elements
public navigationbarContainer: HTMLElement = document.getElementById("navigationbar");
public navigationbar = {
showThumbnailsBtn: <HTMLButtonElement>document.getElementById("showThumbnails"),
showBookmarksBtn: <HTMLButtonElement>document.getElementById("showBookmarks")
};
public imageViewerContainerDiv: HTMLElement = document.getElementById("imageViewerContainer");
public thumbnailsContainer: HTMLElement = document.getElementById("thumbnailsControl");
public bookmarksContainer: HTMLElement = document.getElementById("bookmarksControl");
public affectedContainers: NodeListOf<HTMLElement> = document.querySelectorAll(".affectedContainers");
constructor() {
window.onunload = ((e: Event) => this.onUnload(e));
window.onresize = ((e: Event) => this.onResize(e));
}
private onUnload(e: Event): void {
if (this._documentViewer != null) {
this._documentViewer.dispose();
}
}
Use the code below to dynamically update the display of the document viewer elements according to the browser window size in relation to the header and footer elements in the project.
This code also adjusts the display of the view container if the thumbnail or bookmark containers are visible.
private onResize(e: Event) {
this.updateContainers();
}
public updateContainers(): void {
// Check visibility
let visibleThumbnails: boolean = window.getComputedStyle(this.thumbnailsContainer).display !== "none";
let visibleBookmarks: boolean = window.getComputedStyle(this.bookmarksContainer).display !== "none";
let navigationbarContainerWidth: number = this.navigationbarContainer.offsetWidth;
// Thumbnails, bookmarks and attachments Containers has same width
// Use thumbnails container as common
let containerWidth: number = parseInt(window.getComputedStyle(this.thumbnailsContainer).width);
// Now update viewer container
let imageViewerContainerDivLeft: number = navigationbarContainerWidth;
if (visibleThumbnails || visibleBookmarks)
imageViewerContainerDivLeft += containerWidth;
this.imageViewerContainerDiv.style.left = imageViewerContainerDivLeft.toString() + "px";
// The viewer container size might be changed; call onSizeChanged
this._documentViewer.view.imageViewer.onSizeChanged();
if (this._documentViewer.thumbnails != null) {
this._documentViewer.thumbnails.imageViewer.onSizeChanged();
this._documentViewer.thumbnails.imageViewer.invalidate(lt.LeadRectD.empty);
}
}
Use the code below for the DocumentViewer.run()
which will initialize the viewer, verify the service connection, and load a PDF document.
The PDF document that will be loaded is a sample Leadtools.pdf
file that is available at https://demo.leadtools.com/images/pdf/leadtools.pdf
public run(): void {
// Initialize the Navigation Bar Buttons
this.navigationbar.showThumbnailsBtn.addEventListener("click", () => this.showContainer(this.thumbnailsContainer, true));
this.navigationbar.showBookmarksBtn.addEventListener("click", () => this.showContainer(this.bookmarksContainer, true));
// Initialize the document viewer
this.initDocumentViewer();
// Initialize the UI
this.updateAppUIState();
// Verify Service Connection
lt.Document.DocumentFactory.serviceHost = "http://localhost:40000";
lt.Document.DocumentFactory.servicePath = "";
lt.Document.DocumentFactory.serviceApiPath = "api";
lt.Document.DocumentFactory.verifyService()
.done(() => {
lt.LTHelper.log("Service connection verified!");
})
.fail(() => {
lt.LTHelper.log("Service connection unavailable.");
});
// Load a Document
const url = "https://demo.leadtools.com/images/pdf/leadtools.pdf";
lt.Document.DocumentFactory.loadFromUri(url, null)
.done((doc) => {
this.setDocument(doc);
this.updateAppUIState();
});
}
Use the code below for the navigation bar buttons to use for controlling the visibility of the thumbnails and bookmarks containers.
// Toggle the visibility of the thumbnails/bookmarks containers
public showContainer(container, flipState: boolean): void {
let visibleThumbnails: boolean = window.getComputedStyle(this.thumbnailsContainer).display !== "none";
let visibleBookmarks: boolean = window.getComputedStyle(this.bookmarksContainer).display !== "none";
// Show Thumbnails
if (container == this.thumbnailsContainer) {
if (!visibleThumbnails) {
if (visibleBookmarks) {
this.bookmarksContainer.style.display = "none";
this.navigationbar.showBookmarksBtn.classList.remove("activeNavigationbarBtn");
}
this.navigationbar.showThumbnailsBtn.classList.add("activeNavigationbarBtn");
this.thumbnailsContainer.style.display = "block";
} else {
if (flipState) {
this.navigationbar.showThumbnailsBtn.classList.remove("activeNavigationbarBtn");
this.thumbnailsContainer.style.display = "none";
}
}
this.updateContainers();
return;
}
// Show Bookmarks
if (container == this.bookmarksContainer) {
if (!visibleBookmarks) {
// Hide others
if (visibleThumbnails) {
this.thumbnailsContainer.style.display = "none";
this.navigationbar.showThumbnailsBtn.classList.remove("activeNavigationbarBtn");
}
this.navigationbar.showBookmarksBtn.classList.add("activeNavigationbarBtn");
this.bookmarksContainer.style.display = "block";
} else {
if (flipState) {
this.navigationbar.showBookmarksBtn.classList.remove("activeNavigationbarBtn");
this.bookmarksContainer.style.display = "none";
}
}
this.updateContainers();
return;
}
}
Use the following code to configure the document viewer. The createOptions
object configures the creation of the viewer and hooks the HTML elements.
After the document viewer is created by the DocumentViewerFactory
object, the document viewer settings can also be configured. In this tutorial, the following settings are applied:
// Create the document viewer
private initDocumentViewer(): void {
// Document Viewer Creation Options
let createOptions: lt.Document.Viewer.DocumentViewerCreateOptions = new lt.Document.Viewer.DocumentViewerCreateOptions();
createOptions.viewCreateOptions.useElements = false;
createOptions.thumbnailsCreateOptions.useElements = false;
// Set the UI part where the main view is displayed
createOptions.viewContainer = document.getElementById("imageViewerDiv");
// Set the UI part where the thumbnails are displayed
createOptions.thumbnailsContainer = document.getElementById("thumbnails");
// Set the UI part where the bookmarks are displayed (Set bookmarks container will show them in simple list)
createOptions.bookmarksContainer = document.getElementById("bookmarks");
createOptions.useAnnotations = false;
// Create the viewer
try {
this._documentViewer = lt.Document.Viewer.DocumentViewerFactory.createDocumentViewer(createOptions);
// Document viewer settings
// SVG Preference for Display
this._documentViewer.view.preferredItemType = lt.Document.Viewer.DocumentViewerItemType.svg
// Lazy Loading
this._documentViewer.view.lazyLoad = true;
if (this._documentViewer.thumbnails)
this._documentViewer.thumbnails.lazyLoad = true;
// Log Rendering Errors
let imageViewer: lt.Controls.ImageViewer = this._documentViewer.view.imageViewer;
let logRenderErrors: lt.Controls.ImageViewerRenderEventHandler = function (sender: any, e: lt.Controls.ImageViewerRenderEventArgs) {
let item: number = e.item != null ? e.item.imageViewer.items.indexOf(e.item) : -1;
let message: string = "Error during render item " + item + " part " + (e.part) + ": " + (e.error.message);
lt.LTHelper.logError({ message: message, error: e.error });
}
imageViewer.renderError.add(logRenderErrors);
if (this._documentViewer.thumbnails && this._documentViewer.thumbnails.imageViewer)
this._documentViewer.thumbnails.imageViewer.renderError.add(logRenderErrors);
}
catch (e) {
alert("DocumentViewer creation failed");
lt.LTHelper.logError(e);
return;
}
}
Use the code below to initialize the display of the document viewer app's user interface.
// Update the UI state of the app
private updateAppUIState(): void {
let hasDocument: boolean = this._documentViewer.hasDocument;
if (hasDocument) {
if (window.getComputedStyle(this.imageViewerContainerDiv).display === "none") {
this.imageViewerContainerDiv.style.display = "block";
this._documentViewer.view.imageViewer.updateTransform();
}
if (this.navigationbar.showThumbnailsBtn.matches(":disabled"))
this.navigationbar.showThumbnailsBtn.disabled = false;
if (this._documentViewer.document.isStructureSupported) {
if (this.navigationbar.showBookmarksBtn.matches(":disabled"))
this.navigationbar.showBookmarksBtn.disabled = false;
} else {
this.navigationbar.showBookmarksBtn.classList.remove("activeNavigationbarBtn");
if (!(this.navigationbar.showBookmarksBtn.matches(":disabled")))
this.navigationbar.showBookmarksBtn.disabled = true;
if (this.bookmarksContainer.style.display === "block")
this.bookmarksContainer.style.display = "none";
}
} else {
if (window.getComputedStyle(this.imageViewerContainerDiv).display === "block") {
this.imageViewerContainerDiv.style.display = "none";
}
this.navigationbar.showThumbnailsBtn.classList.remove("activeNavigationbarBtn");
if (!(this.navigationbar.showThumbnailsBtn.matches(":disabled")))
this.navigationbar.showThumbnailsBtn.disabled = true;
if (this.thumbnailsContainer.style.display === "block")
this.thumbnailsContainer.style.display = "none";
this.navigationbar.showBookmarksBtn.classList.remove("activeNavigationbarBtn");
if (!(this.navigationbar.showBookmarksBtn.matches(":disabled")))
this.navigationbar.showBookmarksBtn.disabled = true;
if (this.bookmarksContainer.style.display === "block")
this.bookmarksContainer.style.display = "none";
}
this.updateContainers();
}
The following code checks if the loaded document is parsed, parses the document if needed, and sets the loaded document into the document viewer.
public setDocument(document: lt.Document.LEADDocument): void {
// See if we need to parse the document structure
if (document.structure.isParsed) {
this.finishSetDocument(document);
}
else
this.parseStructure(document);
}
private parseStructure(document: lt.Document.LEADDocument): void {
document.structure.parse()
.done((document: lt.Document.LEADDocument): void => {
this.finishSetDocument(document);
})
.fail((): void => {
lt.LTHelper.log("Error parsing the document structure.");
});
}
public finishSetDocument(document: lt.Document.LEADDocument): void {
if (this._documentViewer.view != null) {
// Use SVG Back Image
this._documentViewer.view.useSvgBackImage = true;
}
// Set the loaded document in the document viewer
this._documentViewer.setDocument(document);
// Update the UI
this.updateAppUIState();
// Call onResize so the DIV sizes get updated
this.onResize(null);
// Fit page to display
this._documentViewer.commands.run(lt.Document.Viewer.DocumentViewerCommands.viewFitPage, null);
}
}
}
Add a call to the run() method in the Index.ts
script.
document.addEventListener("DOMContentLoaded", () => {
(new lt.DocumentViewer.SetLicense()).run();
(new lt.DocumentViewer.DocumentViewerApp()).run();
});
Before running the front-end Document Viewer, run the Document Service. The LEADTOOLS SDK installation provides three examples of the Document Service for the following platforms:
For instructions on how to set up and configure the Document Service, in the three platforms previously listed, refer to the steps in the Get Started with the Document Viewer Demo - HTML5 JavaScript tutorial.
For the purposes of this tutorial, the .NET Framework Document Service is used and it can be found here:
Once you have the back-end Document Service running, execute the build
script to transpile the TS scripts to the output site
folder:
npm run build
Once done, execute the start
script to start the server and automatically open the hosted site in the default browser.
npm run start
This tutorial showed how to initialize, load, and display a document in a NodeJS TypeScript Document Viewer Web application.