Create a Grouping for Measurements by Tag and count the group

Product: Web viewer

Product Version: 11.7.1

Please give a brief summary of your issue:
Create a Grouping for Measurements by Tag and count the group.

Please describe your issue and provide steps to reproduce it:
I want to they the user ability to count by tag. I want to create custom tag through which user can group the annotation and able to count.

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.


To create a grouping for annotations by a custom tag and count them, you can use Apryse’s WebViewer’s AnnotationManager to manage and manipulate annotations. Here’s how you can approach this:

Some things you can try:

  • Use the AnnotationManager to add custom tags to your annotations. You can do this by adding custom data fields to the annotation objects.

  • Iterate over all annotations and group them based on the custom tags.

  • Use a JavaScript object or Map to keep track of the count of each group of annotations based on their tags.

  • Display the count of each group to the user in your application’s UI.




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.

Hello Rishu,

Thank you for contacting WebViewer Forums.

We have a built-in filter in the notesPanel that can filter through any specific annotation. You may also use a custom filter using setCustomNoteFilter(). More information can be found here: Apryse WebViewer Namespace: UI

For counting purposes, you may use getAnnotationsList() to look for a type of annotation you may want to count. More information here: Apryse WebViewer Class: AnnotationManager

Regards,
Luke

1 Like

. I have try using setCustomData method.
I have added the code which I have try:

GetCaseTag: function () {
     $.ajax({
         url: urlConfig.GetCaseTag,
         async: false,
         method: 'GET',
         cache: false,
         success: function (data) {
             caseTags = data;
         },
         error: function () {
             $('#attachedDocs').parent().find('.comment_loader').hide();
             errorDialog({ title: 'Error', message: 'Error in getting selected file annotation. Please try again!' });
         },
     });
 },
 RenderCaseTags: function (container, Annotations, annotManager, docViewer, viewer) {
     if (!caseTags || caseTags.length === 0) {
         container.innerHTML = '<p style="color: gray;">No tags found</p>';
         return;
     }
     caseTags.forEach(tag => {
         const tagDiv = document.createElement('div');
         tagDiv.className = 'case-tag-badge';
         tagDiv.textContent = tag.value;
         tagDiv.draggable = true;
         tagDiv.dataset.tagId = tag.key;
         const mouseHandler = async (e) => {
             const displayMode = docViewer.getDisplayModeManager().getDisplayMode();
             const pageNumber = docViewer.getCurrentPage();
             const windowCoordinates = Apryse.GetMouseLocation(e, viewer);
             const pageCoordinates = displayMode.windowToPage(windowCoordinates, pageNumber);
             const annot = new Annotations.StampAnnotation({
                 PageNumber: pageNumber,
                 X: pageCoordinates.x,
                 Y: pageCoordinates.y,
                 Width: 30,
                 Height: 30,
                 Author: annotManager.getCurrentUser(),
             });
             annot.setCustomData('caseTagId', tag.contentItemId);
             annot.setCustomData('caseTagName', tag.displayText);
             annot.setCustomData('annotationType', 'Count');
             annot.Subject = 'Count';
             annot.setContents(tag.displayText || '1');
             annot.FillColor = new Annotations.Color(26, 70, 107);
             annot.TextColor = new Annotations.Color(255, 255, 255);
             annot.NoRotate = true;
             await annotManager.addAnnotation(annot);
             annotManager.redrawAnnotation(annot);
             docViewer.getScrollViewElement().removeEventListener('click', mouseHandler);
         };
         docViewer.getScrollViewElement().addEventListener('click', mouseHandler);
         container.appendChild(tagDiv);
     });
 },

I have created new panel for the case tag. Now I want to show the case tag on document and base on the tag I want to show the count.

Now the issue is when I try to add the tag on document it is not showing because I’m using stamp . Is there any way to show the case tag on the document.

I there any best way to show the case tag in panel.

1 Like

I want to modify the existing Count Measurement functionality. Instead of a generic count, I want to count annotations by tag type .

When a user adds a Count annotation, I want to include a new “Tag” section in the Style panel, where the user can select a tag (for example, Parking, Bedroom, Washroom, etc.). Once selected, the Count annotation will be associated with that specific tag type.

1 Like

Hello Rishu,

Thank you for your reply.

We have an existing example here that splits up the measurement count: Count measurement Tool - multiple counters - #3 by ychen

If you have the selected annotation filter for the tag defined in your custom property, you can split up the count that way. This code would need to be refactored for that however.

Regarding the panels, you may have to create your own custom panel and have that component update based on the getAnnotationsList(). More information on creating a custom panel can be found here: Modular UI Panels | Apryse documentation

Alternatively, you can use a custom modal defined here: Apryse WebViewer Namespace: UI

Regards,
Luke

1 Like

Thanks for the reply. Now I want to hide the tag section if user change the panel. I want to show tag section only for Style panel (Count measurement Annotation tool)

  const observer2 = new MutationObserver(() => {
      const selectedAnnotations = annotationManager.getSelectedAnnotations();
      var icon = selectedAnnotations[0]?.Icon;
      var selectedAnnotId = selectedAnnotations[0]?.Id;
      if (icon === 'Check') {
          const annotationStyleButton = iframeDoc.querySelector('[data-element="annotationStyleEditButton"]');
          if (annotationStyleButton) {
              annotationStyleButton.addEventListener('click', () => {
                  setTimeout(() => { Apryse.AddTagSectionToStylePanel(iframeDoc, selectedAnnotId) }, 300);
              });
          }
      }
  });
  observer2.observe(iframeDoc.body, { childList: true, subtree: true });

 AddTagSectionToStylePanel: function (iframeDoc, selectedAnnotId) {
     const stylePanel = iframeDoc.querySelector('[data-element="stylePanel"]');
     if (!stylePanel) return;

     const header = stylePanel.querySelector('[data-element="stylePanelHeaderContainer"] h2');
     if (!header || header.textContent.trim() !== 'Count measurement Annotation') return;

     const stylePicker = stylePanel.querySelector('.StylePicker');
     if (!stylePicker) return;

     if (stylePicker.querySelector('[data-element="tagSelector"]')) return;
     const tagSection = document.createElement('div');
     tagSection.setAttribute('data-element', 'stylePanel-tagContainer');
     tagSection.className = 'PanelSection';
     tagSection.innerHTML = `
       <div class="panel-section-wrapper Tag">
         <div class="menu-items">
           <div data-element="tagSelector" class="Dropdown__wrapper">
           <div id="slider-Tag" class="slider-property">Tag</div>
             <div class="Dropdown" role="combobox" aria-haspopup="listbox" aria-expanded="false" tabindex="0">
               <div class="picked-option">
                 <div class="picked-option-text">Select Tag</div>
                 <div class="Icon arrow" aria-hidden="true">
                   <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12">
                     <path fill="#abb0c4" d="M9,3.5l-3,3-3-3-1,1,4,4,4-4Z"></path>
                   </svg>
                 </div>
               </div>
               <div class="Dropdown__items hide" role="listbox"></div>
             </div>
           </div>
         </div>
       </div>
     `;

     stylePicker.appendChild(tagSection);

     const dropdownItemsContainer = tagSection.querySelector('.Dropdown__items');

     caseTags.forEach(tag => {
         if (tag && tag.key && tag.value) {
             const item = document.createElement('div');
             item.className = 'Dropdown__item';
             item.setAttribute('role', 'option');
             item.dataset.value = tag.key;
             item.textContent = tag.value;

             item.addEventListener('click', () => {
                 const picked = tagSection.querySelector('.picked-option-text');
                 picked.textContent = tag.value;
                 tagSection.querySelector('.Dropdown').setAttribute('aria-expanded', 'false');
                 dropdownItemsContainer.classList.add('hide');
                 const selectedTag = {
                     id: tag.key,
                     name: tag.value
                 };
                 console.log('Selected tag for annotation:', selectedTag);
                 Apryse.UpdateDocumentStateModel(selectedAnnotId, tag.value);
             });

             dropdownItemsContainer.appendChild(item);
         }
     });

     const dropdown = tagSection.querySelector('.Dropdown');
     const pickedOption = dropdown.querySelector('.picked-option');

     pickedOption.addEventListener('click', () => {
         const expanded = dropdown.getAttribute('aria-expanded') === 'true';
         dropdown.setAttribute('aria-expanded', expanded ? 'false' : 'true');
         dropdownItemsContainer.classList.toggle('hide', expanded);
     });
 },
1 Like

Hello Rishu,

Thank you for your reply.

We can add some logic similar to if both of these checks are true, then show the body of the tag section else, hide it:

  1. Check if the count measurement tool is selected: Apryse WebViewer Class: DocumentViewer
  2. Check if style panel is visible: Apryse WebViewer Namespace: UI

Regards,
Luke

1 Like