Progress Indicator (PDF) (Angular)

The sample demonstrates how to export FlexGrid content to PDF files asynchronously, display a progress indicator and cancel the export.

The progress argument of the PdfWebWorkerClient's exportGrid method is used to track the export progress, the web worker's terminate method is used to cancel the export.

Learn about FlexGrid | FlexGrid API Reference

This example uses Angular.

app.component.ts
index.html
app.component.html
app.data.ts
styles.css
workers/export-grid.ts
Copy to CodeMine
import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import './styles.css'; // import '@mescius/wijmo.chart.render'; import * as grid from '@mescius/wijmo.grid'; import * as gridPdf from '@mescius/wijmo.grid.pdf'; import * as gauge from '@mescius/wijmo.gauge'; // import '@angular/compiler'; import { Component, Inject, enableProdMode, OnDestroy, ViewChild, ɵresolveComponentResources } from '@angular/core'; import { BrowserModule, bootstrapApplication } from '@angular/platform-browser'; import { DataService } from './app.data'; import { WjGridModule } from '@mescius/wijmo.angular2.grid'; import { WjGaugeModule } from '@mescius/wijmo.angular2.gauge'; // @Component({ standalone: true, providers: [DataService], imports: [WjGridModule, WjGaugeModule, BrowserModule], selector: 'app-component', templateUrl: 'src/app.component.html', }) export class AppComponent implements OnDestroy { data: any[]; @ViewChild('flexGrid', { static: true }) flexGrid: grid.FlexGrid; @ViewChild('progressBar', { static: true }) progressBar: gauge.LinearGauge; private _worker: Worker; // constructor(@Inject(DataService) private dataService: DataService) { this.data = dataService.getData(3000); } // export() { this.cancel(); // this._worker = this.loadWorker('./export-grid', () => { gridPdf.PdfWebWorkerClient.exportGrid( this._worker, this.flexGrid, 'FlexGrid.pdf', { scaleMode: gridPdf.ScaleMode.PageWidth, styles: { cellStyle: { backgroundColor: '#ffffff', borderColor: '#c6c6c6', }, altCellStyle: { backgroundColor: '#f9f9f9', }, groupCellStyle: { backgroundColor: '#dddddd', }, headerCellStyle: { backgroundColor: '#eaeaea', }, }, }, null, (progress) => (this.progressBar.value = progress * 100), ); }); } // cancel() { if (this._worker) { this._worker.terminate(); } this.progressBar.value = 0; } // // Creates a web worker that executes a module from the specified URL. private loadWorker(url: string, ready: () => void) { let worker = new Worker('src/workers/worker-loader.js'); // worker.addEventListener('message', (e) => { if (e.data === '#ready#') { ready(); } }); // worker.postMessage({ url: url }); // return worker; } // ngOnDestroy() { if (this._worker) { this._worker.terminate(); } } } // // enableProdMode(); // Resolve resources (templateUrl, styleUrls etc), After resolution all URLs have been converted into `template` strings. ɵresolveComponentResources(fetch).then(() => { // Bootstrap application bootstrapApplication(AppComponent).catch((err) => console.error(err)); });
import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import './styles.css'; // import '@mescius/wijmo.chart.render'; import * as grid from '@mescius/wijmo.grid'; import * as gridPdf from '@mescius/wijmo.grid.pdf'; import * as gauge from '@mescius/wijmo.gauge'; // import '@angular/compiler'; import { Component, Inject, enableProdMode, OnDestroy, ViewChild, ɵresolveComponentResources } from '@angular/core'; import { BrowserModule, bootstrapApplication } from '@angular/platform-browser'; import { DataService } from './app.data'; import { WjGridModule } from '@mescius/wijmo.angular2.grid'; import { WjGaugeModule } from '@mescius/wijmo.angular2.gauge'; // @Component({ standalone: true, providers: [DataService], imports: [WjGridModule, WjGaugeModule, BrowserModule], selector: 'app-component', templateUrl: 'src/app.component.html', }) export class AppComponent implements OnDestroy { data: any[]; @ViewChild('flexGrid', { static: true }) flexGrid: grid.FlexGrid; @ViewChild('progressBar', { static: true }) progressBar: gauge.LinearGauge; private _worker: Worker; // constructor(@Inject(DataService) private dataService: DataService) { this.data = dataService.getData(3000); } // export() { this.cancel(); // this._worker = this.loadWorker('./export-grid', () => { gridPdf.PdfWebWorkerClient.exportGrid( this._worker, this.flexGrid, 'FlexGrid.pdf', { scaleMode: gridPdf.ScaleMode.PageWidth, styles: { cellStyle: { backgroundColor: '#ffffff', borderColor: '#c6c6c6', }, altCellStyle: { backgroundColor: '#f9f9f9', }, groupCellStyle: { backgroundColor: '#dddddd', }, headerCellStyle: { backgroundColor: '#eaeaea', }, }, }, null, (progress) => (this.progressBar.value = progress * 100), ); }); } // cancel() { if (this._worker) { this._worker.terminate(); } this.progressBar.value = 0; } // // Creates a web worker that executes a module from the specified URL. private loadWorker(url: string, ready: () => void) { let worker = new Worker('src/workers/worker-loader.js'); // worker.addEventListener('message', (e) => { if (e.data === '#ready#') { ready(); } }); // worker.postMessage({ url: url }); // return worker; } // ngOnDestroy() { if (this._worker) { this._worker.terminate(); } } } // // enableProdMode(); // Resolve resources (templateUrl, styleUrls etc), After resolution all URLs have been converted into `template` strings. ɵresolveComponentResources(fetch).then(() => { // Bootstrap application bootstrapApplication(AppComponent).catch((err) => console.error(err)); });
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Progress Indicator</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Polyfills --> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/fesm2015/zone.min.js"></script> <!-- SystemJS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.21.5/system.src.js" integrity="sha512-skZbMyvYdNoZfLmiGn5ii6KmklM82rYX2uWctBhzaXPxJgiv4XBwJnFGr5k8s+6tE1pcR1nuTKghozJHyzMcoA==" crossorigin="anonymous"></script> <script src="systemjs.config.js"></script> <script> // workaround to load 'rxjs/operators' from the rxjs bundle System.import('rxjs').then(function (m) { System.set(SystemJS.resolveSync('rxjs/operators'), System.newModule(m.operators)); System.import('./src/app.component'); }); </script> </head> <body> <app-component></app-component> </body> </html>
<div class="container-fluid"> <wj-flex-grid class="grid" #flexGrid [autoGenerateColumns]="false" [itemsSource]="data"> <wj-flex-grid-column header="ID" binding="id"></wj-flex-grid-column> <wj-flex-grid-column header="Country" binding="country"></wj-flex-grid-column> <wj-flex-grid-column header="Product" binding="product"></wj-flex-grid-column> <wj-flex-grid-column header="Amount" binding="amount" format="c"></wj-flex-grid-column> <wj-flex-grid-column header="Pending" binding="amount2" format="c2"></wj-flex-grid-column> <wj-flex-grid-column header="Discount" binding="discount" format="p1"></wj-flex-grid-column> <wj-flex-grid-column header="Active" binding="active"></wj-flex-grid-column> </wj-flex-grid> <div class="row "> <div class="col-md-6 col-xs-12 well well-sm"> <wj-linear-gauge #progressBar [isReadOnly]="true" [min]="0" [max]="100" [value]="0" [showText]="'Value'"> </wj-linear-gauge> <button class="btn btn-default" (click)="export()">Export</button> <button class="btn btn-default" (click)="cancel()">Cancel</button> </div> </div> </div>
import { Injectable } from '@angular/core'; // @Injectable() export class DataService { getData(count: number) { let countries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece'], products = ['Widget', 'Gadget', 'Doohickey'], data = []; // for (let i = 0; i < count; i++) { let countryId = Math.floor(Math.random() * countries.length), productId = Math.floor(Math.random() * products.length); // let item = { id: i, country: countries[countryId], product: products[productId], amount: Math.random() * 10000, amount2: Math.random() * 10000, discount: Math.random() / 4, active: i % 4 == 0 }; // data.push(item); } // return data; } }
.wj-flexgrid { height: 400px; margin: 6px 0; } .wj-gauge { margin: 20px auto; }
import { PdfWebWorker } from '@mescius/wijmo.grid.pdf'; // PdfWebWorker.initExportGrid();
(function (global) { SystemJS.config({ transpiler: './plugin-typescript.js', typescriptOptions: { "target": "ES2022", "module": "system", "emitDecoratorMetadata": true, "experimentalDecorators": true, }, baseURL: 'node_modules/', meta: { 'typescript': { "exports": "ts" }, '*.css': { loader: 'systemjs-plugin-css' }, '*.mjs': { format: 'esm' }, }, paths: { // paths serve as alias 'npm:': '' }, packageConfigPaths: [ '/node_modules/*/package.json', "/node_modules/@angular/*/package.json", "/node_modules/@mescius/*/package.json" ], map: { 'core-js': 'https://cdn.jsdelivr.net/npm/core-js@2.6.12/client/shim.min.js', 'typescript': 'https://cdnjs.cloudflare.com/ajax/libs/typescript/5.2.2/typescript.min.js', "rxjs": "https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.8.1/rxjs.umd.min.js", 'systemjs-plugin-css': 'https://cdn.jsdelivr.net/npm/systemjs-plugin-css@0.1.37/css.js', '@mescius/wijmo': 'npm:@mescius/wijmo/index.js', '@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js', '@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures', '@mescius/wijmo.chart': 'npm:@mescius/wijmo.chart/index.js', '@mescius/wijmo.chart.analytics': 'npm:@mescius/wijmo.chart.analytics/index.js', '@mescius/wijmo.chart.animation': 'npm:@mescius/wijmo.chart.animation/index.js', '@mescius/wijmo.chart.annotation': 'npm:@mescius/wijmo.chart.annotation/index.js', '@mescius/wijmo.chart.finance': 'npm:@mescius/wijmo.chart.finance/index.js', '@mescius/wijmo.chart.finance.analytics': 'npm:@mescius/wijmo.chart.finance.analytics/index.js', '@mescius/wijmo.chart.hierarchical': 'npm:@mescius/wijmo.chart.hierarchical/index.js', '@mescius/wijmo.chart.interaction': 'npm:@mescius/wijmo.chart.interaction/index.js', '@mescius/wijmo.chart.radar': 'npm:@mescius/wijmo.chart.radar/index.js', '@mescius/wijmo.chart.render': 'npm:@mescius/wijmo.chart.render/index.js', '@mescius/wijmo.chart.webgl': 'npm:@mescius/wijmo.chart.webgl/index.js', '@mescius/wijmo.chart.map': 'npm:@mescius/wijmo.chart.map/index.js', '@mescius/wijmo.gauge': 'npm:@mescius/wijmo.gauge/index.js', '@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js', '@mescius/wijmo.grid.detail': 'npm:@mescius/wijmo.grid.detail/index.js', '@mescius/wijmo.grid.filter': 'npm:@mescius/wijmo.grid.filter/index.js', '@mescius/wijmo.grid.search': 'npm:@mescius/wijmo.grid.search/index.js', '@mescius/wijmo.grid.style': 'npm:@mescius/wijmo.grid.style/index.js', '@mescius/wijmo.grid.grouppanel': 'npm:@mescius/wijmo.grid.grouppanel/index.js', '@mescius/wijmo.grid.multirow': 'npm:@mescius/wijmo.grid.multirow/index.js', '@mescius/wijmo.grid.transposed': 'npm:@mescius/wijmo.grid.transposed/index.js', '@mescius/wijmo.grid.transposedmultirow': 'npm:@mescius/wijmo.grid.transposedmultirow/index.js', '@mescius/wijmo.grid.pdf': 'npm:@mescius/wijmo.grid.pdf/index.js', '@mescius/wijmo.grid.sheet': 'npm:@mescius/wijmo.grid.sheet/index.js', '@mescius/wijmo.grid.xlsx': 'npm:@mescius/wijmo.grid.xlsx/index.js', '@mescius/wijmo.grid.selector': 'npm:@mescius/wijmo.grid.selector/index.js', '@mescius/wijmo.grid.cellmaker': 'npm:@mescius/wijmo.grid.cellmaker/index.js', '@mescius/wijmo.nav': 'npm:@mescius/wijmo.nav/index.js', '@mescius/wijmo.odata': 'npm:@mescius/wijmo.odata/index.js', '@mescius/wijmo.olap': 'npm:@mescius/wijmo.olap/index.js', '@mescius/wijmo.rest': 'npm:@mescius/wijmo.rest/index.js', '@mescius/wijmo.pdf': 'npm:@mescius/wijmo.pdf/index.js', '@mescius/wijmo.pdf.security': 'npm:@mescius/wijmo.pdf.security/index.js', '@mescius/wijmo.viewer': 'npm:@mescius/wijmo.viewer/index.js', '@mescius/wijmo.xlsx': 'npm:@mescius/wijmo.xlsx/index.js', '@mescius/wijmo.undo': 'npm:@mescius/wijmo.undo/index.js', '@mescius/wijmo.interop.grid': 'npm:@mescius/wijmo.interop.grid/index.js', '@mescius/wijmo.touch': 'npm:@mescius/wijmo.touch/index.js', '@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/index.js', '@mescius/wijmo.barcode': 'npm:@mescius/wijmo.barcode/index.js', '@mescius/wijmo.barcode.common': 'npm:@mescius/wijmo.barcode.common/index.js', '@mescius/wijmo.barcode.composite': 'npm:@mescius/wijmo.barcode.composite/index.js', '@mescius/wijmo.barcode.specialized': 'npm:@mescius/wijmo.barcode.specialized/index.js', "@mescius/wijmo.angular2.chart.analytics": "npm:@mescius/wijmo.angular2.chart.analytics/index.js", "@mescius/wijmo.angular2.chart.animation": "npm:@mescius/wijmo.angular2.chart.animation/index.js", "@mescius/wijmo.angular2.chart.annotation": "npm:@mescius/wijmo.angular2.chart.annotation/index.js", "@mescius/wijmo.angular2.chart.finance.analytics": "npm:@mescius/wijmo.angular2.chart.finance.analytics/index.js", "@mescius/wijmo.angular2.chart.finance": "npm:@mescius/wijmo.angular2.chart.finance/index.js", "@mescius/wijmo.angular2.chart.hierarchical": "npm:@mescius/wijmo.angular2.chart.hierarchical/index.js", "@mescius/wijmo.angular2.chart.interaction": "npm:@mescius/wijmo.angular2.chart.interaction/index.js", "@mescius/wijmo.angular2.chart.radar": "npm:@mescius/wijmo.angular2.chart.radar/index.js", '@mescius/wijmo.angular2.chart.map': 'npm:@mescius/wijmo.angular2.chart.map/index.js', "@mescius/wijmo.angular2.chart": "npm:@mescius/wijmo.angular2.chart/index.js", "@mescius/wijmo.angular2.core": "npm:@mescius/wijmo.angular2.core/index.js", "@mescius/wijmo.angular2.gauge": "npm:@mescius/wijmo.angular2.gauge/index.js", "@mescius/wijmo.angular2.grid.detail": "npm:@mescius/wijmo.angular2.grid.detail/index.js", "@mescius/wijmo.angular2.grid.filter": "npm:@mescius/wijmo.angular2.grid.filter/index.js", "@mescius/wijmo.angular2.grid.grouppanel": "npm:@mescius/wijmo.angular2.grid.grouppanel/index.js", "@mescius/wijmo.angular2.grid.search": "npm:@mescius/wijmo.angular2.grid.search/index.js", "@mescius/wijmo.angular2.grid.multirow": "npm:@mescius/wijmo.angular2.grid.multirow/index.js", "@mescius/wijmo.angular2.grid.sheet": "npm:@mescius/wijmo.angular2.grid.sheet/index.js", '@mescius/wijmo.angular2.grid.transposed': 'npm:@mescius/wijmo.angular2.grid.transposed/index.js', '@mescius/wijmo.angular2.grid.transposedmultirow': 'npm:@mescius/wijmo.angular2.grid.transposedmultirow/index.js', "@mescius/wijmo.angular2.grid": "npm:@mescius/wijmo.angular2.grid/index.js", "@mescius/wijmo.angular2.input": "npm:@mescius/wijmo.angular2.input/index.js", "@mescius/wijmo.angular2.olap": "npm:@mescius/wijmo.angular2.olap/index.js", "@mescius/wijmo.angular2.viewer": "npm:@mescius/wijmo.angular2.viewer/index.js", "@mescius/wijmo.angular2.nav": "npm:@mescius/wijmo.angular2.nav/index.js", "@mescius/wijmo.angular2.directivebase": "npm:@mescius/wijmo.angular2.directivebase/index.js", '@mescius/wijmo.angular2.barcode.common': 'npm:@mescius/wijmo.angular2.barcode.common/index.js', '@mescius/wijmo.angular2.barcode.composite': 'npm:@mescius/wijmo.angular2.barcode.composite/index.js', '@mescius/wijmo.angular2.barcode.specialized': 'npm:@mescius/wijmo.angular2.barcode.specialized/index.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'jszip': 'https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js', '@angular/core': 'npm:@angular/core/fesm2022/core.mjs', '@angular/core/primitives/signals': 'npm:@angular/core/fesm2022/primitives/signals.mjs', '@angular/core/primitives/event-dispatch': 'npm:@angular/core/fesm2022/primitives/event-dispatch.mjs', '@angular/common': 'npm:@angular/common/fesm2022/common.mjs', '@angular/common/http': 'npm:@angular/common/fesm2022/http.mjs', '@angular/compiler': 'npm:@angular/compiler/fesm2022/compiler.mjs', '@angular/platform-browser': 'npm:@angular/platform-browser/fesm2022/platform-browser.mjs', '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/fesm2022/platform-browser-dynamic.mjs', '@angular/http': 'npm:@angular/http/fesm2022/http.mjs', '@angular/router': 'npm:@angular/router/fesm2022/router.mjs', '@angular/forms': 'npm:@angular/forms/fesm2022/forms.mjs', }, // packages tells the System loader how to load when no filename and/or no extension packages: { "./src": { defaultExtension: 'ts' }, "node_modules": { defaultExtension: 'js' }, wijmo: { defaultExtension: 'js', } } }); })(this);