window.onload = function() {
const viewer = new DsPdfViewer("#viewer", getViewerOptions());
configureViewerUI(viewer);
viewer.open("/document-solutions/javascript-pdf-viewer/demos/product-bundles/assets/pdf/sign-pdf-in-order.pdf");
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Sign PDF in order</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./src/styles.css">
<script src="/document-solutions/javascript-pdf-viewer/demos/product-bundles/build/dspdfviewer.js"></script>
<script src="/document-solutions/javascript-pdf-viewer/demos/product-bundles/build/wasmSupportApi.js"></script>
<script src="/document-solutions/javascript-pdf-viewer/demos/resource/js/init.js"></script>
<script src="./src/app.js"></script>
<script src="./src/config.js"></script>
</head>
<body>
<div id="viewer"></div>
</body>
</html>
#viewer {
height: 100%;
}
// exported global methods:
var getViewerOptions, configureViewerUI;
(function () {
// Graphical signature locations.
// Note that the { x, y } origin is at the bottom left.
var graphicalSignatureLocationsBottomLeft = {
// The key is the name of the PDF file in lower case without extension.
"sign-pdf-in-order": [
{ pageIndex: 0, x: 187, y: 73, w: 80, h: 20, title: "Buyer" },
{ pageIndex: 0, x: 420, y: 73, w: 80, h: 20, title: "Seller", color: "#1234dd" },
{ pageIndex: 1, x: 187, y: 73, w: 80, h: 20, title: "Buyer" },
{ pageIndex: 1, x: 420, y: 73, w: 80, h: 20, title: "Seller", color: "#1234dd" },
{ pageIndex: 2, x: 187, y: 73, w: 80, h: 20, title: "Buyer" },
{ pageIndex: 2, x: 420, y: 73, w: 80, h: 20, title: "Seller", color: "#1234dd" },
{ pageIndex: 3, x: 187, y: 73, w: 80, h: 20, title: "Buyer" },
{ pageIndex: 3, x: 420, y: 73, w: 80, h: 20, title: "Seller", color: "#1234dd" },
{ pageIndex: 4, x: 187, y: 73, w: 80, h: 20, title: "Buyer" },
{ pageIndex: 4, x: 420, y: 73, w: 80, h: 20, title: "Seller", color: "#1234dd" },
{ pageIndex: 5, x: 187, y: 73, w: 80, h: 20, title: "Buyer" },
{ pageIndex: 5, x: 420, y: 73, w: 80, h: 20, title: "Seller", color: "#1234dd" }
]
};
// Parameters for the "sign date" labels
const signDateLabelParams = {
// x offset from the position of the graphical signature
offset_x: 101,
// y offset from the position of the graphical signature
offset_y: 0,
// label width
w: 58,
// label height
h: 14
}
getViewerOptions = function getViewerOptions() {
return {
supportApi: {
apiUrl: window.top.SUPPORTAPI_URL, // e.g. "http://localhost:5004/api/pdf-viewer";
token: window.top.SUPPORTAPI_TOKEN, // e.g. "support-api-demo-net-core-token";
webSocketUrl: false
},
restoreViewStateOnLoad: false
};
}
configureViewerUI = function (viewer) {
viewer.addDefaultPanels();
viewer.addAnnotationEditorPanel();
viewer.onAfterOpen.register(function () {
populateSignature(viewer);
});
}
async function populateSignature(viewer) {
viewer.__onSignatureLinkEvent = onSignatureLinkEvent;
const locationsBottomLeft = graphicalSignatureLocationsBottomLeft[viewer.fileName.toLowerCase().replace(".pdf", "")];
if (locationsBottomLeft) {
for (let i = 0; i < locationsBottomLeft.length; i++) {
const locationInfo = locationsBottomLeft[i];
const pageIndex = parseInt(locationInfo.pageIndex);
const signTitle = locationInfo.title;
const rect = [locationInfo.x, locationInfo.y, locationInfo.x + locationInfo.w, locationInfo.y + locationInfo.h];
const signUiId = "signui_" + i;
const freeTextLabel = {
annotationType: 3, // AnnotationTypeCode.FREETEXT
subject: signUiId,
borderStyle: { width: 1, style: 2 },
fontSize: 6,
appearanceColor: "#fff59d",
color: locationInfo.color || "#f44336",
contents: "Sign Here",
textAlignment: 1,
rect: [rect[0], rect[3] - 12, rect[0] + 35, rect[3]]
};
await viewer.addAnnotation(pageIndex, freeTextLabel, { skipPageRefresh: true });
const viewerSelector = "#" + viewer.hostElement.id;
const linkAnnotation = {
annotationType: 2, // AnnotationTypeCode.LINK
subject: signUiId,
linkType: "js",
borderStyle: { width: 0, style: 5 },
color: "#2196f3",
jsAction: `if(app.viewerType == 'DsPdfViewer') {
var viewer = DsPdfViewer.findControl("${viewerSelector}");
viewer.__onSignatureLinkEvent(viewer, ${pageIndex}, "${signTitle}", "${signUiId}", ${rect[0]}, ${rect[1]}, ${(rect[2] - rect[0])}, ${(rect[3] - rect[1])});
}`,
rect: rect,
title: signTitle
};
await viewer.addAnnotation(pageIndex, linkAnnotation, { skipPageRefresh: true });
}
viewer.repaint();
}
}
function onSignatureLinkEvent(viewer, pageIndex, signTitle, signId, x, y, w, h) {
viewer.showSignTool({
subject: "AddGraphicalSignature", tabs: ["Type", "Draw"],
dialogLocation: "center",
pageIndex: pageIndex,
title: signTitle,
location: { x: x, y: y },
canvasSize: { width: w * 5, height: h * 5 },
destinationScale: 1 / 5,
convertToContent: true,
afterAdd: function (result) {
// remove current Sign UI and scroll to next one:
removeSignature(viewer, signId).then(function () {
viewer.addAnnotation(pageIndex, {
annotationType: 3, borderStyle: { width: 0 },
fontSize: 10, contents: new Date().toLocaleDateString("en-US"),
rect: [x + signDateLabelParams.offset_x, y + signDateLabelParams.offset_y, x + signDateLabelParams.offset_x + signDateLabelParams.w, y + signDateLabelParams.offset_y + signDateLabelParams.h],
convertToContent: true
},
{ skipPageRefresh: false }).then(function () {
scrollToNextSignature(viewer, signTitle);
});
});
}
});
}
async function removeSignature(viewer, signId) {
const annotations = await viewer.findAnnotations(signId, { findField: "subject", findAll: true });
for (let data of annotations) {
await viewer.removeAnnotation(data.pageIndex, data.annotation.id);
}
};
async function scrollToNextSignature(viewer, signTitle) {
const linkAnnotations = await viewer.findAnnotations(2, { findField: "annotationType", findAll: true });
const data = linkAnnotations.find((el) => el.annotation.title === signTitle) || linkAnnotations[0];
if(data) {
viewer.scrollAnnotationIntoView(data.pageIndex, data.annotation, "smooth");
} else {
alert("The document is fully signed.");
}
}
})();