import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class VizExportService { exportSvg(element: SVGSVGElement): string { const serializer = new XMLSerializer(); const svgString = serializer.serializeToString(element); return `\n${svgString}`; } async exportPng(element: SVGSVGElement, width: number, height: number): Promise { const svgString = this.exportSvg(element); const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' }); const url = URL.createObjectURL(svgBlob); try { const img = new Image(); img.width = width; img.height = height; await new Promise((resolve, reject) => { img.onload = () => resolve(); img.onerror = reject; img.src = url; }); const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d')!; ctx.drawImage(img, 0, 0, width, height); return new Promise((resolve, reject) => { canvas.toBlob((blob) => { if (blob) { resolve(blob); } else { reject(new Error('Failed to create PNG blob')); } }, 'image/png'); }); } finally { URL.revokeObjectURL(url); } } downloadSvg(element: SVGSVGElement, filename = 'chart.svg'): void { const svgString = this.exportSvg(element); const blob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' }); this.downloadBlob(blob, filename); } async downloadPng(element: SVGSVGElement, width: number, height: number, filename = 'chart.png'): Promise { const blob = await this.exportPng(element, width, height); this.downloadBlob(blob, filename); } private downloadBlob(blob: Blob, filename: string): void { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); } }