diff --git a/packages/common/src/lib/image/secure-image.pipe.ts b/packages/common/src/lib/image/secure-image.pipe.ts index b029d6f07c..6d490898d7 100644 --- a/packages/common/src/lib/image/secure-image.pipe.ts +++ b/packages/common/src/lib/image/secure-image.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; import { switchMap } from 'rxjs/operators'; @@ -10,24 +10,26 @@ import { switchMap } from 'rxjs/operators'; export class SecureImagePipe implements PipeTransform { constructor(private http: HttpClient) {} - transform(url: string) { + transform(url: string): Observable { + const headers1 = new HttpHeaders(); + headers1.append('Content-Type', 'text/plain'); + headers1.append('activityInterceptor', 'false'); return this.http .get(url, { - headers: { - activityInterceptor: 'false' - }, + headers: headers1, responseType: 'blob' }) .pipe( - switchMap(blob => { - return new Observable(observer => { + switchMap((blob) => { + return new Observable((observer) => { const reader = new FileReader(); reader.readAsDataURL(blob); reader.onloadend = () => { observer.next(reader.result); + observer.complete(); }; }); }) - ); + ) as Observable; } } diff --git a/packages/geo/src/lib/print/print/print.component.ts b/packages/geo/src/lib/print/print/print.component.ts index 2acfb27d9d..b1e0bb4828 100644 --- a/packages/geo/src/lib/print/print/print.component.ts +++ b/packages/geo/src/lib/print/print/print.component.ts @@ -1,7 +1,6 @@ import { Component, Input } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { take } from 'rxjs/operators'; -import { SubjectStatus } from '@igo2/utils'; import { IgoMap } from '../../map/shared/map'; import { PrintOptions } from '../shared/print.interface'; @@ -102,28 +101,42 @@ export class PrintComponent { this.printService.defineNbFileToProcess(nbFileToProcess); const resolution = +data.resolution; - this.printService.downloadMapImage( - this.map, - resolution, - data.imageFormat, - data.showProjection, - data.showScale, - data.showLegend, - data.title, - data.comment, - data.doZipFile - ); - if (data.showLegend) { - this.printService.getLayersLegendImage( + + let nbRequests = data.showLegend ? 2 : 1; + this.printService + .downloadMapImage( this.map, + resolution, data.imageFormat, - data.doZipFile, - +resolution - ); + data.showProjection, + data.showScale, + data.showLegend, + data.title, + data.comment, + data.doZipFile + ) + .pipe(take(1)) + .subscribe(() => { + nbRequests--; + if (!nbRequests) { + this.disabled$.next(false); + } + }); + if (data.showLegend) { + this.printService + .getLayersLegendImage( + this.map, + data.imageFormat, + data.doZipFile, + +resolution + ) + .then(() => { + nbRequests--; + if (!nbRequests) { + this.disabled$.next(false); + } + }); } - setTimeout(() => { - this.disabled$.next(false); - }, 1000); } } } diff --git a/packages/geo/src/lib/print/shared/print.service.ts b/packages/geo/src/lib/print/shared/print.service.ts index 9651643511..4f5372dbe9 100644 --- a/packages/geo/src/lib/print/shared/print.service.ts +++ b/packages/geo/src/lib/print/shared/print.service.ts @@ -1,7 +1,8 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { Subject } from 'rxjs'; +import { Observable, Subject, forkJoin } from 'rxjs'; +import { map as rxMap } from 'rxjs/operators'; import { saveAs } from 'file-saver'; import * as jsPDF from 'jspdf'; @@ -9,11 +10,11 @@ import html2canvas from 'html2canvas'; import * as JSZip from 'jszip'; import { SubjectStatus } from '@igo2/utils'; +import { SecureImagePipe } from '@igo2/common'; import { MessageService, ActivityService, LanguageService } from '@igo2/core'; import { IgoMap } from '../../map/shared/map'; import { formatScale } from '../../map/shared/map.utils'; -import { OutputLayerLegend } from '../../layer/shared/layers/layer.interface'; import { getLayersLegends } from '../../layer/utils/outputLegend'; import { PrintOptions } from './print.interface'; @@ -73,12 +74,12 @@ export class PrintService { } this.addMap(doc, map, resolution, size, margins).subscribe( - (status: SubjectStatus) => { + async (status: SubjectStatus) => { if (status === SubjectStatus.Done) { if (options.showLegend === true) { - this.addLegend(doc, map, margins, resolution); + await this.addLegend(doc, map, margins, resolution); } else { - this.saveDoc(doc); + await this.saveDoc(doc); } } @@ -98,35 +99,58 @@ export class PrintService { * @param width The width that the legend need to be * @return Html code for the legend */ - getLayersLegendHtml(map: IgoMap, width: number, resolution: number): string { - let html = ''; - const legends = getLayersLegends( - map.layers, - map.viewController.getScale(resolution) - ); - if (legends.length === 0) { - return html; - } + getLayersLegendHtml( + map: IgoMap, + width: number, + resolution: number + ): Observable { + return new Observable((observer) => { + let html = ''; + const legends = getLayersLegends( + map.layers, + map.viewController.getScale(resolution) + ); + if (legends.length === 0) { + observer.next(html); + observer.complete(); + return; + } - // Define important style to be sure that all container is convert - // to image not just visible part - html += ''; - html += ''; - html += '
'; - // For each legend, define an html table cell - legends.forEach((legend: OutputLayerLegend) => { - html += - ''; - html += ''; - html += '
' + legend.title + ''; - html += '
'; + // Define important style to be sure that all container is convert + // to image not just visible part + html += ''; + html += ''; + html += '
'; + + // For each legend, define an html table cell + const images$ = legends.map((legend) => + this.getDataImage(legend.url).pipe( + rxMap((dataImage) => { + let htmlImg = + ''; + htmlImg += ''; + htmlImg += + '
' + legend.title + ''; + htmlImg += '
'; + return htmlImg; + }) + ) + ); + forkJoin(images$).subscribe((dataImages) => { + html = dataImages.reduce((acc, current) => (acc += current), html); + html += '
'; + observer.next(html); + observer.complete(); + }); }); - html += '
'; + } - return html; + getDataImage(url: string): Observable { + const secureIMG = new SecureImagePipe(this.http); + return secureIMG.transform(url); } /** @@ -134,7 +158,7 @@ export class PrintService { * * @param format - Image format. default value to "png" * @return The image of the legend */ - getLayersLegendImage( + async getLayersLegendImage( map, format: string = 'png', doZipFile: boolean, @@ -143,8 +167,11 @@ export class PrintService { const status$ = new Subject(); // Get html code for the legend const width = 200; // milimeters unit, originally define for document pdf - let html = this.getLayersLegendHtml(map, width, resolution); - const that = this; + let html = await this.getLayersLegendHtml( + map, + width, + resolution + ).toPromise(); format = format.toLowerCase(); // If no legend show No LEGEND in an image @@ -161,45 +188,29 @@ export class PrintService { window.document.body.appendChild(div); div.innerHTML = html; - // Define event to execute after all images are loaded to create the canvas - const toCanvas = () => { - html2canvas(div, { useCORS: true }) - .then((canvas) => { - let status = SubjectStatus.Done; - try { - if (!doZipFile) { - // Save the canvas as file - that.saveCanvasImageAsFile(canvas, 'legendImage', format); - } else { - // Add the canvas to zip - that.generateCanvaFileToZip(canvas, 'legendImage' + '.' + format); - } - div.parentNode.removeChild(div); // remove temp div (IE) - } catch (err) { - status = SubjectStatus.Error; - } - status$.next(status); - }) - .catch((e) => { - console.log(e); - }); - }; - - const imgList = div.getElementsByTagName('img'); - const waitImgCompleted = setInterval(() => { - let completed = true; - for (let i = 0; i < imgList.length; i++) { - if (imgList.item(i).complete === false) { - completed = false; - break; + await this.timeout(1); + const canvas = await html2canvas(div, { useCORS: true }).catch((e) => { + console.log(e); + }); + + if (canvas) { + let status = SubjectStatus.Done; + try { + if (!doZipFile) { + // Save the canvas as file + this.saveCanvasImageAsFile(canvas, 'legendImage', format); + } else { + // Add the canvas to zip + this.generateCanvaFileToZip(canvas, 'legendImage' + '.' + format); } + div.parentNode.removeChild(div); // remove temp div (IE) + } catch (err) { + status = SubjectStatus.Error; } + status$.next(status); + } - if (completed) { - clearInterval(waitImgCompleted); - toCanvas(); - } - }, 100); + return status$; } private addTitle(doc: jsPDF, title: string, pageWidth: number) { @@ -280,19 +291,22 @@ export class PrintService { * @param map - Map of the app * @param margins - Page margins */ - private addLegend( + private async addLegend( doc: jsPDF, map: IgoMap, margins: Array, resolution: number ) { - const that = this; // Get html code for the legend const width = doc.internal.pageSize.width; - const html = this.getLayersLegendHtml(map, width, resolution); + const html = await this.getLayersLegendHtml( + map, + width, + resolution + ).toPromise(); // If no legend, save the map directly if (html === '') { - this.saveDoc(doc); + await this.saveDoc(doc); return true; } // Create div to contain html code for legend @@ -304,45 +318,25 @@ export class PrintService { window.document.body.appendChild(div); div.innerHTML = html; - const toCanvas = () => { - html2canvas(div, { useCORS: true }) - .then((canvas) => { - let imgData; - const position = 10; - imgData = canvas.toDataURL('image/png'); - doc.addPage(); - const imageSize = this.getImageSizeToFitPdf(doc, canvas, margins); - doc.addImage( - imgData, - 'PNG', - 10, - position, - imageSize[0], - imageSize[1] - ); - that.saveDoc(doc); - div.parentNode.removeChild(div); // remove temp div (IE style) - }) - .catch((e) => { - console.log(e); - }); - }; - - const imgList = div.getElementsByTagName('img'); - const waitImgCompleted = setInterval(() => { - let completed = true; - for (let i = 0; i < imgList.length; i++) { - if (imgList.item(i).complete === false) { - completed = false; - break; - } - } + await this.timeout(1); + const canvas = await html2canvas(div, { useCORS: true }).catch((e) => { + console.log(e); + }); - if (completed) { - clearInterval(waitImgCompleted); - toCanvas(); - } - }, 100); + if (canvas) { + let imgData; + const position = 10; + imgData = canvas.toDataURL('image/png'); + doc.addPage(); + const imageSize = this.getImageSizeToFitPdf(doc, canvas, margins); + doc.addImage(imgData, 'PNG', 10, position, imageSize[0], imageSize[1]); + await this.saveDoc(doc); + div.parentNode.removeChild(div); // remove temp div (IE style) + } + } + + private timeout(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); } private addCanvas( @@ -635,6 +629,8 @@ export class PrintService { } }); map.ol.renderSync(); + + return status$; } private renderMap(map, size, extent) { @@ -645,8 +641,8 @@ export class PrintService { * Save document * @param doc - Document to save */ - protected saveDoc(doc: jsPDF) { - doc.save('map.pdf'); + protected async saveDoc(doc: jsPDF) { + await doc.save('map.pdf', { returnPromise: true }); } /**