There are a few breaking changes and other deprecated APIs when migrating to v8 from older versions.
Instance namespace adjustments
This is not actually a breaking change since you can still access the old namespaces, but a number of namespaces have been restructured to more logically group things. All of the WebViewer Core namespaces can now be found on instance.Core
and all of the UI related APIs and namespaces can be found on instance.UI
. The CoreControls
namespace now only exists for backwards compatibility and you can access all functions that were previously found on CoreControls
, directly on the Core
namespace.
annotManager
has been renamed toannotationManager
anddocViewer
has been renamed todocumentViewer
.on
has been renamed toaddEventListener
andoff
has been renamed toremoveEventListener
Before:
WebViewer(...)
then(instance => {
const { docViewer, annotManager, Tools, Annotations, PDFNet, CoreControls } = instance;
CoreControls.setWorkerPath(...);
instance.disableElements([...]);
docViewer.on('documentLoaded', () => {
});
});
After:
WebViewer(...)
then(instance => {
const { Core, UI } = instance;
const { documentViewer, annotationManager, Tools, Annotations, PDFNet } = Core;
Core.setWorkerPath(...);
instance.UI.disableElements([...]);
documentViewer.addEventListener('documentLoaded', () => {
});
});
Inside a config file
When running code inside a config file you can now access instance
on the window and it will be identical to the instance
that is resolved from the WebViewer
function. readerControl
no longer exists inside the WebViewer iframe.
Breaking changes
CustomData changes
"Custom data" is stored on annotations and is automatically saved and restored when exporting and importing XFDF, as well as downloading and re-opening a PDF.
To be consistent and fully compatible with other platforms the setCustomData
function now only accepts a string as the value. If you pass something other than a string it will automatically be stringified. Similarly getCustomData
will only return a string.
To more easily enforce the proper types, setting of the CustomData
property directly is now no longer possible. Please use setCustomData
to set your properties instead.
If you would like to use object types you can use JSON.stringify
and JSON.parse
, or parseInt
and parseFloat
for numbers.
Before:
annotation.setCustomData('number-data', 1);
annotation.setCustomData('object-data', { abc: 123 });
annotation.getCustomData('number-data'); // the number 1
annotation.getCustomData('object-data'); // an object
annotation.CustomData = {
key1: 1,
key2: 2
};
annotation.CustomData.key1; // the number 1
After:
annotation.setCustomData('number-data', '1');
annotation.setCustomData('object-data', JSON.stringify({ abc: 123 }));
annotation.getCustomData('number-data'); // the string '1'
JSON.parse(annotation.getCustomData('object-data')); // JSON.parse returns the object
// these will warn and automatically stringify the value
annotation.setCustomData('number-data', 1);
annotation.setCustomData('object-data', { abc: 123 });
// this code no longer works
// annotation.CustomData = {
// key1: 1,
// key2: 2
// };
// annotation.CustomData.key1;
Legacy UI no longer officially supported
With PDF.js Express 8.0, the legacy UI is not officially supported. If you would like to continue using the legacy UI you can stay on version 7.3. Note that the legacy 7.3 branch is available in the public UI repo and you can attempt to update it to be compatible with 8.0 if you like.
Updated annotation linking APIs
The associateLink
, getAssociatedLinks
and unassociateLinks
APIs have been removed. Links are now associated with annotations by using the normal annotation grouping APIs, for example annotationManager.groupAnnotations
.
If you have associated links already saved in your XFDF then WebViewer will automatically convert them over to groups the next time they are loaded.
Before:
annotation.associateLink(linkAnnotation);
After:
annotationManager.groupAnnotations(annotation, [linkAnnotation]);
annotationSelected event never returns null for annotation list
In previous version when all annotations were deselected the annotationSelected
event would provide null
as the annotations
parameter of the event for a deselect
action. Now all deselect
actions will return an array of the annotations that were deselected, never null.
Before:
annotManager.on('annotationSelected', (annotations, action) => {
// when all annotations are deselected, action is 'deselected', annotations is null
});
After:
annotationManager.addEventListener('annotationSelected', (annotations, action) => {
// when all annotations are deselected, action is 'deselected'
// annotations is the array of annotations that were previously selected, possibly an empty array
});
CoreControls.js renamed
The file lib/core/CoreControls.js
has been renamed to lib/core/webviewer-core.min.js
.
getDisplayAuthor parameter change
The AnnotationManager
function getDisplayAuthor
previously would take an annotation object as a parameter and returned the transformed author name, however sometimes there were times that a transformed author name was needed but no annotation object existed yet.
In WebViewer 8.0 the getDisplayAuthor
function now accepts the author id so that it can be used in all cases, with or without an anotation. This also means that the setAnnotationDisplayAuthorMap
callback function receives an author id instead of an annotation.
Before:
annotManager.setAnnotationDisplayAuthorMap((annotation) => {
if (annotation.Id === '1') {
return 'John';
} else {
return 'Guest';
}
});
const displayAuthor = annotManager.getDisplayAuthor(annotation);
After:
annotationManager.setAnnotationDisplayAuthorMap((authorId) => {
if (authorId === '1') {
return 'John';
} else {
return 'Guest';
}
});
const displayAuthor = annotationManager.getDisplayAuthor(annotation.Author);
A few functions are now asynchronous
RubberStampCreateTool
SignatureCreateTool
Consistent NoZoom handling across all annotations
The NoZoom
property on annotations now works consistently for all types of annotations. If you were overriding the draw
function for sticky note annotations then it has changed somewhat. Previously the canvas context was already translated to where the sticky note was drawn, but now you must first translate by annotation.X
and annotation.Y
.
Before:
Annotations.setCustomDrawHandler(Annotations.StickyAnnotation, function(ctx, pageMatrix, options) {
// ctx functions here without translating
});
After:
Annotations.setCustomDrawHandler(Annotations.StickyAnnotation, function(ctx, pageMatrix, options) {
ctx.translate(options.annotation.X, options.annotation.Y);
// continue with previous drawing code
});
Small parameter updates for consistency
The callback for documentViewer.setPagesUpdatedInternalAnnotationsTransform
now provides 1-indexed page numbers instead of 0-indexed page numbers.
Before:
docViewer.setPagesUpdatedInternalAnnotationsTransform((xfdfData, pageList, callback) => {
console.log(pageList); // 0, 1, 2, etc
});
After:
documentViewer.setPagesUpdatedInternalAnnotationsTransform((xfdfData, pageList, callback) => {
console.log(pageList); // 1, 2, 3 etc
});
The documentViewer.select
function expects the point objects to have the pageNumber
property instead of pageIndex
.
Before:
const location1 = {
x: 0,
y: 100,
pageIndex: 0
};
const location2 = {
x: 100,
y: 200,
pageIndex: 0
};
docViewer.select(location1, location2);
After:
const location1 = {
x: 0,
y: 100,
pageNumber: 1
};
const location2 = {
x: 100,
y: 200,
pageNumber: 1
};
documentViewer.select(location1, location2);
Deprecated usages
To make the API more consistent many boolean APIs have mostly moved to the form enableXYZ/disableXYZ/isXYZEnabled
. The previous functions are still accessible but have been deprecated.
AnnotationManager
setReadOnly
becomesenableReadOnlyMode
,disableReadOnlyMode
,isReadOnlyModeEnabled
setFreeformRotationEnabled
becomesenableFreeformRotation
,disableFreeformRotation
enableRedaction(boolean)
becomesenableRedaction
,disableRedaction
setIsAdminUser
,getIsAdminUser
becomespromoteUserToAdmin
,demoteUserFromAdmin
,isUserAdmin
DocumentViewer
getRightToLeftPages
,setRightToLeftPages
becomesenableRightToLeftPageRendering
,disableRightToLeftPageRendering
,isRightToLeftPageRenderingEnabled
setLoadAnnotationsFromVisiblePages
becomesenableLoadingAnnotationsFromVisiblePages
,disableLoadingAnnotationsFromVisiblePages
setEnableAutomaticLinking
becomesenableAutomaticLinking
,disableAutomaticLinking
setEnableStylusMode
becomesenableStylusMode
,disableStylusMode
Document
enableColorSeparations(boolean)
becomesenableColorSeparations
,disableColorSeparations
setOfflineModeEnabled
becomesenableOfflineMode
,disableOfflineMode
Tools
AnnotationSelectTool.setEnableImmediateActionOnAnnotationSelection
becomesAnnotationSelectTool.enableImmediateActionOnAnnotationSelection
,AnnotationSelectTool.disableImmediateActionOnAnnotationSelection
DistanceMeasurementCreateTool.setEnableLeaderLines
becomesDistanceMeasurementCreateTool.enableLeaderLines
,DistanceMeasurementCreateTool.disableLeaderLines
RedactionCreateTool.setEnableTextAutoSize
becomesRedactionCreateTool.enableAutoSizedText
,RedactionCreateTool.disableAutoSizedText
setAllowCreationOverAnnotation
becomesenableCreationOverAnnotation
,disableCreationOverAnnotation
Other
CoreControls.enableFullPDF(boolean)
becomesCore.enableFullPDF
,Core.disableFullPDF
annotation.setRotationControlEnabled
becomesannotation.enableRotationControl
,annotation.disableRotationControl
popupAnnotation.setOpen
becomespopupAnnotation.open
,popupAnnotation.close
- WebViewer constructor option
pdftronServer
becomeswebviewerServerURL
APIs removed
Previously deprecated APIs that have been removed:
- The deprecated
new PDFTron.WebViewer
constructor for WebViewer has been removed.
Before:
const viewerInstance = new PDFTron.WebViewer(options, viewerElement);
viewerElement.addEventListener('ready', () => {
// viewer ready
});
After:
WebViewer(options, viewerElement)
.then(viewerInstance => {
// viewer ready
});
annotation.getLeft()
useannotation.getX()
orannotation.X
insteadannotation.getRight()
useannotation.X + annotation.Width
insteadannotation.getTop()
useannotation.getY()
orannotation.Y
insteadannotation.getBottom()
useannotation.Y + annotation.Height
insteadsignatureWidget.isSignedInitially()
usesignatureWidget.isSignedDigitally()
insteadannotationManager.getAnnotCommand()
useannotationManager.exportAnnotCommand()
instead