Semantic Compare show annotations for the second document

Looks like in your code, you’re also using the document1AnnotationManager for the 2nd document. Could it be the issue?

this.saveAnnotations(document1AnnotationManager, annotations, action);
1 Like

Good catch. I noticed that version 10.2.3 has been released, so I switched to that. I have fixed my example code based on what you found, but I’m still seeing the main problem that I am having in my production code. When adding comments to the document on the right, the event for document viewer 1 is firing, and the XFDF data is missing. Everything else appears to be correct (the initial add of the annotation, replies and deleting).

import { AfterViewInit, Component, ElementRef, EventEmitter, Output, ViewChild } from '@angular/core';
import WebViewer, { Core, WebViewerInstance } from "@pdftron/webviewer";
import { Subject } from "rxjs";

@Component({
  selector: 'app-root',
  styleUrls: ['app.component.css'],
  templateUrl: 'app.component.html'
})
export class AppComponent implements AfterViewInit {
  wvInstance?: WebViewerInstance;

  @ViewChild('viewer') viewer!: ElementRef;

  @Output() coreControlsEvent: EventEmitter<string> = new EventEmitter();

  private documentLoaded$: Subject<void>;

  constructor() {
    this.documentLoaded$ = new Subject<void>();
  }

  ngAfterViewInit(): void {

    WebViewer({
      path: '../lib',
      fullAPI: true
    }, this.viewer.nativeElement).then(instance => {
      this.wvInstance = instance;

      const { documentViewer, Annotations, annotationManager } = instance.Core;

      instance.UI.openElements(['notesPanel']);

      documentViewer.addEventListener('annotationsLoaded', () => {
        console.log('annotations loaded');
      });

      const { UI, Core } = instance;
      const { Color } = Annotations;

      UI.addEventListener(UI.Events.MULTI_VIEWER_READY, () => {
        const [documentViewer1, documentViewer2] = Core.getDocumentViewers();
        const startCompare = async () => {
          const shouldCompare = documentViewer1.getDocument() && documentViewer2.getDocument();
          if (shouldCompare) { // Check if both documents loaded before comparing
            const beforeColor = new Color(21, 205, 131, 0.4);
            const afterColor = new Color(255, 73, 73, 0.4);
            const options = { beforeColor, afterColor };
            await documentViewer1.startSemanticDiff(documentViewer2, options);
          }
        }
        documentViewer1.addEventListener('documentLoaded', startCompare);
        documentViewer2.addEventListener('documentLoaded', startCompare);
        documentViewer1.loadDocument('http://localhost:4200/files/fluffy.pdf');
        documentViewer2.loadDocument('http://localhost:4200/files/scooby.pdf');

        let document1AnnotationManager = documentViewer1.getAnnotationManager();
        document1AnnotationManager.addEventListener(
          'annotationChanged',
          (annotations: any, action: any, { imported }: any) => {
            console.log('AnnotationManager 1 ------------ annotationChanged');
            this.saveAnnotations(document1AnnotationManager, annotations, action);
          }
        );


        let document2AnnotationManager = documentViewer2.getAnnotationManager();
        document2AnnotationManager.addEventListener(
          'annotationChanged',
          (annotations: any, action: any, { imported }: any) => {
            console.log('AnnotationManager 2 ----------- annotationChanged');
            this.saveAnnotations(document2AnnotationManager, annotations, action);
          }
        );
      });
      UI.enableFeatures([UI.Feature.MultiViewerMode]);
    })
  }

  private saveAnnotations(annotationManager: Core.AnnotationManager,
    annotations: any,
    action: string) {

    annotations.forEach((annotation: Core.Annotations.Annotation) => {
      annotationManager.exportAnnotationCommand().then((xfdfData: any) => {
        console.log(`Saving... ${action}`);
        console.log(`XFDF data = ${xfdfData}`);
      });
    });
  }

}

Annotations-not-saving-comments-document-2

1 Like

Hi,

I was able to reproduce the issue. I have added the bug to our back log and it will be reviewed later.

Thanks.

2 Likes

Thank you for your good solution.
i need help to dynamic file name.

I have following code

UI.addEventListener(UI.Events.MULTI_VIEWER_READY, () => {
  const [documentViewer1, documentViewer2] = Core.getDocumentViewers();
  const startCompare = async () => {
    const shouldCompare = documentViewer1.getDocument() && documentViewer2.getDocument();
    if (shouldCompare) { // Check if both documents loaded before comparing
      const beforeColor = new Color(21, 205, 131, 0.4);
      const afterColor = new Color(255, 73, 73, 0.4);
      const options = { beforeColor, afterColor };
      const { doc1Annotations, doc2Annotations, diffCount } = await documentViewer1.startSemanticDiff(documentViewer2, options);
    }
  }

  const docLoaded1 = async () => {
  console.log(documentViewer1)
  console.log(documentViewer2)
  documentViewer2.loadDocument( url_par_d2, {loadAsPDF: true, extension: 'pdf', filename: 'Dokument 2' });
  }

  documentViewer1.addEventListener('documentLoaded', docLoaded1);
  documentViewer2.addEventListener('documentLoaded', startCompare);

documentViewer1.loadDocument( url_par_d1, {loadAsPDF: true, extension: 'pdf', filename: 'Dokument 1' });

});

In this code I write statically the name of the documents (“Document 1” and “Document 2”) but I want to show the name of the document dynamically, can you help me?

1 Like

Hi William,

The fix should be available in the latest nightly build of WebViewer v10.3, please try it out.

2 Likes

Can you use the variables url_par_d1 and url_par_d2? For my real codebase, the urls to load the files do not contain a user friendly name. Instead, our API to get the information for the files to be compared also contains a nicer name. I then use this function to create the object passed into the documentViewer.loadDocument() function:

private getFilenameObjectByFilenameAndExtension(filename: string | undefined, extension: string | undefined): any {
    if (!filename || !extension) {
      return {};
    }

    return { filename: `${filename}.${extension}` };
  }
1 Like

Good day. I thought of continuing this thread instead of creating a new one since the approach to hide the semantic compare differences as annotations in the comments panel was briefly discussed here.

this.wvInstance.UI.setCustomNoteFilter(function (annotation) {
      return annotation.getCustomData('TextDiffType') === '' && annotation.getCustomData('TextDiffID') === '';
 });

Anyway, so we are using the code highlighted above to hide said differences annotations. However, it turns out the Filter dialog is still using those text differences as options for the User filter. See screenshot below as example:

Additionally, the Color filter is adding the Green and Red colors from the difference annotations as options as well:
image

Are there any recommendations to be able to cover this scenario for the Filter dialog as well?

EDIT: I would like to think this may be a bug because the expectation was the Filter Dialog should display options according to what is on the Comments list panel. Setting the .setCustomNoteFilter() should have been all that’s needed as this directly affects what is displayed in the list

Thank you!

Hello Rafael,

We recommend creating a new thread as this makes it easier to track new issues.

Best Regards,
Darian

Hi.

Sorry, I forgot to get back to this. I raised this specific issue a few days ago as https://support.apryse.com/support/tickets/91835 and it was already acknowledged as a bug

Thank you!

Thank you for the clarification. In that case, please direct any questions related to this issue to that ticket.