Skip to main content
The Angular PWA Demo includes comprehensive file generation capabilities for exporting data and visualizations to various formats.

Overview

PDF generation

Export canvas visualizations to PDF

CSV files

Generate and download CSV data files

XLS files

Create Excel spreadsheets

Charts

Interactive data visualizations

PDF generation

Export canvas-based visualizations (graphs, game boards, charts) to PDF files using html2canvas and jsPDF.

Implementation

// src/app/_services/__FileGeneration/pdf.service.ts

import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';

public _GetPDF(
  pageTitle: string, 
  c_canvas: any, 
  divCanvas_Pdf: any, 
  fileName: string
): Observable<string> {
  return new Observable<string>((observer) => 
    this.getPdf(pageTitle, c_canvas, divCanvas_Pdf, fileName, observer)
  );
}

getPdf(
  pageTitle: string, 
  c_canvas: any, 
  divCanvas_Pdf: any, 
  fileName: string, 
  observer: any
): void {
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
  const finalFileName = `${fileName}_${timestamp}.pdf`;
  
  const areaToPrint = c_canvas.nativeElement;
  const borderToPrint = divCanvas_Pdf.nativeElement;
  
  (async () => {
    try {
      const canvas = await html2canvas(areaToPrint);
      
      const w: number = borderToPrint.offsetWidth;
      const h: number = borderToPrint.offsetHeight;
      const imgData: string = canvas.toDataURL('image/jpeg', 0.95);
      
      const pdfDoc: jsPDF = new jsPDF("landscape", "px", [w, h]);
      pdfDoc.addImage(imgData, 'JPEG', 0, 0, w, h);
      pdfDoc.save(finalFileName);
      
      observer.next(finalFileName);
      observer.complete();
    } catch (error) {
      observer.error(error);
    }
  })();
}

Backend PDF generation

For server-side PDF generation:
Backend PDF
public GetPDF(subjectName: string | undefined): Observable<HttpEvent<any>> {
  const baseUrl = this._configService.getConfigValue('baseUrlNetCore');
  const p_url = `${baseUrl}api/PDFManager/GetPdf?subjectName=${subjectName}`;
  
  const req = new HttpRequest('GET', p_url, {
    reportProgress: true,
    responseType: 'text',
  });
  
  return this.http.request<any>(req);
}
PDF generation uses landscape orientation by default and includes timestamps in filenames.

CSV generation

Generate CSV files from backend data with support for multiple backend languages (C#, Node.js, Java, Python).

Features

  • Multi-backend support (.NET Core, Node.js, Spring Boot, Django)
  • Paginated data tables with Material UI
  • Direct download links
  • File upload support

Implementation

Component
// src/app/_modules/_Demos/_DemosFeatures/files-generation/files-generation-csv/files-generation-csv.component.ts

SetCSVData(): void {
  this.status_message.set("Generating please wait...");
  
  let selectedIndex = this._languajeList.nativeElement.options.selectedIndex;
  
  switch (selectedIndex) {
    case 1: // .NET Core
      let csv_informeLogRemoto = this.backendService.getInformeRemotoCSV();
      
      csv_informeLogRemoto.subscribe({
        next: (csv_data: string) => {
          let jsondata = JSON.parse(csv_data);
          let recordNumber = jsondata.length;
          
          this.status_message.set("[" + recordNumber + "] records found");
          
          this.csv_dataSource = new MatTableDataSource<PersonEntity>(jsondata);
          this.csv_dataSource.paginator = this.csv_paginator;
        },
        error: (err: Error) => {
          this.status_message.set("[An error ocurred]");
        }
      });
      break;
      
    case 2: // Node.js
      let csv_informeLogRemoto_NodeJS = this.backendService.getInformeRemotoCSV_NodeJS();
      
      csv_informeLogRemoto_NodeJS.subscribe({
        next: (csv_data_node_js: string) => {
          let csv_data_node_js_json = JSON.parse(csv_data_node_js)['recordsets'][0];
          let recordNumber = csv_data_node_js_json.length;
          
          this.status_message.set("[" + recordNumber + "] records found");
          
          this.csv_dataSource = new MatTableDataSource<PersonEntity>(csv_data_node_js_json);
          this.csv_dataSource.paginator = this.csv_paginator;
        }
      });
      break;
  }
}

XLS generation

Create Excel spreadsheets from database queries with filtering and pagination.

Features

  • Server-side XLS generation
  • Date range filtering
  • Row limit configuration
  • Multi-backend support

Implementation

Component
// src/app/_modules/_Demos/_DemosFeatures/files-generation/files-generation-xls/files-generation-xls.component.ts

td_GenerarInformeXLS(_searchCriteria: SearchCriteria) {
  let td_excelFileName = this.backendService.getInformeExcel(this._model);
  
  this.td_ExcelDownloadLink = "#";
  this.td_buttonCaption_xls = "[Generating please wait ...]";
  this.status_message.set("[Generating please wait ...]");
  
  td_excelFileName.subscribe({
    next: (_excelFileName: string) => {
      let urlFile = UtilManager.DebugHostingContent(_excelFileName);
      
      this.td_ExcelDownloadLink = `${this.configService.getConfigValue('baseUrlNetCore')}/wwwroot/xlsx/${urlFile}`;
      
      this.status_message.set("[XLS file generated correctly]");
      this.td_textStatus_xls = "[Download XLS File]";
    },
    error: (err: Error) => {
      this.td_buttonCaption_xls = "[An error ocurred]";
      this.td_textStatus_xls = "[An error ocurred]";
      this.status_message.set("[An error ocurred]");
    },
    complete: () => {
      this.td_buttonCaption_xls = "[Generate XLS]";
    }
  });
}

Search criteria

Search Form
rf_searchForm = this.formBuilder.group({
  _P_ROW_NUM: ["999", Validators.required],
  _P_FECHA_INICIO: ["2023-01-01", Validators.required],
  _P_FECHA_FIN: ["2022-12-31", Validators.required],
});

_model = new SearchCriteria(
  "1",
  "1",
  "999",
  "2022-09-01",
  "2022-09-30",
  "",
  ""
);

Chart generation

Create interactive charts using Chart.js with pie charts, bar charts, and line graphs.

Chart types

Pie Chart
// src/app/_modules/_Demos/_DemosFeatures/files-generation/chart/chart.component.ts

SetPieChart(): void {
  const statLabels: string[] = [];
  const statData: Number[] = [];
  const statBackgroundColor: string[] = [];
  
  let csv_informeLogRemoto = this.backendService.getInformeRemotoCSV_STAT();
  
  csv_informeLogRemoto.subscribe({
    next: (csv_data: string) => {
      let jsondata = JSON.parse(csv_data);
      
      jsondata.forEach((element: JSON, index: number) => {
        statLabels.push(jsondata[index]["ciudad"]);
        statData.push(Number(jsondata[index]["id_Column"]));
        
        let randomNumber_1 = Math.floor(Math.random() * 100);
        let randomNumber_2 = Math.floor(Math.random() * 100);
        let randomNumber_3 = Math.floor(Math.random() * 100);
        
        let rgbStr = 'rgb('
          + (Number(jsondata[index]["id_Column"]) + randomNumber_1) + ','
          + (Number(jsondata[index]["id_Column"]) + randomNumber_2) + ','
          + (Number(jsondata[index]["id_Column"]) + randomNumber_3) + ')';
        
        statBackgroundColor.push(rgbStr);
      });
    },
    complete: () => {
      const data = {
        labels: statLabels,
        datasets: [{
          label: 'CITIES',
          data: statData,
          backgroundColor: statBackgroundColor,
          hoverOffset: 4
        }]
      };
      
      let context = this.canvas_csv.nativeElement.getContext('2d');
      
      this.pieChartVar_csv = new Chart(context, {
        type: 'pie',
        data: data,
        options: {
          responsive: true,
          plugins: {
            legend: {
              position: 'bottom',
            },
            title: {
              display: true,
              text: 'CITIES'
            }
          }
        }
      });
    }
  });
}

Chart.js configuration

Setup
import { Chart, registerables } from 'chart.js';

constructor() {
  Chart.register(...registerables);
}

@ViewChild('canvas_csv') canvas_csv: any;
@ViewChild('canvas_xls') canvas_xls: any;

public pieChartVar_csv: any;
public pieChartVar_xls: any;
Remember to register Chart.js components before using them in the constructor.

File generation workflow

Best practices

  • Use landscape orientation for wide visualizations
  • Include timestamps in filenames for uniqueness
  • Handle errors gracefully with user feedback
  • Consider file size for large canvases
  • Validate data before sending to backend
  • Show loading indicators during generation
  • Provide download links instead of automatic downloads
  • Clean up temporary files on the server
  • Use responsive chart configurations
  • Generate dynamic colors for better visualization
  • Include legends and titles for clarity
  • Export charts to PDF for sharing

Computer vision

Image processing and OCR features

Algorithms

Algorithm visualizations for export

Build docs developers (and LLMs) love