diff --git a/package.json b/package.json index 14160c49..949e4b20 100644 --- a/package.json +++ b/package.json @@ -31,21 +31,15 @@ "@trpc/client": "^10.45.2", "@trpc/server": "^10.45.2", "astro": "^4.16.10", - "astro-i18next": "1.0.0-beta.21", "body-scroll-lock": "^4.0.0-beta.0", "buffer": "^6.0.3", "bun": "^1.1.34", - "caniuse-lite": "^1.0.30001684", "csvtojson": "^2.0.10", "express": "^4.21.1", "flag-icons": "^6.15.0", "fontkit": "^2.0.4", - "i18next": "^23.16.5", - "i18next-fs-backend": "^2.3.2", - "i18next-http-backend": "^2.6.2", "js-cookie": "^3.0.5", "js-interpolate": "^1.3.1", - "katex": "^0.16.11", "moment": "^2.30.1", "moment-timezone": "^0.5.46", "pdf-lib": "^1.17.1", diff --git a/public/images/sanierungsfahrplan/farbeEnergieEffizienzEins.svg b/public/images/sanierungsfahrplan/farbeEnergieEffizienzEins.svg new file mode 100644 index 00000000..db6448d2 --- /dev/null +++ b/public/images/sanierungsfahrplan/farbeEnergieEffizienzEins.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/farbeEnergieEffizienzZwei.svg b/public/images/sanierungsfahrplan/farbeEnergieEffizienzZwei.svg new file mode 100644 index 00000000..51a348ea --- /dev/null +++ b/public/images/sanierungsfahrplan/farbeEnergieEffizienzZwei.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/farbenEnergieEffizienzHuelle.svg b/public/images/sanierungsfahrplan/farbenEnergieEffizienzHuelle.svg new file mode 100644 index 00000000..32d0b957 --- /dev/null +++ b/public/images/sanierungsfahrplan/farbenEnergieEffizienzHuelle.svg @@ -0,0 +1,850 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/hausIconBoden.svg b/public/images/sanierungsfahrplan/hausIconBoden.svg new file mode 100644 index 00000000..a84fd013 --- /dev/null +++ b/public/images/sanierungsfahrplan/hausIconBoden.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/hausIconDach.svg b/public/images/sanierungsfahrplan/hausIconDach.svg new file mode 100644 index 00000000..91f2a7b8 --- /dev/null +++ b/public/images/sanierungsfahrplan/hausIconDach.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/hausIconFenster.svg b/public/images/sanierungsfahrplan/hausIconFenster.svg new file mode 100644 index 00000000..517b9b1a --- /dev/null +++ b/public/images/sanierungsfahrplan/hausIconFenster.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/hausIconHaus.svg b/public/images/sanierungsfahrplan/hausIconHaus.svg new file mode 100644 index 00000000..f1490c23 --- /dev/null +++ b/public/images/sanierungsfahrplan/hausIconHaus.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/hausIconHeizung.svg b/public/images/sanierungsfahrplan/hausIconHeizung.svg new file mode 100644 index 00000000..43d95c70 --- /dev/null +++ b/public/images/sanierungsfahrplan/hausIconHeizung.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/hausIconLueftung.svg b/public/images/sanierungsfahrplan/hausIconLueftung.svg new file mode 100644 index 00000000..d4fe66b9 --- /dev/null +++ b/public/images/sanierungsfahrplan/hausIconLueftung.svg @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/hausIconWaende.svg b/public/images/sanierungsfahrplan/hausIconWaende.svg new file mode 100644 index 00000000..ab7c3dd4 --- /dev/null +++ b/public/images/sanierungsfahrplan/hausIconWaende.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/hausIconWarmwasser.svg b/public/images/sanierungsfahrplan/hausIconWarmwasser.svg new file mode 100644 index 00000000..9963d37a --- /dev/null +++ b/public/images/sanierungsfahrplan/hausIconWarmwasser.svg @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/hausIconWarmwasserVerteilung.svg b/public/images/sanierungsfahrplan/hausIconWarmwasserVerteilung.svg new file mode 100644 index 00000000..70c6fa54 --- /dev/null +++ b/public/images/sanierungsfahrplan/hausIconWarmwasserVerteilung.svg @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/skalaEnergieEffizienz.svg b/public/images/sanierungsfahrplan/skalaEnergieEffizienz.svg new file mode 100644 index 00000000..b757436e --- /dev/null +++ b/public/images/sanierungsfahrplan/skalaEnergieEffizienz.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/sanierungsfahrplan/skalaEnergieEffizienzVertikal.svg b/public/images/sanierungsfahrplan/skalaEnergieEffizienzVertikal.svg new file mode 100644 index 00000000..694d2eaa --- /dev/null +++ b/public/images/sanierungsfahrplan/skalaEnergieEffizienzVertikal.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/Katex.svelte b/src/components/Katex.svelte deleted file mode 100644 index 87ebf45e..00000000 --- a/src/components/Katex.svelte +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - -{@html katexString} \ No newline at end of file diff --git a/src/components/Tabellen/A12NutzenergiebedarfHeizung.svelte b/src/components/Tabellen/A12NutzenergiebedarfHeizung.svelte index 5804315f..c2fd3b2d 100644 --- a/src/components/Tabellen/A12NutzenergiebedarfHeizung.svelte +++ b/src/components/Tabellen/A12NutzenergiebedarfHeizung.svelte @@ -1,17 +1,114 @@ @@ -63,15 +160,14 @@ 31 - {interpolatedValues[1]?.month} + {Math.round(bilanzinnentemperaturen.Januar*1000)/1000} 1,0 - - {interpolatedValues[1]?.interpolatedValue} + {Math.round(belastungsgrade.Januar*1000)/1000} - - + {waermequellensenkenverhaeltnisJanuar} + {Math.round(ausnutzungsgradJanuar*1000)/1000} @@ -79,15 +175,15 @@ 28 - + {Math.round(bilanzinnentemperaturen.Februar*1000)/1000} 1,9 - + {Math.round(belastungsgrade.Februar*1000)/1000} - - + {waermequellensenkenverhaeltnisFebruar} + {Math.round(ausnutzungsgradFebruar*1000)/1000} @@ -95,15 +191,15 @@ 31 - + {Math.round(bilanzinnentemperaturen.März*1000)/1000} 4,7 - + {Math.round(belastungsgrade.März*1000)/1000} - - + {waermequellensenkenverhaeltnisMärz} + {Math.round(ausnutzungsgradMärz*1000)/1000} @@ -111,15 +207,15 @@ 30 - + {Math.round(bilanzinnentemperaturen.April*1000)/1000} 9,2 - + {Math.round(belastungsgrade.April*1000)/1000} - - + {waermequellensenkenverhaeltnisApril} + {Math.round(ausnutzungsgradApril*1000)/1000} @@ -127,15 +223,15 @@ 31 - + {Math.round(bilanzinnentemperaturen.Mai*1000)/1000} 14,1 - + {Math.round(belastungsgrade.Mai*1000)/1000} - - + {waermequellensenkenverhaeltnisMai} + {Math.round(ausnutzungsgradMai*1000)/1000} @@ -143,15 +239,15 @@ 30 - + {Math.round(bilanzinnentemperaturen.Juni*1000)/1000} 16,7 - + {Math.round(belastungsgrade.Juni*1000)/1000} - - + {waermequellensenkenverhaeltnisJuni} + {Math.round(ausnutzungsgradJuni*1000)/1000} @@ -159,15 +255,15 @@ 31 - + {Math.round(bilanzinnentemperaturen.Juli*1000)/1000} 19,0 - + {Math.round(belastungsgrade.Juli*1000)/1000} - - + {waermequellensenkenverhaeltnisJuli} + {Math.round(ausnutzungsgradJuli*1000)/1000} @@ -175,15 +271,15 @@ 31 - + {Math.round(bilanzinnentemperaturen.August*1000)/1000} 18,6 - + {Math.round(belastungsgrade.August*1000)/1000} - - + {waermequellensenkenverhaeltnisAugust} + {Math.round(ausnutzungsgradAugust*1000)/1000} @@ -191,15 +287,15 @@ 30 - + {Math.round(bilanzinnentemperaturen.September*1000)/1000} 14,3 - + {Math.round(belastungsgrade.September*1000)/1000} - - + {waermequellensenkenverhaeltnisSeptember} + {Math.round(ausnutzungsgradSeptember*1000)/1000} @@ -207,15 +303,15 @@ 31 - + {Math.round(bilanzinnentemperaturen.Oktober*1000)/1000} 9,4 - + {Math.round(belastungsgrade.Oktober*1000)/1000} - - + {waermequellensenkenverhaeltnisOktober} + {Math.round(ausnutzungsgradOktober*1000)/1000} @@ -223,15 +319,15 @@ 30 - + {Math.round(bilanzinnentemperaturen.November*1000)/1000} 4,1 - + {Math.round(belastungsgrade.November*1000)/1000} - - + {waermequellensenkenverhaeltnisNovember} + {Math.round(ausnutzungsgradNovember*1000)/1000} @@ -239,15 +335,15 @@ 31 - + {Math.round(bilanzinnentemperaturen.Dezember*1000)/1000} 0,9 - + {Math.round(belastungsgrade.Dezember*1000)/1000} - - + {waermequellensenkenverhaeltnisDezember} + {Math.round(ausnutzungsgradDezember*1000)/1000} diff --git a/src/components/Tabellen/A9Trinkwassererwaermung.svelte b/src/components/Tabellen/A9Trinkwassererwaermung.svelte index 17a2e90a..baf78967 100644 --- a/src/components/Tabellen/A9Trinkwassererwaermung.svelte +++ b/src/components/Tabellen/A9Trinkwassererwaermung.svelte @@ -4,12 +4,12 @@ export let ausweis: BedarfsausweisWohnenClient; export let gebaeude_aufnahme: GebaeudeAufnahmeClient; - import { berechnungTrinkwarmwasserWaermebedarf } from "#lib/Berechnungen/BedarfsausweisWohnen/BerechnungTrinkwarmwasser.js"; + import { berechnungNutzenergiebedarfTrinkwarmwasser } from "#lib/Berechnungen/BedarfsausweisWohnen/BerechnungNutzenergiebedarfTrinkwarmwasser.js"; let trinkwasserWaermebedarf = 0, flaechenBezogenerWaermebedarf = 0, bezugsflaeche = 0 $: { - const result = berechnungTrinkwarmwasserWaermebedarf(ausweis, gebaeude_aufnahme) + const result = berechnungNutzenergiebedarfTrinkwarmwasser(ausweis, gebaeude_aufnahme) trinkwasserWaermebedarf = result.trinkwasserWaermebedarf flaechenBezogenerWaermebedarf = result.flaechenBezogenerWaermebedarf bezugsflaeche = result.bezugsflaeche diff --git a/src/components/design/content/SanierungsFahrplanBauteilTemplate.svelte b/src/components/design/content/SanierungsFahrplanBauteilTemplate.svelte new file mode 100644 index 00000000..8845fec6 --- /dev/null +++ b/src/components/design/content/SanierungsFahrplanBauteilTemplate.svelte @@ -0,0 +1,103 @@ +
+
+
Farbklasse
+
+
+
+
+
+
+
+
+
+
U-Wert [W/(m²K)] / Beschreibung
+
≤ 0,12 / Sparrendach geneigt und stark hinterlüftet mit 20cm PUR/PIR-Hartschaum Aufsparrendämmung (hocheffiziente Dämmung mit WLG 0,024)
+
≤ 0,14 / Sparrendach geneigt und stark hinterlüftet mit 18cm PUR/PIR-Hartschaum Aufsparrendämmung (hocheffiziente Dämmung mit WLG 0,024)
+
≤ 0,24 / Sparrendach geneigt und hinterlüftet mit 18cm mineralischer Zwischensparren-
dämmung und 5 cm Untersparrendämmung (Standarddämmung mit WLG 0,04)
+
≤ 0,30 / Sparrendach geneigt und hinterlüftet mit 18cm mineralischer Zwischensparren-
dämmung (Standarddämmung mit WLG 0,04)
+
≤ 0,50 / Sparrendach geneigt und hinterlüftet mit 12cm mineralischer Zwischensparren-
dämmung (Standarddämmung mit WLG 0,04)
+
≤ 0,80 / Sparrendach geneigt und hinterlüftet mit 5cm mineralischer Zwischensparren-
dämmung (Standarddämmung mit WLG 0,04)
+
> 0,80 / Sparrendach geneigt und hinterlüftet ungedämmt oder weniger als 5cm Zwischensparrendämmung (Standarddämmung mit WLG 0,04)
+
+
+ + \ No newline at end of file diff --git a/src/components/design/content/SanierungsFahrplanDachTemplate.svelte b/src/components/design/content/SanierungsFahrplanDachTemplate.svelte new file mode 100644 index 00000000..8845fec6 --- /dev/null +++ b/src/components/design/content/SanierungsFahrplanDachTemplate.svelte @@ -0,0 +1,103 @@ +
+
+
Farbklasse
+
+
+
+
+
+
+
+
+
+
U-Wert [W/(m²K)] / Beschreibung
+
≤ 0,12 / Sparrendach geneigt und stark hinterlüftet mit 20cm PUR/PIR-Hartschaum Aufsparrendämmung (hocheffiziente Dämmung mit WLG 0,024)
+
≤ 0,14 / Sparrendach geneigt und stark hinterlüftet mit 18cm PUR/PIR-Hartschaum Aufsparrendämmung (hocheffiziente Dämmung mit WLG 0,024)
+
≤ 0,24 / Sparrendach geneigt und hinterlüftet mit 18cm mineralischer Zwischensparren-
dämmung und 5 cm Untersparrendämmung (Standarddämmung mit WLG 0,04)
+
≤ 0,30 / Sparrendach geneigt und hinterlüftet mit 18cm mineralischer Zwischensparren-
dämmung (Standarddämmung mit WLG 0,04)
+
≤ 0,50 / Sparrendach geneigt und hinterlüftet mit 12cm mineralischer Zwischensparren-
dämmung (Standarddämmung mit WLG 0,04)
+
≤ 0,80 / Sparrendach geneigt und hinterlüftet mit 5cm mineralischer Zwischensparren-
dämmung (Standarddämmung mit WLG 0,04)
+
> 0,80 / Sparrendach geneigt und hinterlüftet ungedämmt oder weniger als 5cm Zwischensparrendämmung (Standarddämmung mit WLG 0,04)
+
+
+ + \ No newline at end of file diff --git a/src/components/design/content/SanierungsFahrplanHeizungTemplate.svelte b/src/components/design/content/SanierungsFahrplanHeizungTemplate.svelte new file mode 100644 index 00000000..cae915c5 --- /dev/null +++ b/src/components/design/content/SanierungsFahrplanHeizungTemplate.svelte @@ -0,0 +1,123 @@ +
+
+
Farbklasse
+
+
+
+
+
+
+
+
+
+
+
+
Effizienzzahl / Beschreibung
+
< 0,4 / Hohe Effizienz / überwiegend erneuerbare Energieträger
+
< 0,7 / Hohe Effizienz / erneuerbare und fossile Energieträger
+
< 1,0 / Moderne Wärmeerzeuger mit fossilen Energieträgern und zusätzlich erneuerbaren Energien
+
< 1,1 / Moderne Wärmeerzeuger mit fossilen Energieträgern
+
< 1,2 / Wärmeerzeuger mit fossilen Energieträgern
+
< 1,3 / Mindestanforderung an neue Heizkessel
+
< 1,5 / Nicht mehr zeitgemäße Technik
+
< 1,6 / Ineffiziente Wärmeerzeuger
+
> 1,6 / Ineffiziente Wärmeerzeuger mit sehr hohen Verlusten
+
+
+ + \ No newline at end of file diff --git a/src/components/design/content/SanierungsFahrplanIstTemplate.svelte b/src/components/design/content/SanierungsFahrplanIstTemplate.svelte new file mode 100644 index 00000000..e32f9630 --- /dev/null +++ b/src/components/design/content/SanierungsFahrplanIstTemplate.svelte @@ -0,0 +1,151 @@ + + +
+ Skala Energieeffizienz +
+ +
+ +
+ +
*inklusive Kellerwänden
+
+ +
+ +
oberer Gebäudeabschluss
+
+ +
+ Hausiconlüftung +
+
+ +
+ Hausiconfenster +
inklusive Dachfenster
+
+ +
+ Hausicon +
+
+ +
+ Hausiconwarmwasser +
+
+ +
+ Hausiconboden +
unterer Gebäudeabschluss
+
+ +
+ +
+
+ +
+ Hausiconwarmwasserverteilung +
inkl. Speicherung und Übergabe
+
+
+
+
+ + {#if showPopup} + +{/if} + + \ No newline at end of file diff --git a/src/components/design/content/SanierungsFahrplanWandTemplate.svelte b/src/components/design/content/SanierungsFahrplanWandTemplate.svelte new file mode 100644 index 00000000..a1f0dabd --- /dev/null +++ b/src/components/design/content/SanierungsFahrplanWandTemplate.svelte @@ -0,0 +1,103 @@ +
+
+
Farbklasse
+
+
+
+
+
+
+
+
+
+
U-Wert [W/(m²K)] / Beschreibung
+
≤ 0,15 / Gasbeton-Blockstein 30 cm mit 16 cm PUR/PIR-Hartschaum (hocheffiziente Dämmung mit WLG 0,028)
+
≤ 0,20 / Gasbeton-Blockstein 30 cm mit 14 cm mineralischer Außendämung (WLG 0,035)
+
≤ 0,24 / Gasbeton-Blockstein 30 cm mit 12 cm mineralischer Außendämung (WLG 0,04)
+
≤ 0,35 / Gasbeton-Blockstein 30 cm mit 10 cm mineralischer Außendämung (WLG 0,04)
+
≤ 0,50 / Gasbeton-Blockstein 30 cm mit 5 cm mineralischer Innendämung (WLG 0,04)
+
≤ 0,80 / Gasbeton-Blockstein 30 cm, Dämmputz
+
> 0,80 / Gasbeton-Blockstein 30 cm
+
+
+ + \ No newline at end of file diff --git a/src/components/design/sidebars/cards/cardNavigation.svelte b/src/components/design/sidebars/cards/cardNavigation.svelte index 0e92363d..99986e58 100644 --- a/src/components/design/sidebars/cards/cardNavigation.svelte +++ b/src/components/design/sidebars/cards/cardNavigation.svelte @@ -136,7 +136,7 @@ if(innerWidth>1024){ diff --git a/src/components/widgets/WelcherAusweisWidget.svelte b/src/components/widgets/WelcherAusweisWidget.svelte index 49d4d235..7d3d6fcc 100644 --- a/src/components/widgets/WelcherAusweisWidget.svelte +++ b/src/components/widgets/WelcherAusweisWidget.svelte @@ -39,9 +39,13 @@ allowedReason.includes(anlass) && allowedTypes.includes(gebaeudetyp) && (leerStand === "bis 30") && (heizungsAlter === ">= 3"); } + } + + +
diff --git a/src/layouts/BlankLayout.astro b/src/layouts/BlankLayout.astro index 915f208b..b38aa5a1 100644 --- a/src/layouts/BlankLayout.astro +++ b/src/layouts/BlankLayout.astro @@ -1,5 +1,4 @@ --- -import i18next from "i18next"; import { NotificationWrapper } from "@ibcornelsen/ui"; @@ -36,7 +35,7 @@ const schema = JSON.stringify({ --- - + diff --git a/src/layouts/MinimalLayout.astro b/src/layouts/MinimalLayout.astro index 5e6d63c8..1b85563a 100644 --- a/src/layouts/MinimalLayout.astro +++ b/src/layouts/MinimalLayout.astro @@ -1,5 +1,4 @@ --- -import i18next from "i18next"; import "#style/global.css"; import "../../svelte-dialogs.config" @@ -42,7 +41,7 @@ const lightTheme = Astro.cookies.get("theme")?.value === "light"; --- - + diff --git a/src/layouts/UserLayout.astro b/src/layouts/UserLayout.astro index 70bd4ff8..f030e361 100644 --- a/src/layouts/UserLayout.astro +++ b/src/layouts/UserLayout.astro @@ -1,5 +1,4 @@ --- -import i18next from "i18next"; import "#style/global.css"; import "../../svelte-dialogs.config" @@ -54,7 +53,7 @@ let lightTheme = Astro.cookies.get("theme")?.value === "light"; --- - + diff --git a/src/lib/Berechnungen/BedarfsausweisWohnen/BerechnungNutzenergiebedarfTrinkwarmwasser.ts b/src/lib/Berechnungen/BedarfsausweisWohnen/BerechnungNutzenergiebedarfTrinkwarmwasser.ts index 340e458b..76058d9f 100644 --- a/src/lib/Berechnungen/BedarfsausweisWohnen/BerechnungNutzenergiebedarfTrinkwarmwasser.ts +++ b/src/lib/Berechnungen/BedarfsausweisWohnen/BerechnungNutzenergiebedarfTrinkwarmwasser.ts @@ -10,7 +10,7 @@ import { linearInterpolation } from "js-interpolate" * @param {BedarfsausweisWohnenClient} ausweis * @param {GebaeudeAufnahmeClient} gebaeude_aufnahme */ -export function berechnungNutzenergiebedarfTrinkwasser(ausweis: BedarfsausweisWohnenClient, gebaeude_aufnahme: GebaeudeAufnahmeClient) { +export function berechnungNutzenergiebedarfTrinkwarmwasser(ausweis: BedarfsausweisWohnenClient, gebaeude_aufnahme: GebaeudeAufnahmeClient) { // A_NGF const bezugsflaeche = gebaeude_aufnahme.nutzflaeche ?? 0; diff --git a/src/lib/Berechnungen/BedarfsausweisWohnen/BerechnungWaermequellenAusAnlagentechnikTrinkwasser.ts b/src/lib/Berechnungen/BedarfsausweisWohnen/BerechnungWaermequellenAusAnlagentechnikTrinkwasser.ts index 93526aee..b039a123 100644 --- a/src/lib/Berechnungen/BedarfsausweisWohnen/BerechnungWaermequellenAusAnlagentechnikTrinkwasser.ts +++ b/src/lib/Berechnungen/BedarfsausweisWohnen/BerechnungWaermequellenAusAnlagentechnikTrinkwasser.ts @@ -1,5 +1,19 @@ -import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js"; +import { BedarfsausweisWohnenClient, GebaeudeAufnahmeClient } from "#components/Ausweis/types.js"; +import { berechnungNutzenergiebedarfTrinkwasser } from "./BerechnungNutzenergiebedarfTrinkwarmwasser.js"; +import { FixedLengthArray } from "./types.js"; -export function berechnungWaermequellenAusAnlagentechnikTrinkwasser(ausweis: VerbrauchsausweisWohnenClient) { - +export function berechnungWaermequellenAusAnlagentechnikTrinkwasser(ausweis: BedarfsausweisWohnenClient, gebaeude_aufnahme: GebaeudeAufnahmeClient) { + const trinkwasserWaermebedarf = berechnungNutzenergiebedarfTrinkwasser(ausweis, gebaeude_aufnahme); + + const result = new Array(12).fill(0) as unknown as FixedLengthArray + + for (let i = 0; i < 12; i++) { + const tageImMonat = new Date(0, i, 0).getDate(); + + const monatlicheTrinkwasserWaermebedarf = trinkwasserWaermebedarf.trinkwasserWaermebedarf / 365 * tageImMonat; + + + } + + return result; } \ No newline at end of file diff --git a/src/lib/Berechnungen/BedarfsausweisWohnen/funktionAusnutzungsgrad.ts b/src/lib/Berechnungen/BedarfsausweisWohnen/funktionAusnutzungsgrad.ts new file mode 100644 index 00000000..a4cc3b7e --- /dev/null +++ b/src/lib/Berechnungen/BedarfsausweisWohnen/funktionAusnutzungsgrad.ts @@ -0,0 +1,84 @@ +// Funktion zur Berechnung des Ausnutzungsgrades aus Tabelle 18 + +import { nevillePolynomialInterpolation } from "js-interpolate"; + +let waermequellensenkenverhaeltnis = 3.4; // Beispielwert - muss noch errechnet werden + +const dataset = { + alleMonate: { + 30: [ 0.999,0.992,0.978,0.956,0.927,0.893,0.856,0.818,0.78,0.742,0.706,0.671,0.638,0.608,0.579,0.553,0.528,0.505 + ,0.483,0.463,0.445,0.428,0.411,0.396,0.382,0.369,0.357,0.345,0.334,0.324,0.314,0.305,0.296,0.288,0.28,0.273,0.266, + 0.259,0.253,0.246,0.22,0.198,0.181,0.166,0.153,0.142,0.133,0.125,0.117,0.111,0.105,0.1], + 40: [ 1.0,0.997,0.99,0.975,0.954,0.926,0.892,0.855,0.817,0.778,0.739,0.702,0.667,0.634,0.603,0.574,0.547,0.522 + ,0.498,0.477,0.457,0.438,0.421,0.405,0.39,0.376,0.363,0.351,0.339,0.329,0.318,0.309,0.3,0.291,0.283,0.276,0.268, + 0.261,0.255,0.249,0.221,0.199,0.181,0.166,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 50: [ 1.0,0.999,0.995,0.986,0.97,0.948,0.918,0.883,0.845,0.805,0.765,0.726,0.688,0.652,0.619,0.588,0.559,0.533 + ,0.508,0.485,0.464,0.445,0.427,0.41,0.394,0.38,0.366,0.354,0.342,0.331,0.321,0.311,0.301,0.293,0.285,0.277,0.269, + 0.262,0.256,0.249,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 60: [ 1.0,1.0,0.998,0.992,0.981,0.963,0.937,0.904,0.867,0.826,0.785,0.743,0.704,0.666,0.631,0.598,0.568,0.54 + ,0.514,0.491,0.469,0.449,0.43,0.413,0.397,0.382,0.368,0.355,0.343,0.332,0.322,0.312,0.302,0.293,0.285,0.277,0.27, + 0.263,0.256,0.25,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 70: [ 1.0,1.0,0.999,0.996,0.988,0.973,0.951,0.921,0.884,0.843,0.8,0.757,0.716,0.676,0.639,0.605,0.574,0.545 + ,0.518,0.494,0.472,0.451,0.432,0.414,0.398,0.383,0.369,0.356,0.344,0.333,0.322,0.312,0.303,0.294,0.286,0.278,0.27, + 0.263,0.256,0.25,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 80: [1.0,1.0,0.999,0.998,0.992,0.981,0.962,0.934,0.898,0.857,0.813,0.769,0.725,0.684,0.646,0.61,0.578,0.548 + ,0.521,0.496,0.473,0.452,0.433,0.415,0.399,0.384,0.37,0.357,0.344,0.333,0.322,0.312,0.303,0.294,0.286,0.278,0.27, + 0.263,0.256,0.25,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 90: [ 1.0,1.0,1.0,0.999,0.995,0.986,0.97,0.944,0.91,0.869,0.824,0.778,0.733,0.69,0.651,0.614,0.581,0.55 + ,0.523,0.497,0.474,0.453,0.434,0.416,0.4,0.384,0.37,0.357,0.345,0.333,0.322,0.312,0.303,0.294,0.286,0.278,0.27, + 0.263,0.256,0.25,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 100: [ 1.0,1.0,1.0,0.999,0.997,0.99,0.976,0.953,0.92,0.879,0.833,0.786,0.739,0.695,0.654,0.617,0.583,0.552 + ,0.524,0.498,0.475,0.454,0.434,0.416,0.4,0.384,0.37,0.357,0.345,0.333,0.323,0.312,0.303,0.294,0.286,0.278,0.27, + 0.263,0.256,0.25,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 110: [ 1.0,1.0,1.0,0.999,0.998,0.993,0.981,0.96,0.928,0.887,0.841,0.792,0.744,0.699,0.657,0.619,0.584,0.553 + ,0.525,0.499,0.475,0.454,0.435,0.417,0.4,0.384,0.37,0.357,0.345,0.333,0.323,0.312,0.303,0.294,0.286,0.278,0.27, + 0.263,0.256,0.25,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 120: [ 1.0,1.0,1.0,1.0,0.999,0.995,0.985,0.966,0.935,0.895,0.847,0.798,0.748,0.702,0.659,0.621,0.586,0.554 + ,0.525,0.5,0.476,0.454,0.435,0.417,0.4,0.385,0.37,0.357,0.345,0.333,0.323,0.312,0.303,0.294,0.286,0.278,0.27, + 0.263,0.256,0.25,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 130: [ 1.0,1.0,1.0,1.0,0.999,0.996,0.988,0.971,0.942,0.901,0.853,0.802,0.752,0.704,0.661,0.622,0.587,0.554 + ,0.526,0.5,0.476,0.454,0.435,0.417,0.4,0.385,0.37,0.357,0.345,0.333,0.323,0.312,0.303,0.294,0.286,0.278,0.27, + 0.263,0.256,0.25,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 140: [ 1.0,1.0,1.0,1.0,0.999,0.997,0.991,0.975,0.947,0.907,0.858,0.806,0.755,0.706,0.662,0.623,0.587,0.555 + ,0.526,0.5,0.476,0.454,0.435,0.417,0.4,0.385,0.37,0.357,0.345,0.333,0.323,0.312,0.303,0.294,0.286,0.278,0.27, + 0.263,0.256,0.25,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + 150: [ 1.0,1.0,1.0,1.0,0.999,0.998,0.992,0.979,0.952,0.912,0.863,0.809,0.757,0.708,0.663,0.623,0.588,0.555 + ,0.526,0.5,0.476,0.454,0.435,0.417,0.4,0.385,0.37,0.357,0.345,0.333,0.323,0.312,0.303,0.294,0.286,0.278,0.27, + 0.263,0.256,0.25,0.222,0.2,0.182,0.167,0.154,0.143,0.133,0.125,0.118,0.111,0.105,0.1], + + }, +} + +const waermeQuellenSenkenVerhaeltnis = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8, + 1.9,2,2.1,2.2,2.3,2.4,2.5,2.6,2.7,2.8,2.9,3,3.1,3.2,3.3,3.4,3.5,3.6,3.7,3.8,3.9,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10]; + +export function funktionAusnutzungsgrad(waermequellensenkenverhaeltnis: number, zeitkonstane: number, monat: keyof typeof dataset) { + const data = dataset[monat] + + const interpolations: number[] = [] + + for (const key in data) { + const values = data[key as unknown as keyof typeof data] + + const interpolate = nevillePolynomialInterpolation( + values.map((value, i) => ({ x: waermeQuellenSenkenVerhaeltnis[i], y: value })), + values.length + ) + + interpolations.push(interpolate(waermequellensenkenverhaeltnis)) + } + + const interpolate = nevillePolynomialInterpolation( + interpolations.map((interpolation, i) => { + return { + x: Object.keys(data)[i], + y: interpolation + } + }), + interpolations.length + ) + + return interpolate(zeitkonstane) +} + +console.log(funktionAusnutzungsgrad(waermequellensenkenverhaeltnis, 30, "alleMonate")) diff --git a/src/lib/Berechnungen/BedarfsausweisWohnen/funktionBilanzInnentemperatur.ts b/src/lib/Berechnungen/BedarfsausweisWohnen/funktionBilanzInnentemperatur.ts new file mode 100644 index 00000000..08ebfb37 --- /dev/null +++ b/src/lib/Berechnungen/BedarfsausweisWohnen/funktionBilanzInnentemperatur.ts @@ -0,0 +1,180 @@ +// Funktion zur Berechnung der Bilanzinnentemperatur aus Tabelle 8 EFH oder Tabelle 10 MFH + +import { nevillePolynomialInterpolation } from "js-interpolate"; +import { any } from "node_modules/cypress/types/bluebird/index.js"; + +let wohneinheiten = 3; + +const datasetEinfamilienHaus = { + Januar: { + 50: [18.83, 18.71, 18.61, 18.38, 18.16, 18.05, 17.99, 17.97, 17.95], + 90: [18.99, 18.87, 18.77, 18.54, 18.31, 18.20, 18.15, 18.12, 18.11], + 130: [19.14, 19.02, 18.92, 18.68, 18.45, 18.34, 18.29, 18.26, 18.25], + }, + Februar: { + 50: [18.88, 18.76, 18.67, 18.44, 18.23, 18.13, 18.08, 18.05, 18.04], + 90: [19.04, 18.93, 18.83, 18.60, 18.39, 18.29, 18.23, 18.21, 18.20], + 130: [19.18, 19.07, 18.97, 18.74, 18.53, 18.42, 18.37, 18.34, 18.33], + }, + März: { + 50: [19.05, 18.95, 18.87, 18.68, 18.50, 18.42, 18.37, 18.35, 18.34], + 90: [19.19, 19.09, 19.01, 18.82, 18.64, 18.55, 18.51, 18.49, 18.48], + 130: [19.31, 19.21, 19.13, 18.94, 18.75, 18.67, 18.62, 18.60, 18.59], + }, + April: { + 50: [19.33, 19.26, 19.20, 19.07, 18.94, 18.88, 18.85, 18.84, 18.83], + 90: [19.43, 19.36, 19.30, 19.17, 19.04, 18.98, 18.95, 18.93, 18.92], + 130: [19.51, 19.44, 19.38, 19.25, 19.12, 19.06, 19.03, 19.01, 19.00], + }, + Mai: { + 50: [19.63, 19.60, 19.56, 19.49, 19.42, 19.39, 19.37, 19.36, 19.36], + 90: [19.69, 19.65, 19.62, 19.55, 19.48, 19.44, 19.42, 19.42, 19.41], + 130: [19.73, 19.70, 19.66, 19.59, 19.52, 19.49, 19.47, 19.46, 19.46], + }, + Juni: { + 50: [19.80, 19.77, 19.76, 19.72, 19.68, 19.66, 19.65, 19.64, 19.64], + 90: [19.83, 19.80, 19.79, 19.75, 19.71, 19.69, 19.68, 19.67, 19.67], + 130: [19.85, 19.83, 19.81, 19.77, 19.73, 19.71, 19.70, 19.70, 19.70], + }, + Juli: { + 50: [19.94, 19.93, 19.93, 19.91, 19.90, 19.90, 19.89, 19.89, 19.89], + 90: [19.95, 19.94, 19.94, 19.92, 19.91, 19.91, 19.90, 19.90, 19.90], + 130: [19.95, 19.95, 19.94, 19.93, 19.92, 19.91, 19.91, 19.91, 19.91], + }, + August: { + 50: [19.91, 19.90, 19.90, 19.88, 19.86, 19.86, 19.85, 19.85, 19.85], + 90: [19.93, 19.92, 19.91, 19.89, 19.88, 19.87, 19.86, 19.86, 19.86], + 130: [19.94, 19.93, 19.92, 19.90, 19.89, 19.88, 19.87, 19.87, 19.87], + }, + September: { + 50: [19.65, 19.61, 19.58, 19.51, 19.44, 19.41, 19.39, 19.39, 19.38], + 90: [19.70, 19.66, 19.63, 19.56, 19.49, 19.46, 19.44, 19.44, 19.43], + 130: [19.74, 19.71, 19.68, 19.60, 19.54, 19.50, 19.49, 19.48, 19.47], + }, + Oktober: { + 50: [19.35, 19.28, 19.23, 19.10, 18.97, 18.91, 18.88, 18.87, 18.86], + 90: [19.44, 19.38, 19.32, 19.19, 19.07, 19.01, 18.98, 18.96, 18.95], + 130: [19.53, 19.46, 19.40, 19.27, 19.15, 19.08, 19.05, 19.04, 19.03], + }, + November: { + 50: [19.01, 18.91, 18.83, 18.63, 18.45, 18.35, 18.31, 18.29, 18.28], + 90: [19.16, 19.06, 18.97, 18.77, 18.59, 18.49, 18.45, 18.43, 18.42], + 130: [19.28, 19.18, 19.09, 18.90, 18.71, 18.61, 18.57, 18.55, 18.53], + }, + Dezember: { + 50: [18.83, 18.71, 18.61, 18.38, 18.15, 18.04, 17.99, 17.96, 17.95], + 90: [18.99, 18.87, 18.76, 18.53, 18.30, 18.19, 18.14, 18.11, 18.10], + 130: [19.14, 19.02, 18.91, 18.67, 18.45, 18.33, 18.28, 18.25, 18.24], + }, + }; + + const datasetMehrfamilienHaus = { + Januar: { + 50: [19.41, 19.37, 19.33, 19.24, 19.16, 19.12, 19.10, 19.09, 19.08], + 90: [19.50, 19.45, 19.41, 19.33, 19.24, 19.20, 19.18, 19.17, 19.17], + 130: [19.57, 19.53, 19.49, 19.40, 19.32, 19.28, 19.26, 19.25, 19.24], + }, + Februar: { + 50: [19.44, 19.40, 19.36, 19.28, 19.20, 19.16, 19.14, 19.13, 19.13], + 90: [19.52, 19.48, 19.44, 19.36, 19.28, 19.24, 19.22, 19.21, 19.21], + 130: [19.59, 19.55, 19.51, 19.43, 19.35, 19.31, 19.29, 19.28, 19.28], + }, + März: { + 50: [19.53, 19.49, 19.46, 19.39, 19.32, 19.29, 19.27, 19.27, 19.26], + 90: [19.60, 19.56, 19.53, 19.46, 19.39, 19.36, 19.34, 19.33, 19.33], + 130: [19.66, 19.62, 19.59, 19.52, 19.45, 19.42, 19.40, 19.39, 19.39], + }, + April: { + 50: [19.66, 19.64, 19.62, 19.57, 19.52, 19.50, 19.49, 19.48, 19.48], + 90: [19.71, 19.69, 19.67, 19.62, 19.57, 19.55, 19.54, 19.53, 19.53], + 130: [19.76, 19.73, 19.71, 19.66, 19.61, 19.59, 19.58, 19.57, 19.57], + }, + Mai: { + 50: [19.82, 19.80, 19.79, 19.76, 19.74, 19.73, 19.72, 19.72, 19.72], + 90: [19.84, 19.83, 19.82, 19.79, 19.77, 19.75, 19.75, 19.74, 19.74], + 130: [19.87, 19.85, 19.84, 19.81, 19.79, 19.78, 19.77, 19.77, 19.76], + }, + Juni: { + 50: [19.90, 19.89, 19.88, 19.87, 19.85, 19.85, 19.84, 19.84, 19.84], + 90: [19.91, 19.91, 19.90, 19.88, 19.87, 19.86, 19.86, 19.86, 19.86], + 130: [19.93, 19.92, 19.91, 19.90, 19.88, 19.87, 19.87, 19.87, 19.87], + }, + Juli: { + 50: [19.97, 19.97, 19.96, 19.96, 19.96, 19.95, 19.95, 19.95, 19.95], + 90: [19.97, 19.97, 19.97, 19.96, 19.96, 19.96, 19.96, 19.96, 19.96], + 130: [19.98, 19.98, 19.97, 19.97, 19.96, 19.96, 19.96, 19.96, 19.96], + }, + August: { + 50: [19.96, 19.95, 19.95, 19.94, 19.94, 19.93, 19.93, 19.93, 19.93], + 90: [19.96, 19.96, 19.96, 19.95, 19.94, 19.94, 19.94, 19.94, 19.94], + 130: [19.97, 19.97, 19.96, 19.96, 19.95, 19.95, 19.95, 19.94, 19.94], + }, + September: { + 50: [19.82, 19.81, 19.80, 19.77, 19.75, 19.74, 19.73, 19.73, 19.73], + 90: [19.85, 19.84, 19.82, 19.80, 19.77, 19.76, 19.76, 19.75, 19.75], + 130: [19.87, 19.86, 19.85, 19.82, 19.80, 19.78, 19.78, 19.77, 19.77], + }, + Oktober: { + 50: [19.67, 19.65, 19.63, 19.58, 19.53, 19.51, 19.50, 19.50, 19.49], + 90: [19.72, 19.70, 19.68, 19.63, 19.58, 19.56, 19.55, 19.54, 19.54], + 130: [19.76, 19.74, 19.72, 19.67, 19.62, 19.60, 19.59, 19.58, 19.58], + }, + November: { + 50: [19.51, 19.47, 19.44, 19.36, 19.30, 19.26, 19.25, 19.24, 19.23], + 90: [19.58, 19.54, 19.51, 19.44, 19.37, 19.33, 19.32, 19.31, 19.30], + 130: [19.64, 19.60, 19.57, 19.50, 19.43, 19.39, 19.38, 19.37, 19.37], + }, + Dezember: { + 50: [19.41, 19.36, 19.32, 19.24, 19.15, 19.11, 19.09, 19.08, 19.08], + 90: [19.49, 19.45, 19.41, 19.32, 19.24, 19.20, 19.18, 19.17, 19.16], + 130: [19.57, 19.52, 19.49, 19.40, 19.31, 19.27, 19.25, 19.24, 19.24], + }, + }; + + function getDataset(wohneinheiten: number) { + if (wohneinheiten < 3) { + return datasetEinfamilienHaus; + } else { + return datasetMehrfamilienHaus; + } + } + + const dataset = getDataset(wohneinheiten); + +// Für "Ohne Teilbeheizung" habe ich hier einfach 0 eingesetzt: +const HeizLast = [0, 5, 10, 25, 50, 75, 100, 125, 150]; + +// Um über die beiden Tabellen zu interpolieren können wir einfach zuerst über +// jede einzeln interpolieren und dann zwischen den Tabellen interpolieren. +// Falls wir also den Wert an Stelle Heizlast: 120, Zeitkonstante 100, Monat: +// Januar haben wollen: +export function funktionBilanzInnentemperatur(heizlast: number, zeitkonstane: number, monat: keyof typeof dataset) { + const data = dataset[monat] + + const interpolations: number[] = [] + + for (const key in data) { + const values = data[key as unknown as keyof typeof data] + + const interpolate = nevillePolynomialInterpolation( + values.map((value, i) => ({ x: HeizLast[i], y: value })), + values.length + ) + + interpolations.push(interpolate(heizlast)) + } + + const interpolate = nevillePolynomialInterpolation( + interpolations.map((interpolation, i) => { + return { + x: Object.keys(data)[i], + y: interpolation + } + }), + interpolations.length + ) + + return interpolate(zeitkonstane) +} + +console.log(funktionBilanzInnentemperatur(120, 100, "Januar")) \ No newline at end of file diff --git a/src/lib/Berechnungen/BedarfsausweisWohnen/funktionMonatlicherBelastungsgrad.ts b/src/lib/Berechnungen/BedarfsausweisWohnen/funktionMonatlicherBelastungsgrad.ts index 8e4e2d58..6bc59388 100644 --- a/src/lib/Berechnungen/BedarfsausweisWohnen/funktionMonatlicherBelastungsgrad.ts +++ b/src/lib/Berechnungen/BedarfsausweisWohnen/funktionMonatlicherBelastungsgrad.ts @@ -1,9 +1,10 @@ -// Funktion zur Berechnung des monatlichen Belastungsgrades aus Tabelle 9 EFH (Januar, Zeitkonstante 90) +// Funktion zur Berechnung des monatlichen Belastungsgrades aus Tabelle 9 EFH und Tabelle 11 MFH import { nevillePolynomialInterpolation } from "js-interpolate"; -// Funktion zur Berechnung des monatlichen Belastungsgrades aus Tabelle 9 EFH (Zeitkonstante 90,130) -const dataset = { +let wohneinheiten = 3; + +const datasetEinfamilienHausMittlereBelastung = { Januar: { 50: [ 0.557, 0.554, 0.55, 0.543, 0.536, 0.533, 0.531, 0.53, 0.53 ], 90: [ 0.562, 0.559, 0.555, 0.548, 0.541, 0.538, 0.536, 0.535, 0.535 ], @@ -66,6 +67,79 @@ const dataset = { }, } +const datasetMehrfamilienHausMittlereBelastung = { + Januar: { + 50: [0.575, 0.574, 0.573, 0.570, 0.567, 0.566, 0.566, 0.565, 0.565], + 90: [0.578, 0.577, 0.575, 0.573, 0.570, 0.569, 0.568, 0.568, 0.568], + 130: [0.580, 0.579, 0.578, 0.575, 0.572, 0.571, 0.571, 0.570, 0.570], + }, + Februar: { + 50: [0.548, 0.547, 0.546, 0.543, 0.541, 0.539, 0.539, 0.538, 0.538], + 90: [0.551, 0.549, 0.548, 0.546, 0.543, 0.542, 0.541, 0.541, 0.541], + 130: [0.553, 0.552, 0.550, 0.548, 0.545, 0.544, 0.543, 0.543, 0.543], + }, + März: { + 50: [0.463, 0.462, 0.461, 0.459, 0.457, 0.456, 0.455, 0.455, 0.455], + 90: [0.465, 0.464, 0.463, 0.461, 0.459, 0.458, 0.458, 0.457, 0.457], + 130: [0.467, 0.466, 0.465, 0.463, 0.461, 0.460, 0.459, 0.459, 0.459], + }, + April: { + 50: [0.327, 0.326, 0.326, 0.324, 0.323, 0.322, 0.321, 0.321, 0.321], + 90: [0.329, 0.328, 0.327, 0.326, 0.324, 0.323, 0.323, 0.323, 0.323], + 130: [0.330, 0.329, 0.328, 0.327, 0.325, 0.325, 0.324, 0.324, 0.324], + }, + Mai: { + 50: [0.179, 0.178, 0.178, 0.177, 0.176, 0.176, 0.176, 0.176, 0.175], + 90: [0.179, 0.179, 0.179, 0.178, 0.177, 0.177, 0.176, 0.176, 0.176], + 130: [0.180, 0.180, 0.179, 0.179, 0.178, 0.177, 0.177, 0.177, 0.177], + }, + Juni: { + 50: [0.100, 0.100, 0.099, 0.099, 0.099, 0.098, 0.098, 0.098, 0.098], + 90: [0.100, 0.100, 0.100, 0.099, 0.099, 0.099, 0.099, 0.099, 0.099], + 130: [0.101, 0.101, 0.100, 0.100, 0.099, 0.099, 0.099, 0.099, 0.099], + }, + Juli: { + 50: [0.030, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030], + 90: [0.030, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030], + 130: [0.031, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030], + }, + August: { + 50: [0.042, 0.042, 0.042, 0.042, 0.042, 0.042, 0.042, 0.042, 0.042], + 90: [0.043, 0.042, 0.042, 0.042, 0.042, 0.042, 0.042, 0.042, 0.042], + 130: [0.043, 0.043, 0.043, 0.042, 0.042, 0.042, 0.042, 0.042, 0.042], + }, + September: { + 50: [0.173, 0.172, 0.172, 0.171, 0.170, 0.170, 0.170, 0.170, 0.170], + 90: [0.173, 0.173, 0.173, 0.172, 0.171, 0.171, 0.170, 0.170, 0.170], + 130: [0.174, 0.174, 0.173, 0.173, 0.172, 0.171, 0.171, 0.171, 0.171], + }, + Oktober: { + 50: [0.318, 0.317, 0.317, 0.315, 0.314, 0.313, 0.313, 0.312, 0.312], + 90: [0.319, 0.319, 0.318, 0.317, 0.315, 0.314, 0.314, 0.314, 0.314], + 130: [0.321, 0.320, 0.319, 0.318, 0.316, 0.316, 0.315, 0.315, 0.315], + }, + November: { + 50: [0.481, 0.480, 0.479, 0.477, 0.475, 0.474, 0.473, 0.473, 0.473], + 90: [0.484, 0.483, 0.482, 0.479, 0.477, 0.476, 0.476, 0.475, 0.475], + 130: [0.486, 0.485, 0.484, 0.481, 0.479, 0.478, 0.477, 0.477, 0.477], + }, + Dezember: { + 50: [0.578, 0.577, 0.576, 0.573, 0.570, 0.569, 0.569, 0.568, 0.568], + 90: [0.581, 0.580, 0.578, 0.576, 0.573, 0.572, 0.571, 0.571, 0.571], + 130: [0.583, 0.582, 0.581, 0.578, 0.575, 0.574, 0.574, 0.573, 0.573], + }, +}; + +function getDatasetBelastung(wohneinheiten: number) { + if (wohneinheiten < 3) { + return datasetEinfamilienHausMittlereBelastung; + } else { + return datasetMehrfamilienHausMittlereBelastung; + } +} + +const dataset = getDatasetBelastung(wohneinheiten); + // Für "Ohne Teilbeheizung" habe ich hier einfach 0 eingesetzt: const HeizLast = [0, 5, 10, 25, 50, 75, 100, 125, 150]; @@ -73,7 +147,7 @@ const HeizLast = [0, 5, 10, 25, 50, 75, 100, 125, 150]; // jede einzeln interpolieren und dann zwischen den Tabellen interpolieren. // Falls wir also den Wert an Stelle Heizlast: 120, Zeitkonstante 100, Monat: // Januar haben wollen: -function crossInterpolate(heizlast: number, zeitkonstane: number, monat: keyof typeof dataset) { +export function funktionMonatlicherBelastungsgrad(heizlast: number, zeitkonstane: number, monat: keyof typeof dataset) { const data = dataset[monat] const interpolations: number[] = [] @@ -100,6 +174,4 @@ function crossInterpolate(heizlast: number, zeitkonstane: number, monat: keyof t ) return interpolate(zeitkonstane) -} - -console.log(crossInterpolate(120, 100, "Januar")); \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib/helpers/txml.ts b/src/lib/helpers/txml.ts new file mode 100644 index 00000000..d1745fe8 --- /dev/null +++ b/src/lib/helpers/txml.ts @@ -0,0 +1,481 @@ +// ==ClosureCompiler== +// @output_file_name default.js +// @compilation_level SIMPLE_OPTIMIZATIONS +// ==/ClosureCompiler== +// module.exports = { +// parse: parse, +// simplify: simplify, +// simplifyLostLess: simplifyLostLess, +// filter: filter, +// stringify: stringify, +// toContentString: toContentString, +// getElementById: getElementById, +// getElementsByClassName: getElementsByClassName, +// transformStream: transformStream, +// }; + +/** + * @author: Tobias Nickel + * @created: 06.04.2015 + * I needed a small xmlparser chat can be used in a worker. + */ + +interface Node { + tagName: string; + attributes: Record; + children: (Node | string)[]; +} + +interface ParseOptions { + attrName?: string; + attrValue?: string; + parseNode: any; + pos?: number; + noChildNodes?: string[]; + setPos?: boolean; + keepComments?: boolean; + keepWhitespace?: boolean; + simplify?: boolean; + filter?: (a: Node, b: Node) => boolean; +} + +/** + * parseXML / html into a DOM Object. with no validation and some failur tolerance + * @param {string} source your XML to parse + * @param {ParseOptions} [options] all other options: + * @return {(Node | string)[]} + */ +export function parse(source: string, options: ParseOptions = {}): (Node | string)[] { + var pos = options.pos || 0; + var keepComments = !!options.keepComments; + var keepWhitespace = !!options.keepWhitespace + + var openBracket = "<"; + var openBracketCC = "<".charCodeAt(0); + var closeBracket = ">"; + var closeBracketCC = ">".charCodeAt(0); + var minusCC = "-".charCodeAt(0); + var slashCC = "/".charCodeAt(0); + var exclamationCC = '!'.charCodeAt(0); + var singleQuoteCC = "'".charCodeAt(0); + var doubleQuoteCC = '"'.charCodeAt(0); + var openCornerBracketCC = '['.charCodeAt(0); + var closeCornerBracketCC = ']'.charCodeAt(0); + + + /** + * parsing a list of entries + */ + function parseChildren(tagName: string) { + var children = []; + while (source[pos]) { + if (source.charCodeAt(pos) == openBracketCC) { + if (source.charCodeAt(pos + 1) === slashCC) { + var closeStart = pos + 2; + pos = source.indexOf(closeBracket, pos); + + var closeTag = source.substring(closeStart, pos) + if (closeTag.indexOf(tagName) == -1) { + var parsedText = source.substring(0, pos).split('\n'); + throw new Error( + 'Unexpected close tag\nLine: ' + (parsedText.length - 1) + + '\nColumn: ' + (parsedText[parsedText.length - 1].length + 1) + + '\nChar: ' + source[pos] + ); + } + + if (pos + 1) pos += 1 + + return children; + } else if (source.charCodeAt(pos + 1) === exclamationCC) { + if (source.charCodeAt(pos + 2) == minusCC) { + //comment support + const startCommentPos = pos; + while (pos !== -1 && !(source.charCodeAt(pos) === closeBracketCC && source.charCodeAt(pos - 1) == minusCC && source.charCodeAt(pos - 2) == minusCC && pos != -1)) { + pos = source.indexOf(closeBracket, pos + 1); + } + if (pos === -1) { + pos = source.length + } + if (keepComments) { + children.push(source.substring(startCommentPos, pos + 1)); + } + } else if ( + source.charCodeAt(pos + 2) === openCornerBracketCC && + source.charCodeAt(pos + 8) === openCornerBracketCC && + source.substr(pos + 3, 5).toLowerCase() === 'cdata' + ) { + // cdata + var cdataEndIndex = source.indexOf(']]>', pos); + if (cdataEndIndex == -1) { + children.push(source.substr(pos + 9)); + pos = source.length; + } else { + children.push(source.substring(pos + 9, cdataEndIndex)); + pos = cdataEndIndex + 3; + } + continue; + } else { + // doctypesupport + const startDoctype = pos + 1; + pos += 2; + var encapsuled = false; + while ((source.charCodeAt(pos) !== closeBracketCC || encapsuled === true) && source[pos]) { + if (source.charCodeAt(pos) === openCornerBracketCC) { + encapsuled = true; + } else if (encapsuled === true && source.charCodeAt(pos) === closeCornerBracketCC) { + encapsuled = false; + } + pos++; + } + children.push(source.substring(startDoctype, pos)); + } + pos++; + continue; + } + var node = parseNode(); + children.push(node); + if (node.tagName[0] === '?') { + children.push(...node.children); + node.children = []; + } + } else { + var text = parseText(); + if (keepWhitespace) { + if (text.length > 0) { + children.push(text); + } + } else { + var trimmed = text.trim(); + if (trimmed.length > 0) { + children.push(trimmed); + } + } + pos++; + } + } + return children; + } + + /** + * returns the text outside of texts until the first '<' + */ + function parseText() { + var start = pos; + pos = source.indexOf(openBracket, pos) - 1; + if (pos === -2) + pos = source.length; + return source.slice(start, pos + 1); + } + /** + * returns text until the first nonAlphabetic letter + */ + var nameSpacer = '\r\n\t>/= '; + + function parseName() { + var start = pos; + while (nameSpacer.indexOf(source[pos]) === -1 && source[pos]) { + pos++; + } + return source.slice(start, pos); + } + /** + * is parsing a node, including tagName, Attributes and its children, + * to parse children it uses the parseChildren again, that makes the parsing recursive + */ + var NoChildNodes = options.noChildNodes || ['img', 'br', 'input', 'meta', 'link', 'hr']; + + function parseNode(): Node { + pos++; + const tagName = parseName(); + const attributes: Record = {}; + let children: (string | Node)[] = []; + + // parsing attributes + while (source.charCodeAt(pos) !== closeBracketCC && source[pos]) { + var c = source.charCodeAt(pos); + if ((c > 64 && c < 91) || (c > 96 && c < 123)) { + //if('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.indexOf(S[pos])!==-1 ){ + var name = parseName(); + // search beginning of the string + var code = source.charCodeAt(pos); + while (code && code !== singleQuoteCC && code !== doubleQuoteCC && !((code > 64 && code < 91) || (code > 96 && code < 123)) && code !== closeBracketCC) { + pos++; + code = source.charCodeAt(pos); + } + if (code === singleQuoteCC || code === doubleQuoteCC) { + var value = parseString(); + if (pos === -1) { + return { + tagName, + attributes, + children, + }; + } + } else { + value = null; + pos--; + } + attributes[name] = value; + } + pos++; + } + // optional parsing of children + if (source.charCodeAt(pos - 1) !== slashCC) { + if (tagName == "script") { + var start = pos + 1; + pos = source.indexOf('', pos); + children = [source.slice(start, pos)]; + pos += 9; + } else if (tagName == "style") { + var start = pos + 1; + pos = source.indexOf('', pos); + children = [source.slice(start, pos)]; + pos += 8; + } else if (NoChildNodes.indexOf(tagName) === -1) { + pos++; + children = parseChildren(tagName); + } else { + pos++ + } + } else { + pos++; + } + return { + tagName, + attributes, + children, + }; + } + + /** + * is parsing a string, that starts with a char and with the same usually ' or " + */ + + function parseString() { + var startChar = source[pos]; + var startpos = pos + 1; + pos = source.indexOf(startChar, startpos) + return source.slice(startpos, pos); + } + + /** + * + */ + function findElements() { + var r = new RegExp('\\s' + options.attrName + '\\s*=[\'"]' + options.attrValue + '[\'"]').exec(source) + if (r) { + return r.index; + } else { + return -1; + } + } + + var out: (string | Node)[] | null = null; + if (options.attrValue !== undefined) { + options.attrName = options.attrName || 'id'; + out = []; + + while ((pos = findElements()) !== -1) { + pos = source.lastIndexOf('<', pos); + if (pos !== -1) { + out.push(parseNode()); + } + source = source.substr(pos); + pos = 0; + } + } else if (options.parseNode) { + out = parseNode() + } else { + out = parseChildren(''); + } + + if (options.filter) { + out = filter(out, options.filter); + } + + if (options.simplify) { + return simplify(Array.isArray(out) ? out : [out]); + } + + if (options.setPos) { + out.pos = pos; + } + + return out; +} + +/** +* transform the DomObject to an object that is like the object of PHP`s simple_xmp_load_*() methods. +* this format helps you to write that is more likely to keep your program working, even if there a small changes in the XML schema. +* be aware, that it is not possible to reproduce the original xml from a simplified version, because the order of elements is not saved. +* therefore your program will be more flexible and easier to read. +* +* @param {tNode[]} children the childrenList +*/ +export function simplify(children: any[]) { + var out = {}; + if (!children.length) { + return ''; + } + + if (children.length === 1 && typeof children[0] == 'string') { + return children[0]; + } + // map each object + children.forEach(function(child: { tagName: string | number; children: any; attributes: {}; }) { + if (typeof child !== 'object') { + return; + } + if (!out[child.tagName]) + out[child.tagName] = []; + var kids = simplify(child.children); + out[child.tagName].push(kids); + if (Object.keys(child.attributes).length && typeof kids !== 'string') { + kids._attributes = child.attributes; + } + }); + + for (var i in out) { + if (out[i].length == 1) { + out[i] = out[i][0]; + } + } + + return out; +}; + + +/** +* similar to simplify, but lost less +* +* @param {tNode[]} children the childrenList +*/ +export function simplifyLostLess(children: any[], parentAttributes = {}) { + var out = {}; + if (!children.length) { + return out; + } + + if (children.length === 1 && typeof children[0] == 'string') { + return Object.keys(parentAttributes).length ? { + _attributes: parentAttributes, + value: children[0] + } : children[0]; + } + // map each object + children.forEach(function(child: { tagName: string | number; children: any; attributes: {} | undefined; }) { + if (typeof child !== 'object') { + return; + } + if (!out[child.tagName]) + out[child.tagName] = []; + var kids = simplifyLostLess(child.children || [], child.attributes); + out[child.tagName].push(kids); + if (Object.keys(child.attributes).length) { + kids._attributes = child.attributes; + } + }); + + return out; +}; + +/** +* behaves the same way as Array.filter, if the filter method return true, the element is in the resultList +* @params children{Array} the children of a node +* @param f{function} the filter method +*/ +export function filter(children: any[], f: (arg0: any, arg1: any, arg2: number, arg3: string) => any, dept = 0, path = '') { + var out: any[] = []; + children.forEach(function(child: { children: any; tagName: string; }, i: string) { + if (typeof(child) === 'object' && f(child, i, dept, path)) out.push(child); + if (child.children) { + var kids = filter(child.children, f, dept + 1, (path ? path + '.' : '') + i + '.' + child.tagName); + out = out.concat(kids); + } + }); + return out; +}; + +/** +* stringify a previously parsed string object. +* this is useful, +* 1. to remove whitespace +* 2. to recreate xml data, with some changed data. +* @param {tNode} O the object to Stringify +*/ +export function stringify(O: any) { + var out = ''; + + function writeChildren(O: string | any[]) { + if (O) { + for (var i = 0; i < O.length; i++) { + if (typeof O[i] == 'string') { + out += O[i].trim(); + } else { + writeNode(O[i]); + } + } + } + } + + function writeNode(N: { tagName: string | string[]; attributes: { [x: string]: string; }; children: any; }) { + out += "<" + N.tagName; + for (var i in N.attributes) { + if (N.attributes[i] === null) { + out += ' ' + i; + } else if (N.attributes[i].indexOf('"') === -1) { + out += ' ' + i + '="' + N.attributes[i].trim() + '"'; + } else { + out += ' ' + i + "='" + N.attributes[i].trim() + "'"; + } + } + if (N.tagName[0] === '?') { + out += '?>'; + return; + } + out += '>'; + writeChildren(N.children); + out += ''; + } + writeChildren(O); + + return out; +}; + + +/** +* use this method to read the text content, of some node. +* It is great if you have mixed content like: +* this text has some big text and a link +* @return {string} +*/ +export function toContentString(tDom: string): string { + if (Array.isArray(tDom)) { + var out = ''; + tDom.forEach(function(e) { + out += ' ' + toContentString(e); + out = out.trim(); + }); + return out; + } else if (typeof tDom === 'object') { + return toContentString(tDom.children) + } else { + return ' ' + tDom; + } +}; + +export function getElementById(S: string, id: any, simplified: any) { + var out = parse(S, { + attrValue: id + }); + return simplified ? simplify(out) : out[0]; +}; + +export function getElementsByClassName(S: string, classname: string, simplified: any) { + const out = parse(S, { + attrName: 'class', + attrValue: '[a-zA-Z0-9- ]*' + classname + '[a-zA-Z0-9- ]*' + }); + return simplified ? simplify(out) : out; +}; \ No newline at end of file diff --git a/src/lib/pdf/datenblatt.html b/src/lib/pdf/datenblatt.html new file mode 100644 index 00000000..395b614a --- /dev/null +++ b/src/lib/pdf/datenblatt.html @@ -0,0 +1,87 @@ +
+

Datenblatt Energieausweis

+

Ausweis ID: 1225432

+
+

Gebäudedaten

+

Adresse: Beispielstraße 15, 22587 Beispielnese

+ +
+
+ +

Neubau

+
+
+ +

Vermietung/Verkauf

+
+
+ +

Modernisierung

+
+
+ +

Sonstiges

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GebäudetypWohnflächeLeerstandWohnungen
DoppelhaushälfteDIN Wohnfläche innen 141m20%2
DachgeschossKeller
unbeheiztnein
+ +

Verbrauch

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Von: 01.01.2014Von: 01.01.2015Von: 01.01.2016
Bis: 31.12.2014Bis: 31.12.2015Bis: 31.12.2016
Heizöl EL1947 l1907 l2248 l
Brennholz6 m36 m36 m3
+ +

Warmwasseranteil: 18%

\ No newline at end of file diff --git a/src/lib/pdf/elements/Checkbox.ts b/src/lib/pdf/elements/Checkbox.ts new file mode 100644 index 00000000..04fca4ef --- /dev/null +++ b/src/lib/pdf/elements/Checkbox.ts @@ -0,0 +1,26 @@ +import { PDFPage, rgb } from 'pdf-lib'; +import { PDFElement } from './PDFElement.js'; + +export class Checkbox extends PDFElement { + private borderWidth: number = 1; + + constructor(protected _width: number, protected _height: number) { + super(); + } + + addChild(...children: PDFElement[]): void { + throw new Error('Method not supported.'); + } + + draw(page: PDFPage, x: number, y: number): void { + page.drawRectangle({ + x: x + this.borderWidth, + // NOTE: Keine Ahnung warum * 1.5 aber dann passt es... + y: y - this._height - this.borderWidth * 1.5, + width: this._width, + height: this._height, + borderColor: rgb(0, 0, 0), + borderWidth: this.borderWidth + }); + } +} diff --git a/src/lib/pdf/elements/Flex.ts b/src/lib/pdf/elements/Flex.ts new file mode 100644 index 00000000..f71216ad --- /dev/null +++ b/src/lib/pdf/elements/Flex.ts @@ -0,0 +1,175 @@ +import { PDFPage } from 'pdf-lib'; +import { PDFElement, Size } from './PDFElement.js'; + +export interface FlexOptions { + page: PDFPage; + width: number; + height: number; + x?: number; + y?: number; + direction?: 'row' | 'column'; + justify?: 'start' | 'center' | 'end' | 'space-between' | 'space-around'; + align?: 'start' | 'center' | 'end' | 'stretch'; + gap?: number; + children?: PDFElement[]; +} + +export class Flex extends PDFElement { + private page: PDFPage; + private x: number; + private y: number; + private direction: 'row' | 'column'; + private justifyContent: 'start' | 'center' | 'end' | 'space-between' | 'space-around'; + private alignItems: 'start' | 'center' | 'end' | 'stretch'; + private gap: number; + private children: PDFElement[]; + + constructor(options: FlexOptions) { + super(); + this.page = options.page; + this._width = options.width; + this._height = options.height; + this.x = options.x ?? 0; + this.y = options.y ?? 0; + this.direction = options.direction ?? 'row'; + this.justifyContent = options.justify ?? 'start'; + this.alignItems = options.align ?? 'start'; + this.gap = options.gap ?? 0; + this.children = options.children ?? []; + } + + addChild(...children: PDFElement[]): void { + this.children.push(...children) + } + + get height(): number { + if (typeof this._height === "number") { + return this._height; + } + + let currentHeight = 0 + + if (this.direction === "column") { + for (const child of this.children) { + currentHeight += child.height; + } + + currentHeight += this.gap * this.children.length - 1; + } else { + for (const child of this.children) { + if (child.height > currentHeight) { + currentHeight = child.height + } + } + } + + return currentHeight; + } + + set width(value: Size) { + this._width = value; + } + + get width(): number { + if (typeof this._width === "number") { + return this._width; + } + + let currentWidth = 0 + + if (this.direction === "row") { + for (const child of this.children) { + currentWidth += child.width; + } + + currentWidth += this.gap * this.children.length - 1; + } else { + for (const child of this.children) { + if (child.width > currentWidth) { + currentWidth = child.width + } + } + } + + return currentWidth; + } + + draw(page: PDFPage, x: number = this.x, y: number = this.y): void { + const childPositions = this.calculateChildPositions(x, y); + + // Draw each child + this.children.forEach((child, i) => { + const pos = childPositions[i]; + + child.draw(page, pos.x, pos.y); + }); + } + + private calculateChildPositions(x: number, y: number): { x: number; y: number }[] { + const positions: { x: number; y: number }[] = []; + let currentX = x; + let currentY = y; + + // Calculate total size of children and gaps + const totalChildrenSize = this.children.reduce( + (sum, child) => sum + (this.direction === 'row' ? child.width : child.height), + 0 + ); + + const totalGaps = this.gap * (this.children.length - 1); + + // Justify content + const justifyOffset = this.calculateJustifyOffset(totalChildrenSize, totalGaps); + + // Since the origin is at X: 0 Y: page height and everything will be drawn + // above the current position we first need to subtract the height of the + // element from the current Y + this.children.forEach((child, i) => { + const childX = this.direction === 'row' ? currentX : currentX + this.calculateAlignOffset(child.width); + const childY = this.direction === 'row' ? currentY - this.calculateAlignOffset(child.height) : currentY; + + if (this.direction === "row") { + currentX += child.width + this.gap + justifyOffset; + } + + if (this.direction === 'column') { + currentY -= child.height + this.gap; + } + + positions.push({ x: childX, y: childY }); + }); + + return positions; + } + + private calculateJustifyOffset(totalChildrenSize: number, totalGaps: number): number { + const remainingSpace = + this.direction === 'row' ? this.width - totalChildrenSize - totalGaps : this.height - totalChildrenSize - totalGaps; + + switch (this.justifyContent) { + case 'center': + return remainingSpace / 2; + case 'end': + return remainingSpace; + case 'space-between': + return totalGaps / (this.children.length - 1) + (this.width - totalChildrenSize) / this.children.length; + case 'space-around': + return remainingSpace / this.children.length; + default: + return 0; + } + } + + private calculateAlignOffset(childSize: number): number { + switch (this.alignItems) { + case 'center': + return (this.direction === 'row' ? this.height - childSize : this.width - childSize) / 2; + case 'end': + return this.direction === 'row' ? this.height - childSize : this.width - childSize; + case 'stretch': + return 0; + default: + return 0; + } + } +} diff --git a/src/lib/pdf/elements/Layout.ts b/src/lib/pdf/elements/Layout.ts new file mode 100644 index 00000000..1f542c3b --- /dev/null +++ b/src/lib/pdf/elements/Layout.ts @@ -0,0 +1,84 @@ +import { PDFPage } from "pdf-lib"; +import { PDFElement, Size } from "./PDFElement.js"; + +export type Margin = { + top: number, + left: number, + right: number, + bottom: number +} + +export type Padding = Margin; + +export class Layout extends PDFElement { + private margin: Margin + protected _height: Size = "auto"; + protected _width: Size = "auto"; + + private padding: Padding = { + bottom: 0, + left: 0, + right: 0, + top: 0 + }; + + public children: PDFElement[]; + + constructor(children: PDFElement[] = [], options?: { + margin?: Margin, + padding?: Padding + }) { + super() + + this.children = children + this.margin = options?.margin ?? { + bottom: 0, + left: 0, + right: 0, + top: 0 + }; + + this.padding = options?.padding ?? { + bottom: 0, + left: 0, + right: 0, + top: 0 + }; + } + + get height(): number { + if (typeof this._height === "number") { + return this._height; + } + + let currentHeight = 0 + + for (const child of this.children) { + currentHeight += child.height; + } + + return currentHeight; + } + + set height(value: number) { + this._height = value; + } + + draw(page: PDFPage, x: number, y: number): void { + let currentY = y - this.margin.top - this.padding.top; + + for (const child of this.children) { + child.draw(page, x + this.margin.left + this.padding.left, currentY); + + currentY -= child.height; + } + } + + addChild(...children: PDFElement[]): void { + this.children.push(...children) + } +} + +export function layout(...args: ConstructorParameters) { + return new Layout(...args); +} \ No newline at end of file diff --git a/src/lib/pdf/elements/PDFElement.ts b/src/lib/pdf/elements/PDFElement.ts new file mode 100644 index 00000000..5a7c0db3 --- /dev/null +++ b/src/lib/pdf/elements/PDFElement.ts @@ -0,0 +1,27 @@ +import { PDFPage } from 'pdf-lib'; +export type Size = number | "auto"; + +export abstract class PDFElement { + protected _width: Size = 0; + + get width(): number { + return this._width === "auto" ? 0 : this._width + } + + set width(value: Size) { + this._width = value; + } + protected _height: Size = 0; + + get height(): number { + return this._height === "auto" ? 0 : this._height + } + + set height(value: Size) { + this._height = value; + } + + abstract draw(page: PDFPage, x: number, y: number): void; + + abstract addChild(...children: PDFElement[]): void; +} diff --git a/src/lib/pdf/elements/Text.ts b/src/lib/pdf/elements/Text.ts new file mode 100644 index 00000000..ad2afb8b --- /dev/null +++ b/src/lib/pdf/elements/Text.ts @@ -0,0 +1,39 @@ +import { PDFPage, PDFFont, rgb, RGB } from 'pdf-lib'; +import { PDFElement, Size } from './PDFElement.js'; + +export interface TextOptions { + font: PDFFont; + fontSize?: number; + color?: RGB; +} + +export class Text extends PDFElement { + private content: string; + private font: PDFFont; + private fontSize: number; + private color: RGB; + + constructor(content: string, options: TextOptions) { + super(); + this.content = content; + this.font = options.font; + this.fontSize = options.fontSize ?? 12; + this.color = options.color ?? rgb(0, 0, 0); + this._width = this.font.widthOfTextAtSize(content, this.fontSize); + this._height = this.font.heightAtSize(this.fontSize); + } + + addChild(...children: PDFElement[]): void { + throw new Error("Cannot add child element to Text") + } + + draw(page: PDFPage, x: number, y: number): void { + page.drawText(this.content, { + x, + y: y - this.height, + size: this.fontSize, + font: this.font, + color: this.color, + }); + } +} diff --git a/src/lib/pdf/elements/index.ts b/src/lib/pdf/elements/index.ts new file mode 100644 index 00000000..bc06510a --- /dev/null +++ b/src/lib/pdf/elements/index.ts @@ -0,0 +1,20 @@ +import { Flex, FlexOptions } from "./Flex.js"; +import { PDFElement } from "./PDFElement.js"; +import { TextOptions } from "./Text.js"; + +import { Checkbox } from "./Checkbox.js" +import { Text } from "./Text.js" + +export function flex(children: PDFElement[], options: Partial): Flex { + return new Flex({ ...options, children }); +} + +export function text(content: string, options: TextOptions): Text { + return new Text(content, options); +} + +export function checkbox(width: number, height: number): Checkbox { + return new Checkbox(width, height); +} + +export { Text, Checkbox, Flex } \ No newline at end of file diff --git a/src/lib/pdf/elements/xml2pdf.ts b/src/lib/pdf/elements/xml2pdf.ts new file mode 100644 index 00000000..9b22cf33 --- /dev/null +++ b/src/lib/pdf/elements/xml2pdf.ts @@ -0,0 +1,105 @@ +import * as txml from "#lib/helpers/txml.js" +import { PDFDocument, PDFFont, rgb, StandardFonts } from "pdf-lib" +import { Checkbox, Flex, Text } from "./index.js" +import { Layout } from "./Layout.js" +import { PDFElement } from "./PDFElement.js" + +export function xml2pdf(xml: string, font: PDFFont) { + const tree = txml.parse(xml) + + const iterateChildren = (children: ReturnType, parent: PDFElement) => { + for (const child of children) { + if (typeof child === "string") { + // Simple text + parent.addChild(new Text(child, { font })) + } else if (child.tagName === "flex") { + const flexbox = new Flex({ + height: parseFloat(child.attributes.height) || "auto", + width: parseFloat(child.attributes.width) || "auto", + align: child.attributes.align, + direction: child.attributes.direction, + gap: parseFloat(child.attributes.gap) || 0, + justify: child.attributes.justify + }) + + iterateChildren(child.children, flexbox) + parent.addChild(flexbox) + } else if (child.tagName === "text") { + + let color = rgb(0,0,0) + + if (child.attributes.hasOwnProperty("color")) { + const colorValue = child.attributes.color.split(",") + + if (colorValue.length !== 3) { + throw new Error("Invalid color, please provide 'r,g,b' as a value.") + } + + color = rgb(...colorValue.map((x) => parseInt(x) / 255) as [number, number, number]); + } + + const text = new Text(child.children[0] || "", { font: child.attributes.hasOwnProperty("bold") ? bold : font, fontSize: parseFloat(child.attributes.size) || 10, color }) + + parent.addChild(text) + } else if (child.tagName === "checkbox") { + if (typeof child.attributes.width === "undefined" || typeof child.attributes.height === "undefined") { + throw new Error("Missing height or width property in Checkbox creation.") + } + + const checkbox = new Checkbox(parseFloat(child.attributes.width), parseFloat(child.attributes.height)) + + parent.addChild(checkbox); + } else if (child.tagName === "layout") { + const layout = new Layout([], { + margin: { + bottom: parseFloat(child.attributes.marginBottom) || 0, + left: parseFloat(child.attributes.marginLeft) || 0, + right: parseFloat(child.attributes.marginRight) || 0, + top: parseFloat(child.attributes.marginTop) || 0, + }, + padding: { + bottom: parseFloat(child.attributes.paddingBottom) || 0, + left: parseFloat(child.attributes.paddingLeft) || 0, + right: parseFloat(child.attributes.paddingRight) || 0, + top: parseFloat(child.attributes.paddingTop) || 0, + } + }) + + iterateChildren(child.children, layout) + parent.addChild(layout) + } + } + } + + const layout = new Layout([]); + iterateChildren(tree, layout) + + return layout +} + +const pdf = await PDFDocument.create() + +const page = pdf.addPage() + +const font = await pdf.embedFont(StandardFonts.Helvetica) +const bold = await pdf.embedFont(StandardFonts.HelveticaBold) + +const layout = xml2pdf(` + Hello + Hello, how are you? + + + Hello + + Hello + Nasya, i love you + + +`, font) + +layout.draw(page, 0, page.getHeight()) + +import { writeFileSync } from "fs" +import { FixedLengthArray } from "#lib/Berechnungen/BedarfsausweisWohnen/types.js" + +writeFileSync("./test-pdf.pdf", await pdf.save()) \ No newline at end of file diff --git a/src/lib/pdf/pdfDatenblatt.ts b/src/lib/pdf/pdfDatenblatt.ts new file mode 100644 index 00000000..fca6f23c --- /dev/null +++ b/src/lib/pdf/pdfDatenblatt.ts @@ -0,0 +1,159 @@ +import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js"; +import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js"; +import * as fs from "fs" +import { PDFDocument, rgb, StandardFonts, TextAlignment } from "pdf-lib"; +import { checkbox, flex, text } from "./elements/index.js"; + +/* -------------------------------- Pdf Tools ------------------------------- */ + +export async function pdfDatenblatt(ausweis: VerbrauchsausweisWohnenClient) { + const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("./templates/Leerseite_Datenblatt.pdf", import.meta.url), "base64"); + const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF) + const pages = pdf.getPages() + + // const template = VerbrauchsausweisWohnen2016Template as Template; + + const berechnungen = await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis); + + const height = pages[0].getHeight() + const width = pages[0].getWidth() + + const font = await pdf.embedFont(StandardFonts.Helvetica) + const bold = await pdf.embedFont(StandardFonts.HelveticaBold) + + const form = pdf.getForm() + form.updateFieldAppearances(font) + + const marginX = 45; + const marginY = 150; + + const benutzer: typeof ausweis.benutzer = ausweis.benutzer || { + vorname: "Max", + name: "Mustermann", + adresse: "Musterstraße 123", + plz: "12345", + ort: "Beispielhausen" + }; + + pages[0].drawText(`${benutzer.vorname} ${benutzer.name}`, { + x: marginX, + y: height - marginY, + font, + size: 12 + }) + + pages[0].drawText(benutzer.adresse, { + x: marginX, + y: height - marginY - 15, + font, + size: 12 + }) + + pages[0].drawText(`${benutzer.plz} ${benutzer.ort}`, { + x: marginX, + y: height - marginY - 30, + font, + size: 12 + }) + + pages[0].drawText("Datenblatt Energieausweis", { + x: marginX, + y: height - marginY - 100, + font: bold, + size: 12, + }) + + let ausweisIDText = `Ausweis ID: ${ausweis.uid}` + + pages[0].drawText(ausweisIDText, { + x: width - marginX - font.widthOfTextAtSize(ausweisIDText, 12), + y: height - marginY - 100, + font, + size: 12, + }) + + pages[0].drawText("Gebäudedaten", { + x: marginX, + y: height - marginY - 125, + font: bold, + size: 12, + }) + + pages[0].drawText(`Adresse: ${ausweis.gebaeude_aufnahme_allgemein.adresse}, ${ausweis.gebaeude_aufnahme_allgemein.plz} ${ausweis.gebaeude_aufnahme_allgemein.ort}`, { + x: marginX, + y: height - marginY - 140, + font, + size: 12, + }) + + const containerWidth = width - marginX; + + const layout = flex([ + flex([ + checkbox(8, 8), text("Neubau", { + color: rgb(0,0,0), + font, + fontSize: 12 + }) + ], { + align: "center", + justify: "center", + gap: 5, + height: 12, + page: pages[0] + }), + flex([ + checkbox(8, 8), text("Vermietung/Verkauf", { + color: rgb(0,0,0), + font, + fontSize: 12 + }) + ], { + align: "center", + justify: "center", + gap: 5, + height: 12, + page: pages[0] + }), + flex([ + checkbox(8, 8), text("Modernisierung", { + color: rgb(0,0,0), + font, + fontSize: 12 + }) + ], { + align: "center", + justify: "center", + gap: 5, + height: 12, + page: pages[0] + }), + flex([ + checkbox(8, 8), text("Sonstiges", { + color: rgb(0,0,0), + font, + fontSize: 12 + }) + ], { + align: "center", + justify: "center", + gap: 5, + height: 12, + page: pages[0] + }) + ], { + align: "center", + justify: "space-between", + gap: 15, + x: marginX, + y: height - marginY - 165, + height: 12, + width: containerWidth + }) + + layout.draw(pages[0]) + + // pdf.getForm().flatten() + + return pdf.save(); +} \ No newline at end of file diff --git a/src/lib/pdf/templates/Leerseite_Datenblatt.pdf b/src/lib/pdf/templates/Leerseite_Datenblatt.pdf new file mode 100644 index 00000000..7a561d4e Binary files /dev/null and b/src/lib/pdf/templates/Leerseite_Datenblatt.pdf differ diff --git a/src/pages/DIN18599/berechnungstabellen/index.astro b/src/pages/DIN18599/berechnungstabellen/index.astro index 93ee2d8a..bfcd4bee 100644 --- a/src/pages/DIN18599/berechnungstabellen/index.astro +++ b/src/pages/DIN18599/berechnungstabellen/index.astro @@ -2,7 +2,7 @@ import Layout from "#layouts/Layout.astro"; import { berechnungNutzenergiebedarfHeizen } from "#lib/Berechnungen/BedarfsausweisWohnen/BerechnungNutzenergiebedarfHeizen.js" -import A12BerechnungNutzenergiebedarf from "#components/Tabellen/A12BerechnungNutzenergiebedarf.svelte"; +import A12NutzenergiebedarfHeizung from "#components/Tabellen/A12NutzenergiebedarfHeizung.svelte"; import { BedarfsausweisWohnenClient, GebaeudeAufnahmeClient } from "#components/Ausweis/types"; import A1AnlagenBeschreibung from "#components/Tabellen/A1AnlagenBeschreibung.svelte"; import A2Wintergarten from "#components/Tabellen/A2Wintergarten.svelte"; @@ -1039,8 +1039,6 @@ const gebaeude_aufnahme: GebaeudeAufnahmeClient = { flaeche: 152 }
- - >
diff --git a/src/pages/dev/datenblatt-viewer.astro b/src/pages/dev/datenblatt-viewer.astro new file mode 100644 index 00000000..8239074d --- /dev/null +++ b/src/pages/dev/datenblatt-viewer.astro @@ -0,0 +1,9 @@ +--- +import BlankLayout from "#layouts/BlankLayout.astro"; + + +--- + + + + \ No newline at end of file diff --git a/src/pages/pdf/datenblatt.astro b/src/pages/pdf/datenblatt.astro index 5cc883d6..6e09c41d 100644 --- a/src/pages/pdf/datenblatt.astro +++ b/src/pages/pdf/datenblatt.astro @@ -1,11 +1,7 @@ --- -import { generate } from "@pdfme/generator"; -import VerbrauchsausweisWohnen2016Template from "../../data/templates/verbrauchsausweis-wohnen-2016.json"; -import { convertAusweisData } from "#lib/AusweisData"; -import { variable } from "#lib/pdf/plugins/variables"; -import { text, image } from "@pdfme/schemas" -import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; +import { BenutzerClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { createCaller } from "#lib/caller"; +import { pdfDatenblatt } from "#lib/pdf/pdfDatenblatt"; const base64 = Astro.url.searchParams.get("base64"); let ausweis: VerbrauchsausweisWohnenClient | null = null; @@ -24,25 +20,11 @@ if (base64) { ausweis = await caller.v1.verbrauchsausweisWohnen.get({ uid: uidAusweis - }) + }); } -if (!ausweis) { - return Astro.redirect("/404"); -} +const pdf = await pdfDatenblatt(ausweis); -const pdf = await generate({ - template: VerbrauchsausweisWohnen2016Template, - plugins: { text, image, variable }, - inputs: [convertAusweisData(ausweis)], - options: { - author: "IB Cornelsen", - creationDate: new Date(), - creator: "IB Cornelsen", - language: "de", - title: "Verbrauchsausweis Wohnen 2016", - }, -}); return new Response(pdf, { headers: { diff --git a/src/pages/sanierungsfahrplan/dach/index.astro b/src/pages/sanierungsfahrplan/dach/index.astro new file mode 100644 index 00000000..bc7e9363 --- /dev/null +++ b/src/pages/sanierungsfahrplan/dach/index.astro @@ -0,0 +1,19 @@ +--- +import Layout from "#layouts/Layout.astro"; +import SanierungsFahrplanDachTemplate from "#components/design/content/SanierungsFahrplanDachTemplate.svelte"; + +--- + + + +

Dach - energetischer Istzustand

+ +

Überblick zum energetischen Istzustand des Daches ihres Hauses

+ +
+ + + +
+ +
\ No newline at end of file diff --git a/src/pages/sanierungsfahrplan/haus/index.astro b/src/pages/sanierungsfahrplan/haus/index.astro new file mode 100644 index 00000000..d9d37753 --- /dev/null +++ b/src/pages/sanierungsfahrplan/haus/index.astro @@ -0,0 +1,19 @@ +--- +import Layout from "#layouts/Layout.astro"; +import SanierungsFahrplanHeizungTemplate from "#components/design/content/SanierungsFahrplanHeizungTemplate.svelte"; + +--- + + + +

Heizung - energetischer Istzustand

+ +

Überblick zum energetischen Istzustand Ihrer Heizung

+ +
+ + + +
+ +
\ No newline at end of file diff --git a/src/pages/sanierungsfahrplan/index.astro b/src/pages/sanierungsfahrplan/index.astro new file mode 100644 index 00000000..3f579c35 --- /dev/null +++ b/src/pages/sanierungsfahrplan/index.astro @@ -0,0 +1,15 @@ +--- +import Layout from "#layouts/Layout.astro"; +import SanierungsFahrplanIstTemplate from "#components/design/content/SanierungsFahrplanIstTemplate.svelte"; + +--- + + + +

Ihr Haus heute - energetischer Istzustand

+ +

Überblick zum energetischen Istzustand und Sanierungsbedarf ihres Hauses

+ + + +
\ No newline at end of file diff --git a/src/pages/sanierungsfahrplan/wände/index.astro b/src/pages/sanierungsfahrplan/wände/index.astro new file mode 100644 index 00000000..1ef506be --- /dev/null +++ b/src/pages/sanierungsfahrplan/wände/index.astro @@ -0,0 +1,19 @@ +--- +import Layout from "#layouts/Layout.astro"; +import SanierungsFahrplanWandTemplate from "#components/design/content/SanierungsFahrplanWandTemplate.svelte"; + +--- + + + +

Wände - energetischer Istzustand

+ +

Überblick zum energetischen Istzustand der Wände ihres Hauses

+ +
+ + + +
+ +
\ No newline at end of file diff --git a/tailwind.config.cjs b/tailwind.config.cjs index a324930a..74045ef5 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -37,7 +37,16 @@ module.exports = { "formular-rahmen": "rgba(255,204,6,1)", "bereich-box": "rgba(252,234,187,0.2)", - + + "effizienzFarbe-1": "#00a759ff", + "effizienzFarbe-2": "#56be06ff", + "effizienzFarbe-3": "#d2dd00ff", + "effizienzFarbe-4": "#fbe115ff", + "effizienzFarbe-5": "#fbb900ff", + "effizienzFarbe-6": "#f59401ff", + "effizienzFarbe-7": "#ef6800ff", + "effizienzFarbe-8": "#dd2a1bff", + "effizienzFarbe-9": "#b11c0cff", "pdf-yellow-bright": "#f3cb00", "pdf-yellow-light": "#fff6ca", diff --git a/test-pdf.pdf b/test-pdf.pdf new file mode 100644 index 00000000..ad6b72a3 Binary files /dev/null and b/test-pdf.pdf differ diff --git a/tsconfig.json b/tsconfig.json index 17f56b38..0681d578 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -41,5 +41,6 @@ "#widgets/*": ["./src/components/widgets/*"] }, "types": ["cypress", "cypress-file-upload", "bun-types", "svelte"] - } + }, + "exclude": ["node_modules"] }