185 lines
5.0 KiB
TypeScript
185 lines
5.0 KiB
TypeScript
import html2canvas from 'html2canvas'
|
|
import jsPDF from 'jspdf'
|
|
import type { Project, DrawFeature } from '@/types'
|
|
import { formatDateTime } from './utils'
|
|
|
|
export interface ExportOptions {
|
|
includeTitle?: boolean
|
|
includeLegend?: boolean
|
|
includeTimestamp?: boolean
|
|
author?: string
|
|
}
|
|
|
|
export async function exportToPNG(
|
|
mapElement: HTMLElement,
|
|
project: Project,
|
|
options: ExportOptions = {}
|
|
): Promise<void> {
|
|
try {
|
|
const canvas = await html2canvas(mapElement, {
|
|
useCORS: true,
|
|
allowTaint: true,
|
|
scale: 2,
|
|
logging: false,
|
|
backgroundColor: '#ffffff',
|
|
})
|
|
|
|
const link = document.createElement('a')
|
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19)
|
|
link.download = `Lageplan_${project.title.replace(/[^a-z0-9äöüß]/gi, '_')}_${timestamp}.png`
|
|
link.href = canvas.toDataURL('image/png', 1.0)
|
|
link.click()
|
|
} catch (error) {
|
|
console.error('PNG export failed:', error)
|
|
throw new Error('PNG Export fehlgeschlagen')
|
|
}
|
|
}
|
|
|
|
export interface LegendEntry {
|
|
name: string
|
|
count: number
|
|
iconUrl?: string
|
|
unNummer?: string
|
|
gefahrennummer?: string
|
|
}
|
|
|
|
export async function exportToPDF(
|
|
mapElement: HTMLElement,
|
|
project: Project,
|
|
features: DrawFeature[],
|
|
legendEntries: LegendEntry[] = [],
|
|
options: ExportOptions = {}
|
|
): Promise<void> {
|
|
try {
|
|
const canvas = await html2canvas(mapElement, {
|
|
useCORS: true,
|
|
allowTaint: true,
|
|
scale: 2,
|
|
logging: false,
|
|
backgroundColor: '#ffffff',
|
|
})
|
|
|
|
const imgWidth = 190
|
|
const imgHeight = (canvas.height * imgWidth) / canvas.width
|
|
|
|
const pdf = new jsPDF('p', 'mm', 'a4')
|
|
|
|
// Title Block
|
|
pdf.setFillColor(220, 38, 38) // Red header
|
|
pdf.rect(0, 0, 210, 8, 'F')
|
|
|
|
pdf.setTextColor(255, 255, 255)
|
|
pdf.setFontSize(12)
|
|
pdf.setFont('helvetica', 'bold')
|
|
pdf.text('LAGEPLAN - FEUERWEHR', 10, 5.5)
|
|
|
|
pdf.setTextColor(0, 0, 0)
|
|
|
|
// Project info box
|
|
pdf.setFillColor(245, 245, 245)
|
|
pdf.rect(10, 12, 190, 28, 'F')
|
|
pdf.setDrawColor(200, 200, 200)
|
|
pdf.rect(10, 12, 190, 28, 'S')
|
|
|
|
pdf.setFontSize(14)
|
|
pdf.setFont('helvetica', 'bold')
|
|
pdf.text(project.title, 15, 22)
|
|
|
|
pdf.setFontSize(10)
|
|
pdf.setFont('helvetica', 'normal')
|
|
|
|
let infoY = 28
|
|
if (project.location) {
|
|
pdf.text(`Einsatzort: ${project.location}`, 15, infoY)
|
|
infoY += 5
|
|
}
|
|
|
|
const now = new Date()
|
|
pdf.text(`Datum: ${now.toLocaleDateString('de-DE')}`, 15, infoY)
|
|
pdf.text(`Uhrzeit: ${now.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })}`, 80, infoY)
|
|
|
|
if (options.author) {
|
|
pdf.text(`Ersteller: ${options.author}`, 130, infoY)
|
|
}
|
|
|
|
// Map image
|
|
const mapY = 45
|
|
const maxMapHeight = legendEntries.length > 0 ? 180 : 220
|
|
const actualMapHeight = Math.min(imgHeight, maxMapHeight)
|
|
|
|
pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 10, mapY, imgWidth, actualMapHeight)
|
|
pdf.setDrawColor(100, 100, 100)
|
|
pdf.rect(10, mapY, imgWidth, actualMapHeight, 'S')
|
|
|
|
// Legend
|
|
if (legendEntries.length > 0) {
|
|
const legendY = mapY + actualMapHeight + 8
|
|
|
|
pdf.setFillColor(245, 245, 245)
|
|
pdf.rect(10, legendY, 190, 6, 'F')
|
|
|
|
pdf.setFontSize(10)
|
|
pdf.setFont('helvetica', 'bold')
|
|
pdf.text('Legende', 15, legendY + 4.5)
|
|
|
|
pdf.setFontSize(8)
|
|
pdf.setFont('helvetica', 'normal')
|
|
|
|
let y = legendY + 12
|
|
const colWidth = 63
|
|
let col = 0
|
|
|
|
legendEntries.forEach((entry, i) => {
|
|
if (y < 280) {
|
|
const x = 15 + (col * colWidth)
|
|
let text = `• ${entry.name}`
|
|
if (entry.count > 1) text += ` (${entry.count})`
|
|
if (entry.unNummer) text += ` [UN ${entry.unNummer}]`
|
|
|
|
pdf.text(text, x, y)
|
|
|
|
col++
|
|
if (col >= 3) {
|
|
col = 0
|
|
y += 5
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// Footer
|
|
pdf.setFontSize(7)
|
|
pdf.setTextColor(128, 128, 128)
|
|
pdf.text(
|
|
`Erstellt mit Lageplan-App | ${now.toLocaleDateString('de-DE')} ${now.toLocaleTimeString('de-DE')}`,
|
|
10,
|
|
292
|
|
)
|
|
pdf.text('Seite 1 von 1', 180, 292)
|
|
|
|
const timestamp = now.toISOString().replace(/[:.]/g, '-').slice(0, 19)
|
|
pdf.save(`Lageplan_${project.title.replace(/[^a-z0-9äöüß]/gi, '_')}_${timestamp}.pdf`)
|
|
} catch (error) {
|
|
console.error('PDF export failed:', error)
|
|
throw new Error('PDF Export fehlgeschlagen')
|
|
}
|
|
}
|
|
|
|
export async function exportToGeoJSON(projectId: string): Promise<void> {
|
|
try {
|
|
const res = await fetch(`/api/projects/${projectId}/export?format=geojson`)
|
|
if (!res.ok) throw new Error('Export fehlgeschlagen')
|
|
|
|
const blob = await res.blob()
|
|
const url = URL.createObjectURL(blob)
|
|
const link = document.createElement('a')
|
|
link.href = url
|
|
link.download = `project_${projectId}.geojson`
|
|
link.click()
|
|
URL.revokeObjectURL(url)
|
|
} catch (error) {
|
|
console.error('GeoJSON export failed:', error)
|
|
throw new Error('GeoJSON Export fehlgeschlagen')
|
|
}
|
|
}
|