Neville Ausgetauscht + PDF

This commit is contained in:
Moritz Utcke
2025-01-13 11:09:20 +07:00
committed by Jens Cornelsen
parent c797fe4dda
commit f694f7aa3f
13 changed files with 992 additions and 120 deletions

2
.gitignore vendored
View File

@@ -30,3 +30,5 @@ bun.lockb
public/fonts/
*.Identifier
src/lib/Berechnungen/BedarfsausweisWohnen/18599-Tabellenverfahren-Wohngebaeude-komplett-ocr.pdf

View File

@@ -1,3 +1,4 @@
<<<<<<< HEAD
{
"name": "online-energieausweis",
"version": "0.0.1",
@@ -84,3 +85,87 @@
"typescript": "^4.9.5"
}
}
=======
{
"name": "online-energieausweis",
"version": "0.0.1",
"license": "GPL V3.0",
"type": "module",
"scripts": {
"dev": "bun astro dev",
"build": "bun astro build",
"preview": "bun astro preview",
"astro": "astro",
"test:e2e": "cypress run",
"test:unit": "bun test",
"format": "prettier --write .",
"build:production": "astro build && bun --bun server.ts",
"i18n:generate": "bunx astro-i18next generate",
"prisma:studio": "bunx prisma studio --schema=./node_modules/@ibcornelsen/database/prisma/schema.prisma"
},
"private": true,
"dependencies": {
"@astrojs/mdx": "^3.1.9",
"@astrojs/node": "^8.3.4",
"@astrojs/svelte": "^2.2.0",
"@astrojs/tailwind": "^3.1.3",
"@ibcornelsen/api": "link:@ibcornelsen/api",
"@ibcornelsen/database": "link:@ibcornelsen/database",
"@ibcornelsen/ui": "^0.0.2",
"@mollie/api-client": "^3.7.0",
"@pdfme/common": "^5.1.7",
"@pdfme/generator": "^5.2.11",
"@pdfme/ui": "^5.1.7",
"@trpc/client": "^10.45.2",
"@trpc/server": "^10.45.2",
"astro": "^4.16.10",
"body-scroll-lock": "^4.0.0-beta.0",
"buffer": "^6.0.3",
"bun": "^1.1.34",
"csvtojson": "^2.0.10",
"express": "^4.21.1",
"flag-icons": "^6.15.0",
"fontkit": "^2.0.4",
"js-cookie": "^3.0.5",
"js-interpolate": "^1.3.2",
"moment": "^2.30.1",
"moment-timezone": "^0.5.46",
"pdf-lib": "^1.17.1",
"postcss-nested": "^7.0.2",
"radix-svelte-icons": "^1.0.0",
"sass": "^1.80.6",
"svelte": "^3.59.2",
"svelte-dialogs": "^1.2.2",
"svelte-preprocess": "^5.1.4",
"svelte-ripple-action": "^1.0.6",
"tailwindcss": "^3.4.14",
"trpc-openapi": "^1.2.0",
"uuid": "^9.0.1",
"zod": "^3.23.8"
},
"devDependencies": {
"@faker-js/faker": "^8.4.1",
"@rollup/plugin-dsv": "^3.0.5",
"@tailwindcss/typography": "^0.5.15",
"@types/body-scroll-lock": "^3.1.2",
"@types/express": "^5.0.0",
"@types/fontkit": "^2.0.7",
"@types/js-cookie": "^3.0.6",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"autoprefixer": "^10.4.20",
"bun-types": "^1.1.34",
"cypress": "^13.15.2",
"cypress-file-upload": "^5.0.8",
"daisyui": "^4.12.14",
"eslint": "~8.15.0",
"eslint-config-prettier": "8.1.0",
"postcss": "^8.4.49",
"postcss-import": "^16.1.0",
"postcss-nesting": "^13.0.1",
"prettier": "^2.8.8",
"typescript": "^4.9.5"
}
}
>>>>>>> 01b701c (Neville Ausgetauscht + PDF)

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import { BedarfsausweisWohnenClient, GebaeudeAufnahmeClient } from "#components/Ausweis/types.js";
import { funktionMonatlicherBelastungsgrad } from "#lib/Berechnungen/BedarfsausweisWohnen/funktionMonatlicherBelastungsgrad";
import { funktionBilanzInnentemperatur } from "#lib/Berechnungen/BedarfsausweisWohnen/funktionBilanzInnentemperatur";
import { funktionAusnutzungsgrad } from "#lib/Berechnungen/BedarfsausweisWohnen/funktionAusnutzungsgrad";
import { funktionMonatlicherBelastungsgrad } from "#lib/Berechnungen/BedarfsausweisWohnen/funktionMonatlicherBelastungsgrad.js";
import { funktionBilanzInnentemperatur } from "#lib/Berechnungen/BedarfsausweisWohnen/funktionBilanzInnentemperatur.js";
import { funktionAusnutzungsgrad } from "#lib/Berechnungen/BedarfsausweisWohnen/funktionAusnutzungsgrad.js";
export let ausweis: BedarfsausweisWohnenClient;
export let gebaeude_aufnahme: GebaeudeAufnahmeClient;
@@ -128,7 +128,7 @@
Dezember: 0
};
let bilanzinnentemperaturen = {
let bilanzInnenTemperaturen = {
Januar: 0,
Februar: 0,
März: 0,
@@ -170,31 +170,34 @@
belastungsgrade.November = funktionMonatlicherBelastungsgrad(heizlast, zeitkonstante, "November");
belastungsgrade.Dezember = funktionMonatlicherBelastungsgrad(heizlast, zeitkonstante, "Dezember");
bilanzinnentemperaturen.Januar = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Januar");
bilanzinnentemperaturen.Februar = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Februar");
bilanzinnentemperaturen.März = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "März");
bilanzinnentemperaturen.April = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "April");
bilanzinnentemperaturen.Mai = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Mai");
bilanzinnentemperaturen.Juni = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Juni");
bilanzinnentemperaturen.Juli = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Juli");
bilanzinnentemperaturen.August = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "August");
bilanzinnentemperaturen.September = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "September");
bilanzinnentemperaturen.Oktober = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Oktober");
bilanzinnentemperaturen.November = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "November");
bilanzinnentemperaturen.Dezember = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Dezember");
bilanzInnenTemperaturen.Januar = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Januar");
bilanzInnenTemperaturen.Februar = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Februar");
bilanzInnenTemperaturen.März = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "März");
bilanzInnenTemperaturen.April = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "April");
bilanzInnenTemperaturen.Mai = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Mai");
bilanzInnenTemperaturen.Juni = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Juni");
bilanzInnenTemperaturen.Juli = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Juli");
bilanzInnenTemperaturen.August = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "August");
bilanzInnenTemperaturen.September = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "September");
bilanzInnenTemperaturen.Oktober = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Oktober");
bilanzInnenTemperaturen.November = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "November");
bilanzInnenTemperaturen.Dezember = funktionBilanzInnentemperatur(heizlast, zeitkonstante, "Dezember");
waermeSenken.Januar = maximalerWaermestrom * [bilanzinnentemperaturen.Januar - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.Januar;
waermeSenken.Februar = maximalerWaermestrom * [bilanzinnentemperaturen.Februar - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.Februar;
waermeSenken.März = maximalerWaermestrom * [bilanzinnentemperaturen.März - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.März;
waermeSenken.April = maximalerWaermestrom * [bilanzinnentemperaturen.April - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.April;
waermeSenken.Mai = maximalerWaermestrom * [bilanzinnentemperaturen.Mai - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.Mai;
waermeSenken.Juni = maximalerWaermestrom * [bilanzinnentemperaturen.Juni - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.Juni;
waermeSenken.Juli = maximalerWaermestrom * [bilanzinnentemperaturen.Juli - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.Juli;
waermeSenken.August = maximalerWaermestrom * [bilanzinnentemperaturen.August - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.August;
waermeSenken.September = maximalerWaermestrom * [bilanzinnentemperaturen.September - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.September;
waermeSenken.Oktober = maximalerWaermestrom * [bilanzinnentemperaturen.Oktober - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.Oktober;
waermeSenken.November = maximalerWaermestrom * [bilanzinnentemperaturen.November - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.November;
waermeSenken.Dezember = maximalerWaermestrom * [bilanzinnentemperaturen.Dezember - minimaleAussentemperatur] / [innenTemperatur - minimaleAussentemperatur] * belastungsgrade.Dezember;
console.log(belastungsgrade.Juli, bilanzInnenTemperaturen.Juli);
waermeSenken.Januar = maximalerWaermestrom * (bilanzInnenTemperaturen.Januar - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.Januar;
waermeSenken.Februar = maximalerWaermestrom * (bilanzInnenTemperaturen.Februar - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.Februar;
waermeSenken.März = maximalerWaermestrom * (bilanzInnenTemperaturen.März - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.März;
waermeSenken.April = maximalerWaermestrom * (bilanzInnenTemperaturen.April - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.April;
waermeSenken.Mai = maximalerWaermestrom * (bilanzInnenTemperaturen.Mai - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.Mai;
waermeSenken.Juni = maximalerWaermestrom * (bilanzInnenTemperaturen.Juni - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.Juni;
waermeSenken.Juli = maximalerWaermestrom * (bilanzInnenTemperaturen.Juli - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.Juli;
waermeSenken.August = maximalerWaermestrom * (bilanzInnenTemperaturen.August - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.August;
waermeSenken.September = maximalerWaermestrom * (bilanzInnenTemperaturen.September - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.September;
waermeSenken.Oktober = maximalerWaermestrom * (bilanzInnenTemperaturen.Oktober - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.Oktober;
waermeSenken.November = maximalerWaermestrom * (bilanzInnenTemperaturen.November - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.November;
waermeSenken.Dezember = maximalerWaermestrom * (bilanzInnenTemperaturen.Dezember - minimaleAussentemperatur) / (innenTemperatur - minimaleAussentemperatur) * belastungsgrade.Dezember;
waermequellensenkenverhaeltnisJanuar = waermeQuellen.Januar / waermeSenken.Januar;
@@ -210,6 +213,9 @@
waermequellensenkenverhaeltnisNovember = waermeQuellen.November / waermeSenken.November;
waermequellensenkenverhaeltnisDezember = waermeQuellen.Dezember / waermeSenken.Dezember;
console.log(waermequellensenkenverhaeltnisJuli);
ausnutzungsgradJanuar = funktionAusnutzungsgrad(waermequellensenkenverhaeltnisJanuar, zeitkonstante, "alleMonate");
ausnutzungsgradFebruar = funktionAusnutzungsgrad(waermequellensenkenverhaeltnisFebruar, zeitkonstante, "alleMonate");
ausnutzungsgradMärz = funktionAusnutzungsgrad(waermequellensenkenverhaeltnisMärz, zeitkonstante, "alleMonate");
@@ -327,7 +333,7 @@
<tbody>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">31</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.Januar*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.Januar*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">1,0</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.Januar*1000)/1000}
</td>
@@ -342,7 +348,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">28</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.Februar*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.Februar*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">1,9</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.Februar*1000)/1000}
@@ -358,7 +364,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">31</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.März*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.März*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">4,7</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.März*1000)/1000}
@@ -374,7 +380,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">30</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.April*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.April*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">9,2</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.April*1000)/1000}
@@ -390,7 +396,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">31</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.Mai*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.Mai*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">14,1</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.Mai*1000)/1000}
@@ -406,7 +412,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">30</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.Juni*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.Juni*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">16,7</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.Juni*1000)/1000}
@@ -422,7 +428,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">31</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.Juli*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.Juli*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">19,0</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.Juli*1000)/1000}
@@ -438,7 +444,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">31</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.August*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.August*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">18,6</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.August*1000)/1000}
@@ -454,7 +460,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">30</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.September*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.September*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">14,3</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.September*1000)/1000}
@@ -470,7 +476,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">31</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.Oktober*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.Oktober*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">9,4</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.Oktober*1000)/1000}
@@ -486,7 +492,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">30</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.November*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.November*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">4,1</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.November*1000)/1000}
@@ -502,7 +508,7 @@
</tr>
<tr>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">31</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzinnentemperaturen.Dezember*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(bilanzInnenTemperaturen.Dezember*1000)/1000}</td>
<td class="border border-gray-300 px-2 py-1 bg-gray-100">0,9</td>
<td class="border border-gray-300 px-2 py-1 bg-blue-100">{Math.round(belastungsgrade.Dezember*1000)/1000}

View File

@@ -1,80 +1,156 @@
// Funktion zur Berechnung des Ausnutzungsgrades aus Tabelle 18
import { nevillePolynomialInterpolation } from "js-interpolate";
import { cubicSplineInterpolation, nevillePolynomialInterpolation } from "js-interpolate";
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],
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,
];
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];
export function funktionAusnutzungsgrad(waermequellensenkenverhaeltnis: number, zeitkonstane: number, monat: keyof typeof dataset) {
const data = dataset[monat]
const interpolations: number[] = []
const interpolations: number[] = [];
for (const key in data) {
const values = data[key as unknown as keyof typeof 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
)
const interpolated = cubicSplineInterpolation(
values.map((value, i) => ({
x: waermeQuellenSenkenVerhaeltnis[i],
y: value,
})),
waermequellensenkenverhaeltnis
);
interpolations.push(interpolate(waermequellensenkenverhaeltnis))
interpolations.push(interpolated);
}
const interpolate = nevillePolynomialInterpolation(
const interpolated = cubicSplineInterpolation(
interpolations.map((interpolation, i) => {
return {
x: Object.keys(data)[i],
y: interpolation
}
y: interpolation,
};
}),
interpolations.length
)
zeitkonstane
);
return interpolate(zeitkonstane)
return interpolated;
}

View File

@@ -1,6 +1,6 @@
// Funktion zur Berechnung der Bilanzinnentemperatur aus Tabelle 8 EFH oder Tabelle 10 MFH
import { nevillePolynomialInterpolation } from "js-interpolate";
import { cubicSplineInterpolation, nevillePolynomialInterpolation } from "js-interpolate";
import { any } from "node_modules/cypress/types/bluebird/index.js";
// aus Eingabeformular
@@ -149,7 +149,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:
export function funktionBilanzInnentemperatur(heizlast: number, zeitkonstane: number, monat: keyof typeof dataset) {
export function funktionBilanzInnentemperatur(heizlast: number, zeitkonstane: number, monat: keyof typeof dataset): number {
const data = dataset[monat]
const interpolations: number[] = []
@@ -157,25 +157,23 @@ export function funktionBilanzInnentemperatur(heizlast: number, zeitkonstane: nu
for (const key in data) {
const values = data[key as unknown as keyof typeof data]
const interpolate = nevillePolynomialInterpolation(
const interpolated = cubicSplineInterpolation(
values.map((value, i) => ({ x: HeizLast[i], y: value })),
values.length
heizlast
)
interpolations.push(interpolate(heizlast))
interpolations.push(interpolated)
}
const interpolate = nevillePolynomialInterpolation(
const interpolated = cubicSplineInterpolation(
interpolations.map((interpolation, i) => {
return {
x: Object.keys(data)[i],
y: interpolation
}
}),
interpolations.length
zeitkonstane
)
return interpolate(zeitkonstane)
return interpolated
}
console.log(funktionBilanzInnentemperatur(120, 100, "Januar"))

View File

@@ -1,6 +1,6 @@
// Funktion zur Berechnung des monatlichen Belastungsgrades aus Tabelle 9 EFH und Tabelle 11 MFH
import { nevillePolynomialInterpolation } from "js-interpolate";
import { cubicSplineInterpolation } from "js-interpolate";
// aus Eingabeformular
let wohneinheiten = 3;
@@ -156,25 +156,30 @@ export function funktionMonatlicherBelastungsgrad(heizlast: number, zeitkonstane
for (const key in data) {
const values = data[key as unknown as keyof typeof data]
const interpolate = nevillePolynomialInterpolation(
const interpolated = cubicSplineInterpolation(
values.map((value, i) => ({ x: HeizLast[i], y: value })),
values.length
heizlast
)
interpolations.push(interpolate(heizlast))
interpolations.push(interpolated)
}
const interpolate = nevillePolynomialInterpolation(
const interpolated = cubicSplineInterpolation(
interpolations.map((interpolation, i) => {
return {
x: Object.keys(data)[i],
y: interpolation
}
}),
interpolations.length
zeitkonstane
)
<<<<<<< HEAD
return interpolate(zeitkonstane)
}
console.log(funktionMonatlicherBelastungsgrad(125, 90, "Januar"))
=======
return interpolated
}
>>>>>>> 01b701c (Neville Ausgetauscht + PDF)

View File

@@ -0,0 +1,206 @@
import { PDFPage } from 'pdf-lib';
import { PDFElement, Size } from './PDFElement.js';
import { Margin, Padding } from './Layout.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[];
margin?: Margin,
padding?: Padding
}
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(private 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 ?? [];
this.padding = options.padding || { top: 0, left: 0, right: 0, bottom: 0}
this.margin = options.margin || { top: 0, left: 0, right: 0, bottom: 0}
}
addChild(...children: PDFElement[]): void {
this.children.push(...children)
}
get height(): number {
if (typeof this._height === "number") {
return this._height + this.padding.top + this.padding.bottom;
}
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 + this.padding.bottom + this.padding.top;
}
set width(value: Size) {
this._width = value;
}
get width(): number {
return this.innerWidth + this.padding.left + this.padding.right
}
get innerWidth() {
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 + this.margin.left + this.padding.left, y - this.margin.top - this.padding.top);
// 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);
// 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 remainingSpace =
this.direction === 'row' ? this.width - totalChildrenSize - totalGaps : this.height - totalChildrenSize - totalGaps;
let childX = this.direction === 'row' ? currentX : currentX + this.calculateAlignOffset(child.width);
let childY = this.direction === 'row' ? currentY - this.calculateAlignOffset(child.height) : currentY;
if (this.direction === "row") {
currentX += child.width + this.gap;
switch (this.justifyContent) {
case 'center':
childX += remainingSpace / 2;
break;
case 'end':
childX += remainingSpace;
break;
case 'space-between':
currentX += (this.innerWidth - totalChildrenSize - totalGaps) / (this.children.length - 1);
break;
case 'space-around':
const adjustment = remainingSpace / (this.children.length + 1);
childX += adjustment;
currentX += adjustment;
break;
case 'start':
default:
break;
}
}
if (this.direction === 'column') {
currentY -= child.height + this.gap;
switch (this.justifyContent) {
case 'center':
childY -= remainingSpace / 2;
break;
case 'end':
childY -= remainingSpace;
break;
case 'space-between':
currentY -= (this.innerHeight - totalChildrenSize - totalGaps) / (this.children.length - 1);
break;
case 'space-around':
const adjustment = remainingSpace / (this.children.length + 1);
childY -= adjustment;
currentY -= adjustment;
break;
case 'start':
default:
break;
}
}
positions.push({ x: childX, y: childY });
});
return positions;
}
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;
}
}
}

View File

@@ -0,0 +1,79 @@
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 {
public margin: Margin
public padding: Padding
protected _height: Size = "auto";
protected _width: Size = "auto";
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 + child.margin.top + child.margin.bottom;
}
}
addChild(...children: PDFElement[]): void {
this.children.push(...children)
}
}
export function layout(...args: ConstructorParameters<typeof Layout>) {
return new Layout(...args);
}

View File

@@ -0,0 +1,38 @@
import { PDFPage } from "pdf-lib";
import { Margin, Padding } from "./Layout.js";
export type Size = number | "auto";
export abstract class PDFElement {
protected _height: Size = 0;
protected _width: Size = 0;
public margin: Margin = { top: 0, bottom: 0, left: 0, right: 0 };
public padding: Padding = { top: 0, bottom: 0, left: 0, right: 0 };
get width(): number {
return this.innerWidth + this.padding.left + this.padding.right;
}
set width(value: Size) {
this._width = value;
}
get innerWidth() {
return this._width === "auto" ? 0 : this._width;
}
get height(): number {
return this.innerHeight + this.padding.top + this.padding.bottom;
}
set height(value: Size) {
this._height = value;
}
get innerHeight() {
return this._height === "auto" ? 0 : this._height;
}
abstract draw(page: PDFPage, x: number, y: number): void;
abstract addChild(...children: PDFElement[]): void;
}

View File

@@ -0,0 +1,61 @@
import { PDFPage, PDFFont, rgb, RGB } from 'pdf-lib';
import { PDFElement, Size } from './PDFElement.js';
import { Margin, Padding } from './Layout.js';
export interface TextOptions {
font: PDFFont;
fontSize?: number;
color?: RGB;
margin?: Margin,
padding?: Padding,
lineHeight?: number
}
export class Text extends PDFElement {
private content: string;
private font: PDFFont;
private fontSize: number;
private color: RGB;
private options: TextOptions
protected _width: number;
protected _height: number;
public padding: Padding
public margin: Margin
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 = options.lineHeight || this.font.heightAtSize(this.fontSize);
this.options = options;
this.margin = this.options.margin || { top: 0, left: 0, right: 0, bottom: 0}
this.padding = this.options.padding || { top: 0, left: 0, right: 0, bottom: 0}
}
addChild(...children: PDFElement[]): void {
throw new Error("Cannot add child element to Text")
}
get height() {
return this._height + this.padding.top + this.padding.bottom;
}
get width() {
return this._width + this.padding.left + this.padding.right;
}
draw(page: PDFPage, x: number, y: number): void {
page.drawText(this.content, {
x: x + this.margin.left + this.padding.left,
y: y - this.height - this.margin.top - this.padding.top,
size: this.fontSize,
font: this.font,
color: this.color
});
}
}

View File

@@ -0,0 +1,140 @@
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, fonts: Record<string, PDFFont> & { "default": PDFFont }) {
const tree = txml.parse(xml)
const iterateChildren = (children: ReturnType<typeof txml.parse>, parent: PDFElement) => {
for (const child of children) {
if (typeof child === "string") {
// Simple text
parent.addChild(new Text(child, { font: fonts["default"] }))
} 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,
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, 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("font") ? fonts[child.attributes["font"]] : fonts["default"], lineHeight: parseFloat(child.attributes.lineHeight), fontSize: parseFloat(child.attributes.size) || 10, color, 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,
} })
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)
// console.log(page.getWidth(), "WIDTH");
// const layout = xml2pdf(`
// <flex direction="column" justify="end" width="${page.getWidth()}" height="${page.getHeight()}">
// <flex direction="row" gap="5" align="center">
// <checkbox width="8" height="8"></checkbox>
// <text size="12">awd1</text>
// </flex>
// <flex direction="row" gap="5" align="center">
// <checkbox width="8" height="8"></checkbox>
// <text size="12">awd2</text>
// </flex>
// <flex direction="row" gap="5" align="center">
// <checkbox width="8" height="8"></checkbox>
// <text size="12">awd3</text>
// </flex>
// <flex direction="row" gap="5" align="center">
// <checkbox width="8" height="8"></checkbox>
// <text size="12">awd4</text>
// </flex>
// </flex>`, {
// "default": 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())

View File

@@ -0,0 +1,176 @@
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";
import { xml2pdf } from "./elements/xml2pdf.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"
};
const layout = xml2pdf(`<layout height="${pages[0].getHeight()}" width="${pages[0].getWidth()}" marginTop="150" marginLeft="45" marginRight="45">
<text size="12" lineHeight="14">${benutzer.vorname} ${benutzer.name}</text>
<text size="12" lineHeight="14">${benutzer.adresse}</text>
<text size="12" lineHeight="14">${benutzer.plz} ${benutzer.ort}</text>
<flex direction="row" justify="space-between" marginTop="55" width="${pages[0].getWidth() - 90}">
<text size="12" font="bold">Datenblatt Energieausweis</text>
<text size="12">Ausweis ID: ${ausweis.uid}</text>
</flex>
<text size="12" lineHeight="14" font="bold" marginTop="10">Gebäudedaten</text>
<text size="12" lineHeight="14">Adresse: ${ausweis.gebaeude_aufnahme_allgemein.adresse}, ${ausweis.gebaeude_aufnahme_allgemein.plz} ${ausweis.gebaeude_aufnahme_allgemein.ort}</text>
<flex direction="row" justify="space-between" width="${pages[0].getWidth() - 90}" marginTop="25">
<flex direction="row" gap="5" align="center">
<checkbox width="8" height="8"></checkbox>
<text size="12">Neubau</text>
</flex>
<flex direction="row" gap="5" align="center">
<checkbox width="8" height="8"></checkbox>
<text size="12">Vermietung/Verkauf</text>
</flex>
<flex direction="row" gap="5" align="center">
<checkbox width="8" height="8"></checkbox>
<text size="12">Modernisierung</text>
</flex>
<flex direction="row" gap="5" align="center">
<checkbox width="8" height="8"></checkbox>
<text size="12">Sonstiges</text>
</flex>
</flex>
<flex direction="row" marginTop="25" gap="15">
<flex direction="column" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
<text size="12" lineHeight="14">Gebäudetyp:</text>
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.gebaeudetyp}</text>
</flex>
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
<text size="12" lineHeight="14">Wohnfläche:</text>
<text size="12" lineHeight="14">DIN Wohnfläche innen ${ausweis.gebaeude_aufnahme_allgemein.flaeche} m²</text>
</flex>
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
<text size="12" lineHeight="14">Leerstand:</text>
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.leerstand || 0}%</text>
</flex>
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
<text size="12" lineHeight="14">Wohnungen:</text>
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.einheiten}</text>
</flex>
</flex>
<flex direction="column" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
<text size="12" lineHeight="14">Dachgeschoss:</text>
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.dachgeschoss}</text>
</flex>
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
<text size="12" lineHeight="14">Keller:</text>
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.keller}</text>
</flex>
</flex>
</flex>
</layout>`, {
"default": font,
bold: bold
})
layout.draw(pages[0], 0, pages[0].getHeight())
// 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();
}

BIN
test-pdf.pdf Normal file

Binary file not shown.