Q:
Is it possible to have tools like Adobe’s insert text and replace text tools that create caret annotations?
A:
Yes, the following code will work with WebViewer 7.0. For older versions the allQuads index values will be 0-indexed, so add one to the page number.
const { Annotations, Tools, annotManager, docViewer } = instance;
// shared helper function that creates caret annotation at the end of the selection
const createCaretAnnotation = (quads, data) => {
const lastQuad = quads[quads.length - 1];
const maxY = Math.max(lastQuad.y1, lastQuad.y2, lastQuad.y3, lastQuad.y4);
const minY = Math.min(lastQuad.y1, lastQuad.y2, lastQuad.y3, lastQuad.y4);
const maxX = Math.max(lastQuad.x1, lastQuad.x2, lastQuad.x3, lastQuad.x4);
const minX = Math.min(lastQuad.x1, lastQuad.x2, lastQuad.x3, lastQuad.x4);
let textRotation;
if (lastQuad.x1 === minX && lastQuad.y1 === maxY) {
textRotation = 0;
} else if (lastQuad.x1 === maxX && lastQuad.y1 === maxY) {
textRotation = 90;
} else if (lastQuad.x1 === maxX && lastQuad.y1 === minY) {
textRotation = 180;
} else if (lastQuad.x1 === minX && lastQuad.y1 === minY) {
textRotation = 270;
}
const caret = new Annotations.CaretAnnotation();
let quadHeight;
if (textRotation === 0 || textRotation === 180) {
quadHeight = maxY - minY;
} else {
quadHeight = maxX - minX;
}
const caretSize = quadHeight / 2;
caret.PageNumber = data.pageNumber;
// position center of caret at the edge of strikeout
// center relative to the strikeout
if (textRotation === 0) {
caret.X = maxX - (caretSize / 2);
caret.Y = maxY - caretSize;
} else if (textRotation === 90) {
caret.X = maxX - caretSize;
caret.Y = minY - (caretSize / 2);
} else if (textRotation === 180) {
caret.X = minX - (caretSize / 2);
caret.Y = minY;
} else if (textRotation === 270) {
caret.X = minX;
caret.Y = maxY - (caretSize / 2);
}
caret.Width = caretSize;
caret.Height = caretSize;
caret.Author = annotManager.getCurrentUser();
caret.StrokeColor = new Annotations.Color(0, 0, 255);
caret.Rotation = textRotation;
annotManager.addAnnotation(caret);
if (data.annotation) {
annotManager.groupAnnotations(data.annotation, [caret]);
}
annotManager.redrawAnnotation(caret);
return caret;
};
// Replace Text Tool
const ReplaceTextTool = function() {
Tools.TextStrikeoutCreateTool.apply(this, arguments);
};
ReplaceTextTool.prototype = new Tools.TextStrikeoutCreateTool();
const replaceToolName = 'ReplaceTextTool';
const replaceTextTool = new ReplaceTextTool(docViewer);
replaceTextTool.on('annotationAdded', function(annotation) {
// adds the caret annotation when the strikeout is added with the custom tool
createCaretAnnotation(annotation.Quads, {
annotation,
pageNumber: annotation.PageNumber
});
instance.focusNote(annotation.Id);
});
instance.registerTool({
toolName: replaceToolName,
toolObject: replaceTextTool,
buttonImage: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">' +
'<path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/>' +
'<path d="M0 0h24v24H0z" fill="none"/>' +
'</svg>',
buttonName: 'replaceTextToolButton',
tooltip: 'Replace Text'
}, Annotations.CaretAnnotation);
instance.setHeaderItems(function(header) {
const replaceTextButton = {
type: 'toolButton',
toolName: replaceToolName
};
header.push(replaceTextButton);
});
// Insert Text Tool
const InsertTextTool = function() {
Tools.TextSelectTool.apply(this, arguments);
};
InsertTextTool.prototype = new Tools.TextSelectTool();
InsertTextTool.prototype.switchIn = function() {
Tools.TextSelectTool.prototype.switchIn.apply(this, arguments);
Tools.Tool.ENABLE_AUTO_SWITCH = false;
};
InsertTextTool.prototype.switchOut = function() {
Tools.TextSelectTool.prototype.switchOut.apply(this, arguments);
Tools.Tool.ENABLE_AUTO_SWITCH = true;
};
const insertToolName = 'InsertTextTool';
const insertTextTool = new InsertTextTool(docViewer);
insertTextTool.on('selectionComplete', (startLocation, allQuads) => {
const selectedPageNumbers = Object.keys(allQuads);
const pageNumber = selectedPageNumbers[selectedPageNumbers.length - 1];
const caret = createCaretAnnotation(allQuads[pageNumber], { pageNumber });
instance.focusNote(caret.Id);
});
instance.registerTool({
toolName: insertToolName,
toolObject: insertTextTool,
buttonImage: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">' +
'<path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/>' +
'<path d="M0 0h24v24H0z" fill="none"/>' +
'</svg>',
buttonName: 'insertTextToolButton',
tooltip: 'Insert Text'
}, Annotations.CaretAnnotation);
instance.setHeaderItems(function(header) {
const insertTextButton = {
type: 'toolButton',
toolName: insertToolName
};
header.push(insertTextButton);
});