Integrate WebViewer into a Node.js App for Enhanced Server-Side Search Functionality

This sample integrates WebViewer into a Node.js project, enabling a server-side search feature that replaces the default client-side search.

WebViewer provides a slick out-of-the-box responsive UI that enables you to view, annotate and manipulate PDFs and other document types inside any web project.

Click the button below to view the full project in GitHub.

1if(!fetch || !Promise){
2 // check if browser supports fetch and Promises
3 const viewerElement = document.getElementById('viewer');
4 viewerElement.innerHTML = 'This example requires browser supporting both fetch and Promise API. Internet Explorer 11 not supported.'
5}
6
7function requestSearch(keyword, options){
8 const apiUrl = new URL('http://localhost:8080/api/search');
9 // add keyword as a url query parameter
10 apiUrl.searchParams.append("keyword", keyword);
11 const optionKeys = Object.keys(options);
12 // Add all search options as a url query parameters
13 optionKeys.forEach(function(key){
14 apiUrl.searchParams.append(key, options[key]);
15 });
16 return fetch(apiUrl.href)
17 .then(function(response){
18 if(response.ok){
19 return response.json();
20 } else {
21 console.log('Backend call failed, ', response.statusText);
22 }
23 });
24}
25
26function convertQuadCoordinatesToPdfCoordinates(document, pageNumber, quad){
27 // PDFNet search result coordinate space is different than WebViewer coordinate space
28 // so we need to convert them to be able to show highlights correctly
29 // https://docs.apryse.com/documentation/web/guides/coordinates/
30 const point1 = document.getPDFCoordinates(pageNumber, quad.p1x, quad.p1y);
31 const point2 = document.getPDFCoordinates(pageNumber, quad.p2x, quad.p2y);
32 const point3 = document.getPDFCoordinates(pageNumber, quad.p3x, quad.p3y);
33 const point4 = document.getPDFCoordinates(pageNumber, quad.p4x, quad.p4y);
34 return {
35 'x1': point1.x,
36 'y1': point1.y,
37 'x2': point2.x,
38 'y2': point2.y,
39 'x3': point3.x,
40 'y3': point3.y,
41 'x4': point4.x,
42 'y4': point4.y,
43 }
44}
45
46function convertSearchResultForWebViewer(document, result){
47 const webViewerFormattedQuads = result.quads.map((quad) => {
48 // PDFNet search result coordinate space is different than WebViewer coordinate space
49 // so we need to convert them to be able to show highlights correctly
50 // https://docs.apryse.com/documentation/web/guides/coordinates/
51 return convertQuadCoordinatesToPdfCoordinates(document, result.page_num, quad);
52 });
53 // WebViewer uses slightly modified result format than PDFNet on the server side.
54 // To support displaying results on default UI, we need to convert it to match WebViewer format
55 const searchResult = {
56 resultCode: result.code,
57 resultStr: result.out_str,
58 resultStrStart: -1,
59 resultStrEnd: -1,
60 result_str: result.out_str,
61 result_str_start: -1,
62 result_str_end: -1,
63 page_num: result.page_num,
64 pageNum: result.page_num,
65 ambient_str: result.ambient_str,
66 ambientStr: result.ambient_str,
67 quads: webViewerFormattedQuads
68 };
69 return searchResult;
70}
71
72function executeSearchOnBackendFactory(docViewer){
73 // Function that will be executed instead of default search
74 return function executeSearchOnBackend(searchValue, searchOptions){
75 docViewer.clearSearchResults();
76 const document = docViewer.getDocument();
77 requestSearch(searchValue, searchOptions).then((data) => {
78 if(data && data.length > 0) {
79 const extendedResult = data.map((result) => {
80 return convertSearchResultForWebViewer(document, result);
81 });
82 docViewer.displayAdditionalSearchResults(extendedResult);
83 docViewer.setActiveSearchResult(extendedResult[0]);
84 }
85 });
86 }
87}
88
89const WebViewer = window.WebViewer;
90WebViewer({
91 initialDoc: 'assets/webviewer-demo-annotated.pdf',
92 enableFilePicker: true,
93 path: 'webviewer/lib',
94}, document.getElementById('viewer')).then((instance) => {
95 const { documentViewer } = instance.Core;
96 documentViewer.addEventListener('documentLoaded', function() {
97 instance.UI.overrideSearchExecution(executeSearchOnBackendFactory(documentViewer));
98 });
99});
100
101function getPoints() {
102 return {
103 'x1': this.x1,
104 'y1': this.y1,
105 'x2': this.x2,
106 'y2': this.y2,
107 'x3': this.x3,
108 'y3': this.y3,
109 'x4': this.x4,
110 'y4': this.y4,
111 };
112}
113

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales