PDF-Schedule-Generator optimized
This commit is contained in:
@@ -1,43 +0,0 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
defineProps({
|
||||
msg: String,
|
||||
})
|
||||
|
||||
const count = ref(0)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>{{ msg }}</h1>
|
||||
|
||||
<div class="card">
|
||||
<button type="button" @click="count++">count is {{ count }}</button>
|
||||
<p>
|
||||
Edit
|
||||
<code>components/HelloWorld.vue</code> to test HMR
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Check out
|
||||
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
|
||||
>create-vue</a
|
||||
>, the official Vue + Vite starter
|
||||
</p>
|
||||
<p>
|
||||
Learn more about IDE Support for Vue in the
|
||||
<a
|
||||
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
|
||||
target="_blank"
|
||||
>Vue Docs Scaling up Guide</a
|
||||
>.
|
||||
</p>
|
||||
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
</style>
|
||||
95
frontend/src/components/PDFGenerator.js
Normal file
95
frontend/src/components/PDFGenerator.js
Normal file
@@ -0,0 +1,95 @@
|
||||
import jsPDF from 'jspdf';
|
||||
import html2canvas from 'html2canvas';
|
||||
|
||||
class PDFGenerator {
|
||||
constructor(margin = 20, columnGap = 10) {
|
||||
this.pdf = new jsPDF('p', 'mm', 'a4');
|
||||
this.margin = margin;
|
||||
this.columnGap = columnGap;
|
||||
this.pageHeight = 295 - margin * 2; // A4 height in mm minus Ränder
|
||||
this.columnWidth = (210 - margin * 2 - columnGap) / 2; // Zwei Spalten mit Lücke dazwischen
|
||||
this.position = margin;
|
||||
this.yPos = this.position;
|
||||
this.xPos = margin;
|
||||
this.isLeftColumn = true;
|
||||
}
|
||||
|
||||
async addSchedule(element) {
|
||||
const canvas = await html2canvas(element, { scale: 2 });
|
||||
const imgData = canvas.toDataURL('image/png');
|
||||
const imgWidth = 210 - this.margin * 2; // A4 width in mm minus Ränder
|
||||
const imgHeight = (canvas.height * imgWidth) / canvas.width;
|
||||
let heightLeft = imgHeight;
|
||||
let position = this.margin;
|
||||
|
||||
this.pdf.addImage(imgData, 'PNG', this.margin, position, imgWidth, imgHeight);
|
||||
heightLeft -= this.pageHeight;
|
||||
|
||||
while (heightLeft >= 0) {
|
||||
position = heightLeft - imgHeight + this.margin;
|
||||
this.pdf.addPage();
|
||||
this.pdf.addImage(imgData, 'PNG', this.margin, position, imgWidth, imgHeight);
|
||||
heightLeft -= this.pageHeight;
|
||||
}
|
||||
}
|
||||
|
||||
addNewPage() {
|
||||
this.pdf.addPage();
|
||||
this.xPos = this.margin;
|
||||
this.yPos = this.position;
|
||||
this.isLeftColumn = true;
|
||||
}
|
||||
|
||||
addHeader(title) {
|
||||
this.pdf.setFontSize(12);
|
||||
this.pdf.setFont('helvetica', 'bold');
|
||||
this.pdf.text(title, this.margin, this.position);
|
||||
this.pdf.setLineWidth(0.5);
|
||||
this.pdf.line(this.margin, this.position + 2, 210 - this.margin, this.position + 2);
|
||||
this.yPos += 10;
|
||||
this.position = this.yPos;
|
||||
}
|
||||
|
||||
addAddress(clubName, addressLines) {
|
||||
this.pdf.setFontSize(10);
|
||||
|
||||
// Vereinname fett drucken
|
||||
this.pdf.setFont('helvetica', 'bold');
|
||||
this.pdf.text(clubName, this.xPos, this.yPos);
|
||||
this.yPos += 5;
|
||||
|
||||
this.pdf.setFont('helvetica', 'normal');
|
||||
addressLines.forEach(line => {
|
||||
this.pdf.text(line, this.xPos, this.yPos);
|
||||
this.yPos += 5;
|
||||
});
|
||||
|
||||
this.yPos += 10; // Abstand zwischen den Adressen
|
||||
|
||||
// Spaltenwechsel oder neuer Seite bei Bedarf
|
||||
this.checkColumnOverflow();
|
||||
}
|
||||
|
||||
checkColumnOverflow() {
|
||||
if (this.isLeftColumn) {
|
||||
if (this.yPos > this.pageHeight) {
|
||||
this.xPos += this.columnWidth + this.columnGap; // Zur rechten Spalte wechseln
|
||||
this.yPos = this.position; // Zurück zum Anfang der neuen Spalte
|
||||
this.isLeftColumn = false;
|
||||
}
|
||||
} else {
|
||||
if (this.yPos > this.pageHeight) {
|
||||
this.pdf.addPage();
|
||||
this.xPos = this.margin; // Zurück zur linken Spalte auf der neuen Seite
|
||||
this.yPos = this.position;
|
||||
this.isLeftColumn = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
save(filename) {
|
||||
this.pdf.save(filename);
|
||||
}
|
||||
}
|
||||
|
||||
export default PDFGenerator;
|
||||
@@ -61,6 +61,7 @@ import { mapGetters } from 'vuex';
|
||||
import apiClient from '../apiClient.js';
|
||||
import jsPDF from 'jspdf';
|
||||
import html2canvas from 'html2canvas';
|
||||
import PDFGenerator from '../components/PDFGenerator.js';
|
||||
|
||||
export default {
|
||||
name: 'ScheduleView',
|
||||
@@ -145,32 +146,42 @@ export default {
|
||||
return club ? club.name : '';
|
||||
},
|
||||
async generatePDF() {
|
||||
const element = this.$el.querySelector('.flex-item > div');
|
||||
const element = this.$el.querySelector('.flex-item > div'); // Das richtige div-Element auswählen
|
||||
if (element) {
|
||||
const canvas = await html2canvas(element, {
|
||||
scale: 2
|
||||
const pdfGen = new PDFGenerator();
|
||||
await pdfGen.addSchedule(element);
|
||||
pdfGen.addNewPage();
|
||||
pdfGen.addHeader('Hallen-Adressen');
|
||||
const uniqueLocations = this.getUniqueLocations();
|
||||
uniqueLocations.forEach((addressLines, clubName) => {
|
||||
pdfGen.addAddress(clubName, addressLines);
|
||||
});
|
||||
const imgData = canvas.toDataURL('image/png');
|
||||
const pdf = new jsPDF('p', 'mm', 'a4');
|
||||
const margin = 20;
|
||||
const imgWidth = 210 - margin * 2;
|
||||
const pageHeight = 295 - margin * 2;
|
||||
const imgHeight = (canvas.height * imgWidth) / canvas.width;
|
||||
let heightLeft = imgHeight;
|
||||
let position = margin;
|
||||
pdf.addImage(imgData, 'PNG', margin, position, imgWidth, imgHeight);
|
||||
heightLeft -= pageHeight;
|
||||
while (heightLeft >= 0) {
|
||||
position = heightLeft - imgHeight;
|
||||
pdf.addPage();
|
||||
pdf.addImage(imgData, 'PNG', margin, position, imgWidth, imgHeight);
|
||||
heightLeft -= pageHeight;
|
||||
}
|
||||
|
||||
pdf.save('Spielpläne.pdf');
|
||||
pdfGen.save('Spielpläne.pdf');
|
||||
} else {
|
||||
console.error('No matches found to generate PDF.');
|
||||
}
|
||||
},
|
||||
getUniqueLocations() {
|
||||
const uniqueLocations = new Map();
|
||||
|
||||
this.matches.forEach(match => {
|
||||
const location = match.location;
|
||||
const clubName = match.homeTeam.name;
|
||||
const addressLines = [
|
||||
location.name,
|
||||
location.address,
|
||||
`${location.zip} ${location.city}`
|
||||
];
|
||||
|
||||
const addressKey = addressLines.join('; '); // Unique key für die Map
|
||||
|
||||
if (!uniqueLocations.has(addressKey)) {
|
||||
uniqueLocations.set(clubName, addressLines);
|
||||
}
|
||||
});
|
||||
|
||||
return uniqueLocations;
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
@@ -215,9 +226,11 @@ tr:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
th, td {
|
||||
th,
|
||||
td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.hover-info {
|
||||
margin-top: 10px;
|
||||
background-color: #eef;
|
||||
@@ -226,8 +239,8 @@ th, td {
|
||||
border-radius: 4px;
|
||||
max-width: 300px;
|
||||
position: fixed;
|
||||
top:16em;
|
||||
left:14em;
|
||||
top: 16em;
|
||||
left: 14em;
|
||||
}
|
||||
|
||||
.modal {
|
||||
|
||||
Reference in New Issue
Block a user