v1.0.3: Fix PDF footer overlap, arrow alignment, screenshot quality, arrowheads in export

This commit is contained in:
Pepe Ziberi
2026-02-21 16:28:32 +01:00
parent c11565aaf8
commit 25d3d553ff
5 changed files with 38 additions and 12 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "lageplan", "name": "lageplan",
"version": "1.0.2", "version": "1.0.3",
"description": "Feuerwehr Lageplan - Krokier-App für Einsatzdokumentation", "description": "Feuerwehr Lageplan - Krokier-App für Einsatzdokumentation",
"private": true, "private": true,
"scripts": { "scripts": {

View File

@@ -1130,6 +1130,32 @@ export default function AppPage() {
} }
} }
// Draw arrowheads for arrow features
for (const f of currentFeatures.filter(f => f.type === 'arrow')) {
if (f.geometry.type !== 'LineString') continue
const lineCoords = f.geometry.coordinates as number[][]
if (lineCoords.length < 2) continue
const p1 = lineCoords[lineCoords.length - 2]
const p2 = lineCoords[lineCoords.length - 1]
const px1 = mapInstance.project(p1 as [number, number])
const px2 = mapInstance.project(p2 as [number, number])
const angle = Math.atan2(px2.y - px1.y, px2.x - px1.x)
const color = (f.properties.color as string) || '#000000'
const arrowSize = 14 * dpr
ctx.save()
ctx.translate(px2.x * dpr, px2.y * dpr)
ctx.rotate(angle + Math.PI / 2)
ctx.beginPath()
ctx.moveTo(0, -arrowSize)
ctx.lineTo(-arrowSize * 0.7, arrowSize * 0.3)
ctx.lineTo(arrowSize * 0.7, arrowSize * 0.3)
ctx.closePath()
ctx.fillStyle = color
ctx.fill()
ctx.restore()
}
// Draw line/polygon label markers at midpoints // Draw line/polygon label markers at midpoints
for (const f of currentFeatures.filter(f => f.properties.label && (f.geometry.type === 'LineString' || f.geometry.type === 'Polygon'))) { for (const f of currentFeatures.filter(f => f.properties.label && (f.geometry.type === 'LineString' || f.geometry.type === 'Polygon'))) {
const label = f.properties.label as string const label = f.properties.label as string

View File

@@ -1030,8 +1030,8 @@ export function JournalView({ projectId, projectTitle, projectLocation, einsatzl
if (mapRef?.current) { if (mapRef?.current) {
const canvas = mapRef.current.getCanvas() const canvas = mapRef.current.getCanvas()
if (canvas) { if (canvas) {
// Resize to max 1600px wide and convert to JPEG // Resize to max 2400px wide and convert to JPEG
const maxW = 1600 const maxW = 2400
const ratio = Math.min(1, maxW / canvas.width) const ratio = Math.min(1, maxW / canvas.width)
const offscreen = document.createElement('canvas') const offscreen = document.createElement('canvas')
offscreen.width = Math.round(canvas.width * ratio) offscreen.width = Math.round(canvas.width * ratio)
@@ -1039,18 +1039,18 @@ export function JournalView({ projectId, projectTitle, projectLocation, einsatzl
const ctx = offscreen.getContext('2d') const ctx = offscreen.getContext('2d')
if (ctx) { if (ctx) {
ctx.drawImage(canvas, 0, 0, offscreen.width, offscreen.height) ctx.drawImage(canvas, 0, 0, offscreen.width, offscreen.height)
mapScreenshot = offscreen.toDataURL('image/jpeg', 0.75) mapScreenshot = offscreen.toDataURL('image/jpeg', 0.85)
} }
} }
} }
} catch (e) { console.warn('Map screenshot failed:', e) } } catch (e) { console.warn('Map screenshot failed:', e) }
} else if (rawScreenshot.length > 500000) { } else if (rawScreenshot.length > 800000) {
// Compress pre-captured screenshot if too large // Compress pre-captured screenshot if too large
try { try {
const img = new Image() const img = new Image()
img.src = rawScreenshot img.src = rawScreenshot
await new Promise(r => { img.onload = r; img.onerror = r }) await new Promise(r => { img.onload = r; img.onerror = r })
const maxW = 1600 const maxW = 2400
const ratio = Math.min(1, maxW / img.naturalWidth) const ratio = Math.min(1, maxW / img.naturalWidth)
const offscreen = document.createElement('canvas') const offscreen = document.createElement('canvas')
offscreen.width = Math.round(img.naturalWidth * ratio) offscreen.width = Math.round(img.naturalWidth * ratio)
@@ -1058,7 +1058,7 @@ export function JournalView({ projectId, projectTitle, projectLocation, einsatzl
const ctx = offscreen.getContext('2d') const ctx = offscreen.getContext('2d')
if (ctx) { if (ctx) {
ctx.drawImage(img, 0, 0, offscreen.width, offscreen.height) ctx.drawImage(img, 0, 0, offscreen.width, offscreen.height)
mapScreenshot = offscreen.toDataURL('image/jpeg', 0.75) mapScreenshot = offscreen.toDataURL('image/jpeg', 0.85)
} }
} catch { mapScreenshot = rawScreenshot } } catch { mapScreenshot = rawScreenshot }
} else { } else {

View File

@@ -1377,12 +1377,12 @@ export function MapView({
const lineCoords = f.geometry.coordinates as number[][] const lineCoords = f.geometry.coordinates as number[][]
if (lineCoords.length < 2) return if (lineCoords.length < 2) return
// Get last two points to calculate arrow direction // Get last two points to calculate arrow direction using screen-projected coords
const p1 = lineCoords[lineCoords.length - 2] const p1 = lineCoords[lineCoords.length - 2]
const p2 = lineCoords[lineCoords.length - 1] const p2 = lineCoords[lineCoords.length - 1]
const angle = Math.atan2(p2[1] - p1[1], p2[0] - p1[0]) * (180 / Math.PI) const px1 = map.current.project(p1 as [number, number])
// MapLibre uses screen coords where Y is inverted, so negate the angle const px2 = map.current.project(p2 as [number, number])
const screenAngle = -angle + 90 const screenAngle = Math.atan2(px2.y - px1.y, px2.x - px1.x) * (180 / Math.PI) + 90
const color = (f.properties.color as string) || '#000000' const color = (f.properties.color as string) || '#000000'
const arrowEl = document.createElement('div') const arrowEl = document.createElement('div')

View File

@@ -4,7 +4,7 @@ import { Document, Page, Text, View, StyleSheet, Font, Image } from '@react-pdf/
// Register default font (Helvetica is built-in) // Register default font (Helvetica is built-in)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
page: { page: {
padding: '12mm 15mm 15mm', padding: '12mm 15mm 32mm',
fontFamily: 'Helvetica', fontFamily: 'Helvetica',
fontSize: 10, fontSize: 10,
lineHeight: 1.4, lineHeight: 1.4,