Add termination to pdf webworker

Allows to cancel the PDF generation by clicking a cancel-button
This commit is contained in:
Sean Engelhardt 2019-08-27 09:58:30 +02:00
parent e3a7cbf935
commit 64c6327720
5 changed files with 70 additions and 12 deletions

View File

@ -66,6 +66,8 @@ export class PdfDocumentService {
*/ */
private imageUrls: string[] = []; private imageUrls: string[] = [];
private pdfWorker: Worker;
/** /**
* Constructor * Constructor
* *
@ -396,9 +398,15 @@ export class PdfDocumentService {
* Shows the progress bar earlier * Shows the progress bar earlier
*/ */
private showProgress(): void { private showProgress(): void {
this.matSnackBar.openFromComponent(ProgressSnackBarComponent, { const progressBarRef = this.matSnackBar.openFromComponent(ProgressSnackBarComponent, {
duration: 0 duration: 0
}); });
// Listen to clicks on the cancel button
progressBarRef.onAction().subscribe(() => {
this.cancelPdfCreation();
});
this.progressService.message = this.translate.instant('Creating PDF file ...'); this.progressService.message = this.translate.instant('Creating PDF file ...');
this.progressService.progressMode = 'determinate'; this.progressService.progressMode = 'determinate';
} }
@ -459,12 +467,12 @@ export class PdfDocumentService {
const isIE = /msie\s|trident\//i.test(window.navigator.userAgent); const isIE = /msie\s|trident\//i.test(window.navigator.userAgent);
if (typeof Worker !== 'undefined' && !isIE) { if (typeof Worker !== 'undefined' && !isIE) {
const worker = new Worker('./pdf-worker.worker', { this.pdfWorker = new Worker('./pdf-worker.worker', {
type: 'module' type: 'module'
}); });
// the result of the worker // the result of the worker
worker.onmessage = ({ data }) => { this.pdfWorker.onmessage = ({ data }) => {
// if the worker returns a numbers, is always the progress // if the worker returns a numbers, is always the progress
if (typeof data === 'number') { if (typeof data === 'number') {
// update progress // update progress
@ -476,10 +484,11 @@ export class PdfDocumentService {
if (typeof data === 'object') { if (typeof data === 'object') {
this.matSnackBar.dismiss(); this.matSnackBar.dismiss();
saveAs(data, filename, { autoBOM: true }); saveAs(data, filename, { autoBOM: true });
this.pdfWorker = null;
} }
}; };
worker.postMessage({ this.pdfWorker.postMessage({
doc: JSON.parse(JSON.stringify(doc)), doc: JSON.parse(JSON.stringify(doc)),
fonts: fonts, fonts: fonts,
vfs: vfs vfs: vfs
@ -492,6 +501,16 @@ export class PdfDocumentService {
} }
} }
/**
* Cancel the pdf generation
*/
private cancelPdfCreation(): void {
if (!!this.pdfWorker) {
this.pdfWorker.terminate();
this.pdfWorker = null;
}
}
/** /**
* Definition of styles for standard papers * Definition of styles for standard papers
* *

View File

@ -1,6 +1,18 @@
<div> <div class="progress-grid-wrapper">
{{ message | translate }} <div classs="message">
</div> {{ message | translate }}
<div> </div>
<mat-progress-bar [mode]="mode" [value]="value"></mat-progress-bar> <div class="bar">
<mat-progress-bar [mode]="mode" [value]="value"></mat-progress-bar>
</div>
<div class="action">
<button
mat-icon-button
color="warn"
matTooltip="{{ 'Cancel' | translate }}"
(click)="snackBarRef.dismissWithAction()"
>
<mat-icon>close</mat-icon>
</button>
</div>
</div> </div>

View File

@ -0,0 +1,20 @@
.progress-grid-wrapper {
display: grid;
width: 100%;
grid-template-areas:
'message action'
'bar action';
grid-template-columns: auto min-content;
}
.message {
grid-area: message;
}
.bar {
grid-area: bar;
}
.action {
grid-area: action;
}

View File

@ -1,16 +1,18 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MatSnackBarRef } from '@angular/material';
import { E2EImportsModule } from 'e2e-imports.module'; import { E2EImportsModule } from 'e2e-imports.module';
import { ProgressSnackBarComponent } from './progress-snack-bar.component'; import { ProgressSnackBarComponent } from './progress-snack-bar.component';
describe('ProgressSnackBarComponent', () => { fdescribe('ProgressSnackBarComponent', () => {
let component: ProgressSnackBarComponent; let component: ProgressSnackBarComponent;
let fixture: ComponentFixture<ProgressSnackBarComponent>; let fixture: ComponentFixture<ProgressSnackBarComponent>;
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [E2EImportsModule] imports: [E2EImportsModule],
providers: [{ provide: MatSnackBarRef, useValue: {} }]
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -6,6 +6,7 @@ import {
OnInit, OnInit,
ViewEncapsulation ViewEncapsulation
} from '@angular/core'; } from '@angular/core';
import { MatSnackBarRef } from '@angular/material';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators'; import { distinctUntilChanged } from 'rxjs/operators';
@ -78,7 +79,11 @@ export class ProgressSnackBarComponent implements OnInit, OnDestroy {
/** /**
* Declare the progressService * Declare the progressService
*/ */
public constructor(private progressService: ProgressService, private cd: ChangeDetectorRef) {} public constructor(
private progressService: ProgressService,
private cd: ChangeDetectorRef,
public snackBarRef: MatSnackBarRef<ProgressSnackBarComponent>
) {}
/** /**
* Get the progress subject and subscribe to the info subject * Get the progress subject and subscribe to the info subject