This Javascript sample shows how to render three synchronized panels where the middle panel shows pixel differences between the two documents. Learn more about our Web SDK.
1(async exports => {
2 const Core = exports.Core;
3 const PDFNet = exports.Core.PDFNet;
4 Core.setWorkerPath('../../../lib/core');
5 Core.enableFullPDF();
6 await PDFNet.initialize();
7
8 const parentDoc = window.parent.window.document;
9
10 // Replace with your license key here as it needs to be passed when instantiating the worker transport promise
11 const licenseKey = undefined;
12
13 // Shared worker
14 const workerTransportPromise = Core.initPDFWorkerTransports('pdf', {}, licenseKey);
15
16 const containers = ['viewer1', 'viewer2'];
17 const instances = [];
18 const initialFiles = ['/samples/files/semantic_test_doc_1.pdf', '/samples/files/semantic_test_doc_2.pdf'];
19
20 let scrollTimeout = null;
21 let originalScroller = null;
22
23 const initializeViewer = containerName => {
24 return new Promise(resolve => {
25 WebViewer(
26 {
27 path: '../../../lib',
28 // Use shared worker
29 workerTransportPromise,
30 fullAPI: true,
31 },
32 document.getElementById(containerName)
33 ).then(instance => {
34 instance.Core.syncNamespaces({ PDFNet });
35
36 instance.Core.documentViewer.addEventListener('documentLoaded', () => {
37 const scrollView = instance.Core.documentViewer.getScrollViewElement();
38 scrollView.onscroll = function() {
39 if (!originalScroller || originalScroller === scrollView) {
40 originalScroller = scrollView;
41 const leftPercentage = scrollView.scrollLeft / scrollView.scrollWidth;
42 const topPercentage = scrollView.scrollTop / scrollView.scrollHeight;
43 syncDocumentContainerScrolls(leftPercentage, topPercentage);
44 clearTimeout(scrollTimeout);
45 scrollTimeout = setTimeout(() => {
46 originalScroller = null;
47 }, 50);
48 }
49 };
50
51 // Update zoom value of the WebViewer instances
52 instance.Core.documentViewer.addEventListener('zoomUpdated', zoom => {
53 // zoom events will also trigger a scroll event
54 // set the original scroll to be the same panel that first triggers the zoom event
55 // so that scroll events are handled properly and in the correct order
56 // some browsers such as Chrome do not respect the scroll event ordering correctly
57 if (!originalScroller) {
58 originalScroller = scrollView;
59 clearTimeout(scrollTimeout);
60 scrollTimeout = setTimeout(() => {
61 originalScroller = null;
62 }, 50);
63 }
64 syncZoom(zoom);
65 });
66
67 instance.Core.documentViewer.addEventListener('rotationUpdated', rotation => {
68 syncRotation(rotation);
69 });
70 });
71
72 instances.push(instance);
73 resolve(instance);
74 });
75 });
76 };
77
78 const main = async () => {
79 const initTasks = containers.map(containerName => initializeViewer(containerName));
80
81 const docTasks = initialFiles.map(initialFile => PDFNet.PDFDoc.createFromURL(initialFile));
82
83 await Promise.all([...initTasks, ...docTasks]);
84 const docs = await Promise.all(docTasks);
85
86 await compareDoc(docs[0], docs[1]);
87
88 parentDoc.getElementById('fileUpload1').disabled = false;
89 parentDoc.getElementById('fileUpload2').disabled = false;
90 const compareButton = parentDoc.getElementById('compareButton');
91 compareButton.addEventListener('click', async () => {
92 const doc1 = uploadedDoc[0];
93 const doc2 = uploadedDoc[1];
94 disableCompareButton();
95 await compareDoc(doc1, doc2);
96 });
97 };
98
99 main();
100
101 const uploadedDoc = [null, null];
102 const recentDiffs = [];
103
104 const syncDocumentContainerScrolls = (scrollLeftPercentage, scrollTopPercentage) => {
105 instances.forEach(instance => {
106 const scrollView = instance.Core.documentViewer.getScrollViewElement();
107 if (!scrollView) {
108 return;
109 }
110 const currentLeftPosition = scrollView.scrollLeft / scrollView.scrollWidth;
111 const currentTopPosition = scrollView.scrollTop / scrollView.scrollHeight;
112 if (currentLeftPosition !== scrollLeftPercentage) {
113 scrollView.scrollLeft = scrollView.scrollWidth * scrollLeftPercentage;
114 }
115 if (currentTopPosition !== scrollTopPercentage) {
116 scrollView.scrollTop = scrollView.scrollHeight * scrollTopPercentage;
117 }
118 });
119 };
120
121 const syncZoom = zoom => {
122 instances.forEach(instance => {
123 if (instance.UI.getZoomLevel() !== zoom) {
124 instance.UI.setZoomLevel(zoom);
125 }
126 });
127 };
128
129 const syncRotation = rotation => {
130 instances.forEach(instance => {
131 const documentViewer = instance.Core.documentViewer;
132 if (documentViewer.getRotation() !== rotation) {
133 documentViewer.setRotation(rotation);
134 }
135 });
136 };
137
138 const compareDoc = async (doc1, doc2) => {
139 const leftPageCount = await doc1.getPageCount();
140 const rightPageCount = await doc2.getPageCount();
141
142 const leftDoc = await PDFNet.PDFDoc.create();
143 leftDoc.lock();
144
145 const rightDoc = await PDFNet.PDFDoc.create();
146 rightDoc.lock();
147
148 const newDoc = await PDFNet.PDFDoc.create();
149 newDoc.lock();
150
151 await newDoc.appendTextDiffDoc(doc1, doc2);
152
153 const totalPageCount = await newDoc.getPageCount();
154 const isLeftDocLarger = leftPageCount > rightPageCount;
155 const smallerCount = leftPageCount > rightPageCount ? leftPageCount : rightPageCount;
156
157 for (let i = 0; i < totalPageCount; i++) {
158 const page = await newDoc.getPage(i + 1);
159 if (i === smallerCount) {
160 if (isLeftDocLarger) {
161 await leftDoc.pagePushBack(page);
162 } else {
163 await rightDoc.pagePushBack(page);
164 }
165 continue;
166 }
167 if (i % 2 === 0) {
168 await leftDoc.pagePushBack(page);
169 } else {
170 await rightDoc.pagePushBack(page);
171 }
172 }
173
174 await newDoc.unlock();
175 await leftDoc.unlock();
176 await rightDoc.unlock();
177
178 instances[0].UI.loadDocument(leftDoc);
179 instances[1].UI.loadDocument(rightDoc);
180
181 recentDiffs.push([...uploadedDoc]);
182
183 // Skip default comparison
184 if (recentDiffs.length === 1) {
185 return;
186 }
187
188 const recentElement = parentDoc.getElementById('recentFiles');
189 const comparisonElement = document.createElement('button');
190 comparisonElement.innerText = `Compare ${doc1.fileName} (A) & ${doc2.fileName} (B)`;
191 comparisonElement.classList.add('link');
192 comparisonElement.onclick = onClickRecentLink.bind({ idx: recentDiffs.length - 1 });
193 recentElement.appendChild(comparisonElement);
194 };
195
196 const enableCompareButton = async () => {
197 const compareButton = parentDoc.getElementById('compareButton');
198
199 if (!compareButton.classList.contains('disabled')) {
200 return;
201 }
202
203 compareButton.classList.remove('disabled');
204 };
205
206 const disableCompareButton = async () => {
207 const compareButton = parentDoc.getElementById('compareButton');
208
209 if (compareButton.classList.contains('disabled')) {
210 return;
211 }
212
213 compareButton.classList.add('disabled');
214 };
215
216 const getPDFDocFromUpload = async (file, fileIndex) => {
217 const newDoc = await Core.createDocument(file, {});
218 uploadedDoc[fileIndex] = await newDoc.getPDFDoc();
219 uploadedDoc[fileIndex].fileName = file.name;
220 if (uploadedDoc[1] !== null && uploadedDoc[0] !== null) {
221 enableCompareButton();
222 }
223 };
224
225 parentDoc.getElementById('fileUpload1').addEventListener('change', e => {
226 getPDFDocFromUpload(e.target.files[0], 0);
227 });
228
229 parentDoc.getElementById('fileUpload2').addEventListener('change', e => {
230 getPDFDocFromUpload(e.target.files[0], 1);
231 });
232
233 const onClickRecentLink = async function() {
234 await compareDoc(recentDiffs[this.idx][0], recentDiffs[this.idx][1]);
235 };
236})(window);
237// eslint-disable-next-line spaced-comment
238//# sourceURL=config.js
Did you find this helpful?
Trial setup questions?
Ask experts on DiscordNeed other help?
Contact SupportPricing or product questions?
Contact Sales