If the user is using the Area, Ellipse, or Rectangular Area measurement tool, they will not be able to add note annotations or any other types of annotations. correct this issue

Product: Web viewer

Product Version: 11.7.1

Please give a brief summary of your issue:
If the user is using the Area, Ellipse, or Rectangular Area measurement tool, they will not be able to add note annotations or any other types of annotations. correct this issue

Please describe your issue and provide steps to reproduce it:
If the user is using the Area, Ellipse, or Rectangular Area measurement tool, they will not be able to add note annotations or any other types of annotations. correct this issue.
If user trying to add note annot after adding Area measurement, user not able to add.

Please provide a link to a minimal sample where the issue is reproducible:

Hello, I’m AiRon, an automated tech support bot :robot:
While you wait for one of our customer support representatives, I can help you with your question.


It sounds like you’re experiencing an issue with adding note annotations when using the Area, Ellipse, or Rectangular Area measurement tools in WebViewer. This problem may be related to how annotations are being handled or a configuration issue in your implementation.

Some things you can try:

  • Ensure that annotation permissions are correctly set to allow adding new annotations. Check the ReadOnly, Locked, and LockedContents properties.

  • Verify that there are no conflicting scripts or settings that might be preventing the addition of new annotations.

  • Check if the issue persists after resetting the measurement tools or switching between different annotation modes.

  • Consider reviewing the event listeners for annotations to ensure they are not being blocked or overridden unexpectedly.



Here are some resources that might help you:


Hopefully, this helps you solve your problem while you wait for a human to get back to you.

Hi there,

I am able to add a sticky note annotation on top of measurements annotations on the showcase demo:

Do you have a specific snap mode set? Can you reproduce this issue on our samples?

best regards,
Kevin

1 Like

Thanks for the reply. I have enable the snap.
Here is the code for your reference:

    EnableMeasurementSnap: function (instance) {
        const { documentViewer, Tools } = instance.Core;

        const snapMode =
            Tools.SnapModes.DEFAULT |
            Tools.SnapModes.END |
            Tools.SnapModes.MIDPOINT |
            Tools.SnapModes.INTERSECTION;
        const measurementTools = [
            Tools.ToolNames.DISTANCE_MEASUREMENT,
            Tools.ToolNames.ARC_MEASUREMENT,
            Tools.ToolNames.ELLIPSE_MEASUREMENT,
            Tools.ToolNames.AREA_MEASUREMENT,
            Tools.ToolNames.RECTANGULAR_AREA_MEASUREMENT,
            Tools.ToolNames.ELLIPSE_AREA_MEASUREMENT,
            Tools.ToolNames.ELLIPSE_MEASUREMENT,
            Tools.ToolNames.PERIMETER_MEASUREMENT,
        ];

        measurementTools.forEach(toolName => {
            const tool = documentViewer.getTool(toolName);
            if (tool && tool.setSnapMode) {
                tool.setSnapMode(snapMode);
            }
        });
    },
1 Like

Thank you for your reply,

I am still unable to reproduce this issue on the showcase demo using that code snippet:

Could you please share the exact steps or a minimal reproducible sample project to troubleshoot?

best regards,
Kevin

1 Like

Hello kkim,

Thanks for the response, I have add the complete code for your reference.
I have also notice one thing that , If i execute this part of my code.

const AttachedDocsItems = [];
let Annotationsmark = [];
let fileList = [];
let core = '';
let percentageChangeModalCreated = false;
const rotationChanges = [];
let isComparePopupOpen = false;
let userID = '';
let isLayover = false;
let isSideBySide = false;
let isRotatingPages = false;
let isDocumentLoading = false;
let isImageStampPanelOpen = false;
let isDropListenerBound = false;
let dropInProgress = false;
let isRealtimeEnabled = true;
let currentPdfFileId = '';
let userAction = '';
let originalContentItemId = '';
let isImporting = false;
let selectedDepartments = new Set();
let saveStamp = false;
let caseTags = [];
let caseTagCount = [];
let currentSettings = {
    offComments: false,
    offStamps: false,
    offAnnotations: false,
    offPictures: false,
    onlyMyComments: false,
};
let url = '';
let lastStamp = null;
let connection = '';
let currentGroup = '';
let imageData = [];
let defaultComparaLayout = '';
let hideCADState = false;
const Apryse = {
    viewerId: '',
    pdffilepath: '',
    licenseKey: '',
    userId: '',
    annotationList: '',
    userName: '',
    annotationsData: '',
    stampData: '',
    rotationPage: '',
    rotationAngle: '',
    saveIcon: '',
    viewSettingIcon: '',
    compareIcon: '',
    title: '',
    bold: false,
    color: '',
    font: '',
    italic: false,
    isImageAddedFromPanel: false,
    underline: false,
    annotId: '',
    strikeout: false,
    textColor: '',
    stampUserName: '',
    isUserNameChecked: false,
    isDateChecked: false,
    subtitle: '',
    isTimeChecked: false,
    dateFormat: '',
    turnOffComments: false,
    turnOffStamps: false,
    turnOffAnnotations: false,
    turnOffPictures: false,
    turnOffForm: true,
    turnOffFillAndSign: true,
    turnOffSignature: true,
    isAdmin: true,
    signatureUrl: '',
    isForntEndDoc: false,
    permissions: [],
    files: [],
    departments: [],
    compareDefaultLayout: '',
    initilize: function () {
        $('.common-loading-spinner-text').text('Please do not close your browser or press the back button until the document has fully loaded.');
        $('.common-loading').show();
        WebViewer.Iframe({
            path: '/GovBuilt.PlanReview/webviewer',
            licenseKey: Apryse.licenseKey,
            initialDoc: !Apryse.isForntEndDoc ? Apryse.pdffilepath : null,
            loadSpinner: false,
            annotationUser: this.userId,
            compareDefaultLayout: Apryse.compareDefaultLayout,
            permissions: Apryse.permissions,
            fullAPI: true,
            UI: 'Modular',
            css: '/GovBuilt.PlanReview/css/viewer.min.css',
        }, document.getElementById(Apryse.viewerId))
            .then((instance) => {
                window.webViewerInstance = instance;
                core = instance.Core;
                const { documentViewer, annotationManager, Annotations } = instance.Core;
                const { Feature } = instance.UI;
                const { Color } = Annotations;
                const { PDFNet, Tools } = instance.Core;
                const UIEvents = instance.UI.Events; 

The issue is not reproduce.
Apryse.js (124.4 KB)

After few investigation I found the issue is then line of code

 connection = new signalR.HubConnectionBuilder()
     .withUrl(`/planReviewAnnotationHub?pdfFileId=${currentPdfFileId}`)
     .withAutomaticReconnect()
     .build();
 connection.start().then(() => {
 });
 connection.on("ReceiveAnnotation", function (annotationData, action) {
     if (!isRealtimeEnabled) {
         isRealtimeEnabled = true;
     }
     isImporting = true;
     instance.UI.enableElement('customCollaborationButton');
     if (action === 'delete') {
         const deletedAnnotIds = PartialApryse.GetAnnotationIdFromXFDF(annotationData);
         const existingAnnotations = annotationManager.getAnnotationsList();

         deletedAnnotIds.forEach(id => {
             const toDeleteAnnot = existingAnnotations.find(annot => annot.nj === id);
             if (toDeleteAnnot) {
                 annotationManager.deleteAnnotation(toDeleteAnnot);
             }
         });
     } else {
         annotationManager.importAnnotations(annotationData).then(() => {
             isImporting = false;
         });
     }
     isImporting = false;
     instance.Core.documentViewer.refreshAll();
     instance.Core.documentViewer.updateView();
 });

 connection.on("ReceiveRealtimeToggle", function (newState) {
     isRealtimeEnabled = newState;
 });
 connection.on("ReceiveUserCountChanged", function (userCount) {
     if (userCount > 1) {
         instance.UI.enableElement(['turnOffAutoSync']);
         instance.UI.disableElement(['turnOnAutoSync']);
     } else {
         instance.UI.disableElement(['turnOffAutoSync']);
     }
 });

annotationManager.addEventListener('annotationChanged', function (annotations, action) {
     if (isImporting) return;
     if (['add', 'modify', 'delete'].includes(action)) {
         annotationManager.exportAnnotations({ annotationList: annotations, action: action }).then(xfdfString => {
             connection.invoke("SendAnnotationAsync", currentPdfFileId, xfdfString, action);
         });
     }
 });  
annotationManager.addEventListener('annotationChanged', handleAnnotationChanged); 
the issue is in this. When i uncomment it user not able to add other annotation over rectangular area annotation. If I comment this then user able to add other annotation over rectangular area annotation

When i uncomment it user not able to add other annotation over rectangular area annotation. If I comment this then user able to add other annotation over rectangular area annotation

const xfdf = await annotationManager.exportAnnotations();

issue is with this line

 annotationManager.addEventListener('annotationChanged', async (annotations, action, info) => {
     if (isImporting || isDocumentLoading) return;

     const measurementTools = [
         'AnnotationCreateAreaMeasurement',
         'AnnotationCreateEllipseAreaMeasurement',
         'AnnotationCreateRectangularAreaMeasurement',
         'AnnotationCreateCountMeasurement'
     ];


     const isMeasurement = annotations.some(a => measurementTools.includes(a.ToolName));
     if (isMeasurement) {
         if (action === 'add' || action === 'modify' || action === 'delete') {
             const xfdf = await annotationManager.exportAnnotations();
             annotations.forEach(a => {
                 if (measurementTools.includes(a.ToolName)) {
                     PartialApryse.ProcessAnnotation(a, xfdf, action);
                 }
             });

             PartialApryse.SaveDocumentAnnotations();
         }
         return; 
     }

     if (['add', 'modify', 'delete'].includes(action)) {
         const xfdf = await annotationManager.exportAnnotations({
             annotationList: annotations,
             action
         });
         connection.invoke("SendAnnotationAsync", currentPdfFileId, xfdf, action);
     }

     const stamps = annotations.filter(a => a.ToolName === "AnnotationCreateRubberStamp");
     if (stamps.length > 0 && saveStamp && action !== 'delete') {
         const xfdfStrings = await annotationManager.exportAnnotationCommand();
         stamps.forEach(a => PartialApryse.ProcessAnnotation(a, xfdfStrings, action));
         PartialApryse.SaveDocumentAnnotations();
     }
 });
1 Like

Hi there,

Thank you for the report,

The issue is due to the exportAnnotations API on the measurement annotation.
You can workaround this by removing the appearance on the annotation:

measurementAnnotation.removeCustomAppearance()
await annotationManager.redrawAnnotation(measurementAnnotation)

best regards,
Kevin

1 Like

Thank for the response. I’ve tried the code you have provide it work for the first time but if user try again I still face same issue.

For your reference I have added updated code:

 annotationManager.addEventListener('annotationChanged', async (annots, action, info = {}) => {
     if (isImporting) return;
     if (info.imported || isDocumentLoading) return;
     const stampAnnots = annots.filter(a => a.ToolName === "AnnotationCreateRubberStamp");

     if (stampAnnots.length > 0 && !saveStamp && action !== 'delete' && action !== 'modify') {
         return;
     }

     if (action === 'add' &&
         annots?.[0]?.ToolName === 'AnnotationCreateCountMeasurement' &&
         info.imported === false) {

         const annotation = annots[0];
         const zoom = documentViewer.getZoomLevel();

         const x1 = annotation.X + annotation.Width / 2 / zoom;
         const y1 = annotation.Y - annotation.Height / 2 / zoom;
         const x2 = x1 + annotation.Width / zoom;
         const y2 = y1 + annotation.Height / zoom;

         const rect = new Annotations.Rect(x1, y1, x2, y2);
         annotation.setRect(rect);
     }

     if (['add', 'modify', 'delete'].includes(action)) {
         const xfdfString = await annotationManager.exportAnnotations({
             annotationList: annots,
             action: action
         });

         connection.invoke("SendAnnotationAsync", currentPdfFileId, xfdfString, action);
     }

     const measurementTools = [
         'AnnotationCreateDistanceMeasurement',
         'AnnotationCreatePerimeterMeasurement',
         'AnnotationCreateAreaMeasurement',
         'AnnotationCreateCountMeasurement',
         'AnnotationCreateEllipseMeasurement',
         'AnnotationCreateRectangularAreaMeasurement'
     ];

     const xfdfCommands = await annotationManager.exportAnnotationCommand();
     for (const annot of annots) {
         if (measurementTools.includes(annot.ToolName)) {
             annot.removeCustomAppearance();
             await annotationManager.redrawAnnotation(annot);
         }
         PartialApryse.ProcessAnnotation(annot, xfdfCommands, action);
     }

     PartialApryse.SaveDocumentAnnotations();
 });
![MeasurementIssue|video](upload://ycKJvmmtWlqn5zfx6dtY3n0WRk6.mp4)

1 Like

Thank you for your reply,

It looks like the appearance is being re-generated causing the same issue. We will let you know when we have additional information regarding this issue.

best regards,
Kevin

1 Like