Korrekturen

This commit is contained in:
Andreas Knuth 2024-11-19 20:08:32 +01:00
parent 3be7a9cdec
commit f70af3a59e
2 changed files with 83 additions and 55 deletions

View File

@ -1,6 +1,6 @@
<!-- src/app/upload-image-modal.component.html --> <!-- src/app/upload-image-modal.component.html -->
<div #uploadImageModal id="uploadImageModal" tabindex="-1" aria-hidden="true" class="fixed top-0 left-0 right-0 z-50 hidden w-full p-4 overflow-x-hidden overflow-y-auto md:inset-0 h-modal md:h-full"> <div #uploadImageModal id="uploadImageModal" tabindex="-1" aria-hidden="true" class="fixed top-0 left-0 right-0 z-50 hidden w-full p-4 overflow-x-hidden overflow-y-auto md:inset-0 h-modal md:h-full">
<div class="relative w-full h-full max-w-2xl md:h-auto"> <div class="relative md:h-auto">
<div class="relative bg-white rounded-lg shadow"> <div class="relative bg-white rounded-lg shadow">
<button type="button" class="absolute top-3 right-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center" (click)="closeModal()"> <button type="button" class="absolute top-3 right-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center" (click)="closeModal()">
<svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20"> <svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
@ -8,7 +8,7 @@
</svg> </svg>
<span class="sr-only">Schließen</span> <span class="sr-only">Schließen</span>
</button> </button>
<div class="p-6"> <div class="p-6 relative">
<h3 class="mb-4 text-xl font-medium text-gray-900">Bild zu Deck hinzufügen</h3> <h3 class="mb-4 text-xl font-medium text-gray-900">Bild zu Deck hinzufügen</h3>
<!-- Formular sichtbar, solange formVisible true ist --> <!-- Formular sichtbar, solange formVisible true ist -->
@ -19,21 +19,27 @@
</div> </div>
</div> </div>
<!-- Canvas sichtbar, sobald upload erfolgreich ist --> <!-- Canvas und Save Button sichtbar, sobald canvasVisible true ist -->
<div *ngIf="canvasVisible"> <div *ngIf="canvasVisible" class="mt-4">
<canvas #canvas class="border border-gray-300 rounded"></canvas> <canvas #canvas class="border border-gray-300 rounded w-full h-auto"></canvas>
<button (click)="save()" class="mt-4 bg-green-500 text-white py-2 px-4 rounded hover:bg-green-600">
Save
</button>
</div> </div>
<!-- Statusanzeige --> <!-- Statusanzeige -->
<div *ngIf="processingStatus" class="mt-4"> <div *ngIf="processingStatus && !canvasVisible" class="mt-4">
<p class="text-sm text-gray-700">{{ processingStatus }}</p> <p class="text-sm text-gray-700">{{ processingStatus }}</p>
</div> </div>
<!-- Ladeanzeige --> <!-- Ladeanzeige als Overlay -->
<div *ngIf="loading" class="mt-4"> <div *ngIf="loading" class="absolute inset-0 bg-gray-800 bg-opacity-50 flex items-center justify-center z-10">
<div class="bg-white p-4 rounded shadow">
<p class="text-sm text-gray-700">Verarbeitung läuft...</p> <p class="text-sm text-gray-700">Verarbeitung läuft...</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>

View File

@ -4,14 +4,13 @@ import { DeckService } from '../deck.service';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { fabric } from 'fabric'; import { fabric } from 'fabric';
import { FormsModule } from '@angular/forms';
import { Modal } from 'flowbite'; import { Modal } from 'flowbite';
@Component({ @Component({
selector: 'app-upload-image-modal', selector: 'app-upload-image-modal',
templateUrl: './upload-image-modal.component.html', templateUrl: './upload-image-modal.component.html',
standalone: true, standalone: true,
imports: [CommonModule, FormsModule] imports: [CommonModule]
}) })
export class UploadImageModalComponent implements AfterViewInit, OnDestroy { export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
@Input() deckName: string = ''; @Input() deckName: string = '';
@ -21,37 +20,34 @@ export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
@ViewChild('canvas') canvasElement!: ElementRef<HTMLCanvasElement>; @ViewChild('canvas') canvasElement!: ElementRef<HTMLCanvasElement>;
imageFile: File | null = null; imageFile: File | null = null;
imageText: string = ''; processingStatus: string = '';
modal!: any; // Typ kann je nach Flowbite-Version angepasst werden loading: boolean = false;
canvas!: fabric.Canvas;
// Fabric.js Related Variables // Fabric.js Related Variables
originalImageSrc: string | ArrayBuffer | undefined | null = null; originalImageSrc: string | ArrayBuffer | undefined | null = null;
detectedText: string = ''; detectedText: string = '';
processingStatus: string = ''; boxes: { x1: number; x2: number; y1: number; y2: number }[] = [];
loading: boolean = false; canvas!: fabric.Canvas;
// Maximal erlaubte Größe // Maximal erlaubte Größe
maxCanvasWidth: number = 0; maxCanvasWidth: number = 0;
maxCanvasHeight: number = 0; maxCanvasHeight: number = 0;
boxes: { x1: number; x2: number; y1: number; y2: number }[] = [];
originalImageWidth: number = 0;
originalImageHeight: number = 0;
// Referenz zum Keydown-Eventhandler // Referenz zum Keydown-Eventhandler
private keyDownHandler!: (e: KeyboardEvent) => void; private keyDownHandler!: (e: KeyboardEvent) => void;
// State Management
formVisible: boolean = true;
canvasVisible: boolean = false;
modal:any;
originalImageWidth:number|undefined;
originalImageHeight:number|undefined;
constructor(private deckService: DeckService, private http: HttpClient) { } constructor(private deckService: DeckService, private http: HttpClient) { }
ngAfterViewInit(): void { ngAfterViewInit(): void {
// Initialisiere die Flowbite Modal // Initialisiere die Flowbite Modal
this.modal = new Modal(this.modalElement.nativeElement); this.modal = new Modal(this.modalElement.nativeElement);
// Initialisiere Fabric.js Canvas
this.canvas = new fabric.Canvas(this.canvasElement.nativeElement);
// Berechne die maximal erlaubten Abmessungen basierend auf dem Viewport // Berechne die maximal erlaubten Abmessungen basierend auf dem Viewport
this.maxCanvasWidth = window.innerWidth * 0.6; // Passe nach Bedarf an this.maxCanvasWidth = window.innerWidth * 0.6; // Passe nach Bedarf an
this.maxCanvasHeight = window.innerHeight * 0.6; // Passe nach Bedarf an this.maxCanvasHeight = window.innerHeight * 0.6; // Passe nach Bedarf an
@ -81,15 +77,19 @@ export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
resetState(): void { resetState(): void {
this.imageFile = null; this.imageFile = null;
this.imageText = '';
this.originalImageSrc = null;
this.detectedText = '';
this.processingStatus = ''; this.processingStatus = '';
this.loading = false; this.detectedText = '';
this.boxes = []; this.boxes = [];
this.originalImageWidth = 0; this.originalImageSrc = null;
this.originalImageHeight = 0; this.canvasVisible = false;
this.formVisible = true;
// Clear Fabric canvas if it exists
if (this.canvas) {
this.canvas.clear(); this.canvas.clear();
this.canvas.dispose();
this.canvas = undefined as any;
}
} }
onKeyDown(e: KeyboardEvent): void { onKeyDown(e: KeyboardEvent): void {
@ -107,7 +107,7 @@ export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
const file: File = event.target.files[0]; const file: File = event.target.files[0];
if (!file) return; if (!file) return;
// Status zurücksetzen this.imageFile = file;
this.processingStatus = 'Verarbeitung läuft...'; this.processingStatus = 'Verarbeitung läuft...';
this.detectedText = ''; this.detectedText = '';
this.loading = true; this.loading = true;
@ -121,6 +121,10 @@ export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
const imageBase64 = (this.originalImageSrc as string).split(',')[1]; const imageBase64 = (this.originalImageSrc as string).split(',')[1];
try { try {
// Eingabefelder ausblenden und Canvas anzeigen
this.formVisible = false;
this.canvasVisible = true;
// Anfrage an den Backend-Service senden // Anfrage an den Backend-Service senden
const response = await this.http.post<any>('/api/ocr', { image: imageBase64 }).toPromise(); const response = await this.http.post<any>('/api/ocr', { image: imageBase64 }).toPromise();
@ -136,6 +140,9 @@ export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
console.error('Fehler beim OCR-Service:', error); console.error('Fehler beim OCR-Service:', error);
this.processingStatus = 'Fehler beim OCR-Service'; this.processingStatus = 'Fehler beim OCR-Service';
this.loading = false; this.loading = false;
// Eingabefelder ausblenden und Canvas anzeigen
this.formVisible = true;
this.canvasVisible = false;
} }
}; };
reader.readAsDataURL(file); reader.readAsDataURL(file);
@ -159,7 +166,13 @@ export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
async processImage(ocrResults: any[]): Promise<void> { async processImage(ocrResults: any[]): Promise<void> {
// Canvas zurücksetzen // Canvas zurücksetzen
if (this.canvas) {
this.canvas.clear(); this.canvas.clear();
this.canvas.dispose();
}
this.canvas = new fabric.Canvas(this.canvasElement.nativeElement);
this.boxes = []; this.boxes = [];
// Hintergrundbild setzen // Hintergrundbild setzen
@ -216,7 +229,7 @@ export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
top: top, top: top,
width: width, width: width,
height: height, height: height,
fill: 'rgba(0, 0, 0, 0.5)', fill: 'rgba(0, 0, 0, 0.3)',
selectable: true, selectable: true,
hasControls: true, hasControls: true,
hasBorders: true, hasBorders: true,
@ -252,8 +265,6 @@ export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
this.processingStatus = 'Verarbeitung abgeschlossen'; this.processingStatus = 'Verarbeitung abgeschlossen';
this.loading = false; this.loading = false;
// Eingabefelder und Button ausblenden
this.hideFormElements();
} catch (error) { } catch (error) {
console.error('Fehler beim Setzen des Hintergrundbildes:', error); console.error('Fehler beim Setzen des Hintergrundbildes:', error);
this.processingStatus = 'Fehler bei der Bildverarbeitung'; this.processingStatus = 'Fehler bei der Bildverarbeitung';
@ -299,20 +310,31 @@ export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
this.canvas.requestRenderAll(); this.canvas.requestRenderAll();
} }
hideFormElements(): void { save(): void {
// Implementiere die Logik, um die Eingabefelder und den Button auszublenden // Hier kannst du die Logik zum Speichern der Bilddaten implementieren
// Dies kann durch eine zusätzliche Variable gesteuert werden // Zum Beispiel:
this.formVisible = false; /*
this.canvasVisible = true; const data = {
deckName: this.deckName,
image: this.originalImageSrc,
boxes: this.boxes,
detectedText: this.detectedText
};
this.deckService.saveImageData(data).subscribe({
next: () => {
alert('Bild gespeichert!');
this.imageUploaded.emit();
this.closeModal();
},
error: (err) => {
console.error('Fehler beim Speichern des Bildes:', err);
alert('Fehler beim Speichern des Bildes.');
} }
});
showFormElements(): void { */
this.formVisible = true; // Temporäres Beispiel:
this.canvasVisible = false; alert('Save button clicked');
this.imageUploaded.emit();
this.closeModal();
} }
// Neue Variable zur Steuerung der Sichtbarkeit
formVisible: boolean = true;
canvasVisible: boolean = true;
} }