Bilder Rotieren

This commit is contained in:
Moritz Utcke
2024-03-16 11:01:25 +07:00
parent c3d9913cc7
commit b45206290f
7 changed files with 71 additions and 27 deletions

View File

@@ -1,15 +1,16 @@
import { GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { Enums } from "@ibcornelsen/database/client";
import { addNotification, updateNotification } from "@ibcornelsen/ui";
import { client } from "src/trpc";
export async function bilderHochladen(images: (UploadedGebaeudeBild & { base64?: string })[], gebaeude: GebaeudeClient) {
export async function bilderHochladen(images: (UploadedGebaeudeBild & { base64?: string })[], gebaeude_uid: string) {
if (images.length == 0) {
return images;
}
// Wenn Bilder hochgeladen werden konvertieren wir sie zu base64, das heißt, dass die base64 Eigenschaft bei diesen Bildern
// existiert. Das müssen wir TypeScript nur wissen lassen, damit es uns in Ruhe lässt.
const imagesToUpload = images.filter(image => !image.uid) as unknown as { base64: string, kategorie: string, uid?: string }[];
const imagesToUpload = images.filter(image => !image.uid || image.update) as unknown as { base64: string, kategorie: string, uid?: string, update: boolean }[];
if (imagesToUpload.length == 0) {
return images;
@@ -27,13 +28,21 @@ export async function bilderHochladen(images: (UploadedGebaeudeBild & { base64?:
const image = imagesToUpload[i];
try {
if (image.update) {
await client.v1.bilder.update.mutate({
uid: image.uid as string,
base64: image.base64,
kategorie: image.kategorie as Enums.BilderKategorie
})
} else {
const response = await client.v1.bilder.upload.mutate({
base64: image.base64,
kategorie: image.kategorie,
gebaeude_uid: gebaeude.uid
kategorie: image.kategorie as Enums.BilderKategorie,
gebaeude_uid
})
image.uid = response.uid
}
updateNotification(notification, {
dismissable: true,

View File

@@ -37,7 +37,7 @@ export async function verbrauchsausweisWohnenSpeichern(
},
});
images = await bilderHochladen(images, gebaeude);
images = await bilderHochladen(images, gebaeude.uid);
return { uid: ausweis.uid, gebaeude_uid: gebaeude.uid, gebaeude_aufnahme_uid: gebaeude_aufnahme_allgemein.uid };
} catch (e) {
@@ -57,7 +57,7 @@ export async function verbrauchsausweisWohnenSpeichern(
},
});
images = await bilderHochladen(images, gebaeude);
images = await bilderHochladen(images, response.gebaeude_uid);
return response;
} catch (e: any) {

View File

@@ -270,7 +270,7 @@
</div>
<div class="flex flex-col gap-2">
<div class="column">
<span>Verbrauch</span>
<span>Verbrauch *</span>
<input
name="verbrauch_1"
type="number"
@@ -280,7 +280,7 @@
/>
</div>
<div class="column">
<span>Verbrauch</span>
<span>Verbrauch *</span>
<input
name="verbrauch_2"
type="number"
@@ -290,7 +290,7 @@
/>
</div>
<div class="column">
<span>Verbrauch</span>
<span>Verbrauch *</span>
<input
name="verbrauch_3"
type="number"

View File

@@ -4,7 +4,7 @@ import { inferProcedureInput, inferProcedureOutput } from "@trpc/server";
export type UploadedGebaeudeBild = inferProcedureOutput<
AppRouter["v1"]["verbrauchsausweisWohnen"]["get"]
>["gebaeude_aufnahme_allgemein"]["gebaeude_stammdaten"]["gebaeude_bilder"][0] & { base64?: string };
>["gebaeude_aufnahme_allgemein"]["gebaeude_stammdaten"]["gebaeude_bilder"][0] & { base64?: string, update?: boolean };
/**

View File

@@ -2,6 +2,7 @@
import UploadImages from "./UploadImages.svelte";
import type { BedarfsausweisWohnen, Enums, VerbrauchsausweisGewerbe } from "@ibcornelsen/database/client";
import { GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "./Ausweis/types";
import { RotateCounterClockwise, Trash } from "radix-svelte-icons";
export let images: UploadedGebaeudeBild[] = [];
export let max: number = 4;
@@ -10,8 +11,24 @@
export let gebaeude: GebaeudeClient;
export let kategorie: Enums.BilderKategorie
console.log(images);
async function rotateImage(image: UploadedGebaeudeBild): Promise<UploadedGebaeudeBild> {
return new Promise((resolve, reject) => {
let img = new Image();
img.src = image.base64 ? image.base64 : `/bilder/${image.uid}.webp`;
img.onload = () => {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = img.height;
canvas.height = img.width;
ctx?.translate(img.height / 2, img.width / 2);
ctx?.rotate((-90 * Math.PI) / 180);
ctx?.drawImage(img, -img.width / 2, -img.height / 2);
image.base64 = canvas.toDataURL("image/webp");
image.update = true;
resolve(image)
};
})
}
</script>
<div class="flex flex-col gap-4">
@@ -23,18 +40,31 @@
<img
src={image.base64 ? image.base64 : `/bilder/${image.uid}.webp`}
alt={kategorie}
class="h-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all"
class="h-full max-h-96 w-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all"
/>
<div class="invisible group-hover:visible absolute left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] flex flex-row gap-2">
<button
type="button"
class="invisible group-hover:visible absolute left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] rounded-full w-[30px] h-[30px] p-2 bg-[rgba(0,0,0,0.4)]"
class="rounded-full w-[30px] h-[30px] flex items-center justify-center p-0 bg-[rgba(0,0,0,0.4)]"
on:click={() => {
delete images[i];
images = images.filter((x) => x);
}}
>
R
<Trash size={20} color="#fff"></Trash>
</button>
<button
type="button"
class="rounded-full w-[30px] h-[30px] flex items-center justify-center p-0 bg-[rgba(0,0,0,0.4)]"
on:click={async () => {
let image = await rotateImage(images[i]);
images[i] = image;
images = images
}}
>
<RotateCounterClockwise size={20} color="#fff"></RotateCounterClockwise>
</button>
</div>
</div>
{/if}
{/each}

View File

@@ -26,6 +26,8 @@
import { VerbrauchsausweisWohnenClient, BenutzerClient, UploadedGebaeudeBild } from "#components/Ausweis/types";
import { verbrauchsausweisWohnenSpeichern } from "src/client/lib/verbrauchsausweisWohnenSpeichern";
// TODO: Vom Server sollte ein volles Objekt kommen, dass alle Subobjekte enthält, weil es sonst zu Problemen führen kann
// wenn gebaeude_aufnahme_allgemein oder gebaeude_stammdaten nicht existiert...
export let ausweis: VerbrauchsausweisWohnenClient;
export let user: BenutzerClient = {} as BenutzerClient;

View File

@@ -1,24 +1,27 @@
---
import AusweisLayout from "#layouts/AusweisLayout.astro";
import VerbrauchsausweisWohnenModule from "#modules/Ausweise/VerbrauchsausweisWohnenModule.svelte";
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { createCaller } from "#lib/caller";
const uid = Astro.url.searchParams.get("uid");
let ausweis: VerbrauchsausweisWohnenClient = {} as VerbrauchsausweisWohnenClient;
let ausweis: VerbrauchsausweisWohnenClient = {
gebaeude_aufnahme_allgemein: { gebaeude_stammdaten: {} },
} as VerbrauchsausweisWohnenClient;
const caller = createCaller(Astro);
if (uid) {
ausweis = await caller.v1.verbrauchsausweisWohnen.get({
uid: uid
})
uid: uid,
});
if (!ausweis) {
// Der Ausweis scheint nicht zu existieren.
// Wir leiten auf die generische Ausweisseite ohne UID weiter.
return Astro.redirect("/energieausweis-erstellen/verbrauchsausweis-wohnen");
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-wohnen"
);
}
}
---