Hello, We have a custom annotation tool that we use to annotate a text insertion in a document when the user reviews the document. We want to remove the resize option on the annotation icon that is displayed like a bubble shown in the screenshot. Can you please help with how this can be done?
Hi,
In your code of where it creates the annotation, can you try setting the ‘NoResize’ to be false?
Sample code snippet:
annotation.NoResize = false;
https://www.pdftron.com/api/web/Annotations.Annotation.html
Thanks,
Anthony Chen
const updateXFDF = (action, xmlString, userSelect, userAnnotations) => {
if (areAllAnnotationsEmpty(userAnnotations)) {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
if (
xmlDoc.getElementsByTagName("ffield").length > 0 &&
xmlDoc.getElementsByTagName("widget").length > 0
) {
const ffield = xmlDoc.getElementsByTagName("ffield")[0].outerHTML;
const widget = xmlDoc.getElementsByTagName("widget")[0].outerHTML;
setUserAnnotations((prevState) => {
const updatedAnnotations = prevState.map((user) => {
if (user.userID === userSelect) {
return {
...user,
xml: [{ ffield: ffield, widget: widget }],
};
}
return user;
});
return updatedAnnotations;
});
}
} else {
// Iterate over each user's annotations
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
xmlDoc.querySelectorAll("widget").forEach((widget) => {
const widgetName = widget.getAttribute("name");
const ffieldName = widget.getAttribute("field");
let widgetFound = false;
userAnnotations.forEach((user) => {
user.xml.forEach((xml) => {
if (xml.widget.includes(widgetName)) {
// Replace the ffield and widget with new values from the main XML
xml.ffield = xmlDoc.querySelector(
`ffield[name="${ffieldName}"]`
).outerHTML;
xml.widget = widget.outerHTML;
widgetFound = true;
}
});
});
// If the widget was not found in userAnnotations, add it
if (!widgetFound) {
userAnnotations.forEach((user) => {
if (user.userID === userSelect) {
// Assuming you want to add to the current user's annotations
user.xml.push({
ffield: xmlDoc.querySelector(`ffield[name="${ffieldName}"]`)
.outerHTML,
widget: widget.outerHTML,
});
}
});
}
});
// Update the state with the modified userAnnotations
setUserAnnotations(userAnnotations);
}
};
// if using a class, equivalent of componentDidMount
useEffect(() => {
if (webViewer.attachmentBlob) {
WebViewer(
{
path: "/webviewer/lib",
showLocalFilePicker: true,
fullAPI: true,
licenseKey:****
},
viewer.current
).then(async (instance) => {
setInstance(instance);
instance.UI.loadDocument(base64ToBlob(webViewer.attachmentBlob), {
filename: fileName,
});
const { documentViewer, annotationManager} =
instance.Core;
//======================================== disable header =====================================//
instance.UI.disableElements([
"annotationPopup",
"outlinesPanelButton",
"comboBoxFieldToolGroupButton",
"listBoxFieldToolGroupButton",
"toolsOverlay",
"toolbarGroup-Shapes",
"toolbarGroup-Edit",
"toolbarGroup-Insert",
"shapeToolGroupButton",
"menuButton",
"freeHandHighlightToolGroupButton",
"underlineToolGroupButton",
"freeHandToolGroupButton",
"stickyToolGroupButton",
"squigglyToolGroupButton",
"strikeoutToolGroupButton",
"notesPanel",
"viewControlsButton",
"selectToolButton",
"toggleNotesButton",
"searchButton",
"freeTextToolGroupButton",
"crossStampToolButton",
"checkStampToolButton",
"dotStampToolButton",
"rubberStampToolGroupButton",
"dateFreeTextToolButton",
"eraserToolButton",
"panToolButton",
"signatureToolGroupButton",
"viewControlsOverlay",
"contextMenuPopup",
]);
//======================================== disable header =====================================//
//======================================== for cutome side bar =====================================//
// Example handler for when the dropdown value changes
const handleDropdownChange = (selectedValue) => {
setSelectedUser(selectedValue);
};
const openCustomModal = () => {
setOpenAddParticipentModal(true); // Open the custom modal
};
// Create a render function for the custom panel
const renderCustomPanel = () => {
return (
<div>
<label htmlFor="participantDropdown">{t("Participant")}</label>
<select
id="participantDropdown"
name="Participant"
onChange={(e) => handleDropdownChange(e.target.value)}
>
<option value="user1">user1</option>
<option value="user2">user2</option>
{/* Add more options as needed */}
</select>
<button onClick={openCustomModal}>Open Custom Modal</button>
</div>
);
};
var myCustomPanel = {
tab: {
dataElement: "customPanelTab",
title: "customPanelTab",
img: "/favicon-32x32.png",
},
panel: {
dataElement: "customPanel",
render: renderCustomPanel,
},
};
instance.UI.setCustomPanel(myCustomPanel);
//======================================== for cutome side bar =====================================//
//======================================== header save button =====================================//
async function generateBase64FromBlob(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function () {
const base64String = reader.result.split(",")[1];
resolve(base64String);
};
reader.onerror = function (error) {
reject(error);
};
reader.readAsDataURL(blob);
});
}
instance.UI.setHeaderItems((header) => {
header.push({
type: "actionButton",
img: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></svg>',
onClick: async () => {
const xfdfString = await annotationManager.exportAnnotations();
console.log("xfdfStringxfdf String", xfdfString);
// Remove annotations from the xfdfString
const doc = documentViewer.getDocument();
const data = await doc.getFileData({}); // No xfdfString for annotations
const arr = new Uint8Array(data);
const blob = new Blob([arr], { type: "application/pdf" });
generateBase64FromBlob(blob)
.then((base64String) => {
console.log(
"xfdfStringxfdf PDF Base64 String:",
base64String
);
// Here you can use the base64String as needed
})
.catch((error) => {
console.error("Error generating base64 string:", error);
});
// Dispatch your Redux action to send the data to the API
if (Number(commingFrom) === 1) {
const apiData = {
TaskID: taskId, // Assuming taskId is defined in your component
TaskAttachementID: attachmentID, // Assuming attachmentID is defined in your component
AnnotationString: xfdfString, // Pass the annotations data here
};
// for todo
dispatch(addAnnotationsOnToDoAttachement(navigate, t, apiData));
} else if (Number(commingFrom) === 2) {
let notesData = {
NoteID: taskId,
NoteAttachementID: attachmentID,
AnnotationString: xfdfString,
};
dispatch(
addAnnotationsOnNotesAttachement(navigate, t, notesData)
);
// for notes
} else if (Number(commingFrom) === 3) {
let resolutionData = {
ResolutionID: taskId,
ResolutionAttachementID: attachmentID,
AnnotationString: xfdfString,
};
dispatch(
addAnnotationsOnResolutionAttachement(
navigate,
t,
resolutionData
)
);
// for resultion
} else if (Number(commingFrom) === 4) {
// for data room
let dataRoomData = {
FileID: attachmentID,
AnnotationString: xfdfString,
};
dispatch(
addAnnotationsOnDataroomAttachement(navigate, t, dataRoomData)
);
}
},
});
header.push({
type: "actionButton",
img: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></svg>',
onClick: async () => {},
});
});
//======================================== header save button =====================================//
//======================================== for documentLoaded =====================================//
await documentViewer.getAnnotationsLoadedPromise();
documentViewer.addEventListener("documentLoaded", async () => {
// annotManager.setCurrentUser(name);
if (webViewer.xfdfData !== "" && annotationManager) {
try {
await annotationManager.importAnnotations(
pdfResponceDataRef.current
);
} catch (error) {
console.log("importAnnotations", error);
}
}
});
//======================================== for documentLoaded =====================================//
});
}
}, [webViewer.attachmentBlob]);
useEffect(() => {
if (Instance) {
const { annotationManager } = Instance.Core;
annotationManager.addEventListener(
"annotationChanged",
async (annotations, action, { imported }) => {
if (imported) {
return;
}
try {
annotations.NoResize = false;
// Export annotations to XFDF format using `exportAnnotations`
const xfdfString = await annotationManager.exportAnnotations();
// Update the user's annotations based on the action
updateXFDF(
action,
xfdfString,
selectedUserRef.current,
userAnnotationsRef.current
);
} catch (error) {
console.error("Error in annotationChanged event:", error);
}
}
);
}
}, [Instance]);```
in the upper comment i have provide my code
what i want is that disable resized and rotation of annotations in my ui how can i do that
Hello prabahar.kuppuswamy1,
You can set the NoResize option on your annotation:
https://docs.apryse.com/api/web/Core.Annotations.Annotation.html#NoResize__anchor
Best regards,
Tyler