From d3db348fe41f401415adcddb8603ceb469698b73 Mon Sep 17 00:00:00 2001 From: Timo Bejan Date: Fri, 30 Oct 2020 22:04:25 +0200 Subject: [PATCH] re-draw requests --- .../file-preview-screen.component.ts | 60 ++++------------ .../screens/file/model/annotation.wrapper.ts | 50 ++++++++----- .../file/pdf-viewer/pdf-viewer.component.ts | 3 +- .../file/service/annotation-draw.service.ts | 71 +++++++++++++++++++ apps/red-ui/src/app/utils/annotation-utils.ts | 5 +- 5 files changed, 124 insertions(+), 65 deletions(-) create mode 100644 apps/red-ui/src/app/screens/file/service/annotation-draw.service.ts diff --git a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts index 137b20268..9c3c33a2b 100644 --- a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts @@ -29,6 +29,7 @@ import { ManualAnnotationResponse } from '../model/manual-annotation-response'; import { FileDataModel } from '../model/file-data.model'; import { AnnotationFilter } from '../../../utils/types'; import { FileActionService } from '../service/file-action.service'; +import { AnnotationDrawService } from '../service/annotation-draw.service'; @Component({ selector: 'redaction-file-preview-screen', @@ -60,6 +61,7 @@ export class FilePreviewScreenComponent implements OnInit { private readonly _activatedRoute: ActivatedRoute, private readonly _dialogService: DialogService, private readonly _router: Router, + private readonly _annotationDrawService: AnnotationDrawService, private readonly _fileActionService: FileActionService, private readonly _manualAnnotationService: ManualAnnotationService, private readonly _fileDownloadService: FileDownloadService, @@ -100,9 +102,15 @@ export class FilePreviewScreenComponent implements OnInit { .loadFileData(this.appStateService.activeProjectId, this.fileId) .subscribe((fileDataModel) => { this.fileData = fileDataModel; - this.annotations = fileDataModel.redactionLog.redactionLogEntry.map( - (rde) => new AnnotationWrapper(rde, null) + const manualRedactionAnnotations = fileDataModel.manualRedactions.entriesToAdd.map( + (mr) => AnnotationWrapper.fromManualRedaction(mr) ); + const redactionLogAnnotations = fileDataModel.redactionLog.redactionLogEntry.map( + (rde) => AnnotationWrapper.fromRedactionLog(rde) + ); + + this.annotations.push(...manualRedactionAnnotations); + this.annotations.push(...redactionLogAnnotations); this._changeDetectorRef.detectChanges(); }); } @@ -177,22 +185,7 @@ export class FilePreviewScreenComponent implements OnInit { this._dialogRef = this._dialogService.openManualRedactionDialog( $event, (response: ManualAnnotationResponse) => { - const manualRedactionEntry: ManualRedactionEntry = - response.manualRedactionEntryWrapper.manualRedactionEntry; - - const annotManager = this.activeViewer.annotManager; - const originalQuads = $event.quads; - for (const key of Object.keys(originalQuads)) { - const pageNumber = parseInt(key, 10); - const highlight = new this.activeViewer.Annotations.TextHighlightAnnotation(); - highlight.PageNumber = pageNumber; - highlight.StrokeColor = this._getColor(manualRedactionEntry); - highlight.setContents(manualRedactionEntry.reason); - highlight.Quads = originalQuads[key]; - highlight.Id = this._computeId(response); - annotManager.addAnnotation(highlight, true); - annotManager.redrawAnnotation(highlight); - } + // TODO REDRAW ANNOTATIONS FROM MANUAL REQUESTS } ); }); @@ -403,33 +396,10 @@ export class FilePreviewScreenComponent implements OnInit { viewerReady($event: WebViewerInstance) { this.instance = $event; this.viewReady = true; - } - - private _computeId(response: ManualAnnotationResponse) { - // if owner or not set the request prefix in the id - const prefix = this.appStateService.isActiveProjectOwner ? '' : 'request:add:'; - - if (prefix.length > 0) { - return prefix + response.dictionary + ':' + response.annotationId; - } else { - const dictionaryType: 'hint' | 'redaction' = - response.manualRedactionEntryWrapper.type === 'REDACTION' - ? 'redaction' - : this.appStateService.getDictionaryTypeValue(response.dictionary).hint - ? 'hint' - : 'redaction'; - return dictionaryType + ':' + response.dictionary + ':' + response.annotationId; - } - } - - private _getColor(manualRedactionEntry: ManualRedactionEntry) { - // if you're the owner, use the request color, otherwise use the actual dict color - const color = this.appStateService.isActiveProjectOwner - ? this.appStateService.getDictionaryColor(manualRedactionEntry.type) - : this.appStateService.getDictionaryColor('request'); - - const rgbColor = hexToRgb(color); - return new this.activeViewer.Annotations.Color(rgbColor.r, rgbColor.g, rgbColor.b); + this._annotationDrawService.drawAnnotations( + this.instance, + this.fileData.manualRedactions.entriesToAdd + ); } filtersChanged(filters: AnnotationFilter[]) { diff --git a/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts b/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts index 40f0c1bed..d696523b8 100644 --- a/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts +++ b/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts @@ -1,9 +1,4 @@ -import { - ManualRedactionEntry, - ManualRedactions, - Point, - RedactionLogEntry -} from '@redaction/red-ui-http'; +import { ManualRedactionEntry, Point, RedactionLogEntry } from '@redaction/red-ui-http'; export class AnnotationWrapper { superType: 'request' | 'redaction' | 'hint' | 'ignore'; @@ -17,22 +12,39 @@ export class AnnotationWrapper { content: string; pageNumber; - constructor(public redactionLogEntry: RedactionLogEntry, manualRedactions?: ManualRedactions) { - this.superType = redactionLogEntry.redacted + static fromRedactionLog(redactionLogEntry: RedactionLogEntry) { + const annotationWrapper = new AnnotationWrapper(); + annotationWrapper.superType = redactionLogEntry.redacted ? 'redaction' : redactionLogEntry.hint ? 'hint' : 'ignore'; - this.dictionary = redactionLogEntry.type; - this.firstTopLeftPoint = redactionLogEntry.positions[0]?.topLeft; - this.pageNumber = redactionLogEntry.positions[0]?.page; - this.id = redactionLogEntry.id; - this.content = - this.superType === 'redaction' || this.superType === 'ignore' - ? this.createAnnotationContent(redactionLogEntry) + annotationWrapper.dictionary = redactionLogEntry.type; + annotationWrapper.firstTopLeftPoint = redactionLogEntry.positions[0]?.topLeft; + annotationWrapper.pageNumber = redactionLogEntry.positions[0]?.page; + annotationWrapper.id = redactionLogEntry.id; + annotationWrapper.content = + annotationWrapper.superType === 'redaction' || annotationWrapper.superType === 'ignore' + ? AnnotationWrapper.createAnnotationContentForRedactionLogEntry(redactionLogEntry) : null; + return annotationWrapper; } + static fromManualRedaction(manualRedactionEntry: ManualRedactionEntry) { + const annotationWrapper = new AnnotationWrapper(); + annotationWrapper.superType = 'request'; + annotationWrapper.dictionary = manualRedactionEntry.type; + annotationWrapper.firstTopLeftPoint = manualRedactionEntry.positions[0]?.topLeft; + annotationWrapper.pageNumber = manualRedactionEntry.positions[0]?.page; + annotationWrapper.id = manualRedactionEntry.id; + annotationWrapper.content = manualRedactionEntry.addToDictionary + ? null + : AnnotationWrapper.createAnnotationContentForManualRedaction(manualRedactionEntry); + return annotationWrapper; + } + + constructor() {} + get manualRedactionOwner() { return this.manualRedactionEntry?.user; } @@ -45,7 +57,13 @@ export class AnnotationWrapper { return this.firstTopLeftPoint.y; } - private createAnnotationContent(entry: RedactionLogEntry) { + private static createAnnotationContentForManualRedaction(entry: ManualRedactionEntry) { + return entry.reason; + // + '\n\nLegal basis:' + + // entry.legalBasis + } + + private static createAnnotationContentForRedactionLogEntry(entry: RedactionLogEntry) { // return "\nRule " + entry.matchedRule + " matched\n\n" + entry.reason + "\n\nLegal basis:" + entry.legalBasis + "\n\nIn section: \"" + entry.section + "\""; return ( entry.reason + diff --git a/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts b/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts index b36e4999f..7d39b9533 100644 --- a/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts +++ b/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts @@ -129,8 +129,6 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges { instance.loadDocument(pdfBlob, { filename: this.fileStatus ? this.fileStatus.filename : 'document.pdf' }); - - this.viewerReady.emit(instance); }); } @@ -284,6 +282,7 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges { } private _restoreViewerState() { + this.viewerReady.emit(this.instance); this._restoreState(this._viewerState, this.instance); } diff --git a/apps/red-ui/src/app/screens/file/service/annotation-draw.service.ts b/apps/red-ui/src/app/screens/file/service/annotation-draw.service.ts new file mode 100644 index 000000000..024450d09 --- /dev/null +++ b/apps/red-ui/src/app/screens/file/service/annotation-draw.service.ts @@ -0,0 +1,71 @@ +import { Injectable } from '@angular/core'; +import { WebViewerInstance } from '@pdftron/webviewer'; +import { ManualRedactionEntry, Rectangle } from '@redaction/red-ui-http'; +import { hexToRgb } from '../../../utils/functions'; +import { AppStateService } from '../../../state/app-state.service'; + +@Injectable({ + providedIn: 'root' +}) +export class AnnotationDrawService { + constructor(private readonly _appStateService: AppStateService) {} + + public drawAnnotations(activeViewer: WebViewerInstance, mres: ManualRedactionEntry[]) { + mres.forEach((mre) => { + this.drawAnnotation(activeViewer, mre); + }); + } + + public drawAnnotation(activeViewer: WebViewerInstance, mre: ManualRedactionEntry) { + const pageNumber = mre.positions[0].page; + const highlight = new activeViewer.Annotations.TextHighlightAnnotation(); + highlight.PageNumber = pageNumber; + highlight.StrokeColor = this._getColor(activeViewer, mre); + highlight.setContents(mre.reason); + highlight.Quads = this._rectanglesToQuads(mre.positions, activeViewer, pageNumber); + highlight.Id = mre.id; + + const annotationManager = activeViewer.annotManager; + annotationManager.addAnnotation(highlight, true); + annotationManager.redrawAnnotation(highlight); + } + + private _getColor(activeViewer: WebViewerInstance, manualRedactionEntry: ManualRedactionEntry) { + // if you're the owner, use the request color, otherwise use the actual dict color + const color = this._appStateService.isActiveProjectOwner + ? this._appStateService.getDictionaryColor(manualRedactionEntry.type) + : this._appStateService.getDictionaryColor('request'); + + const rgbColor = hexToRgb(color); + return new activeViewer.Annotations.Color(rgbColor.r, rgbColor.g, rgbColor.b); + } + + private _rectanglesToQuads( + positions: Rectangle[], + activeViewer: WebViewerInstance, + pageNumber: number + ): any[] { + const pageHeight = activeViewer.docViewer.getPageHeight(pageNumber); + return positions.map((p) => this._rectangleToQuad(p, activeViewer, pageHeight)); + } + + private _rectangleToQuad( + rectangle: Rectangle, + activeViewer: WebViewerInstance, + pageHeight: number + ): any { + const x1 = rectangle.topLeft.x; + const y1 = pageHeight - (rectangle.topLeft.y + rectangle.height); + + const x2 = rectangle.topLeft.x + rectangle.width; + const y2 = pageHeight - (rectangle.topLeft.y + rectangle.height); + + const x3 = rectangle.topLeft.x + rectangle.width; + const y3 = pageHeight - rectangle.topLeft.y; + + const x4 = rectangle.topLeft.x; + const y4 = pageHeight - rectangle.topLeft.y; + + return new activeViewer.Annotations.Quad(x1, y1, x2, y2, x3, y3, x4, y4); + } +} diff --git a/apps/red-ui/src/app/utils/annotation-utils.ts b/apps/red-ui/src/app/utils/annotation-utils.ts index e2fe24a4d..49b7ea6a3 100644 --- a/apps/red-ui/src/app/utils/annotation-utils.ts +++ b/apps/red-ui/src/app/utils/annotation-utils.ts @@ -1,5 +1,8 @@ import { AnnotationWrapper } from '../screens/file/model/annotation.wrapper'; import { AnnotationFilter } from './types'; +import { ManualRedactionEntry } from '@redaction/red-ui-http'; +import { WebViewerInstance } from '@pdftron/webviewer'; +import { hexToRgb } from './functions'; export class AnnotationUtils { public static sortAnnotations(annotations: AnnotationWrapper[]): AnnotationWrapper[] { @@ -70,8 +73,6 @@ export class AnnotationUtils { obj[page].annotations = this.sortAnnotations(obj[page].annotations); }); - console.log(obj); - return obj; } }