Tectum v0.4.0 — mijlpaal gevelopbouw
Configurator voor Van Emous Mantelzorgwoningen: wanden, vloeren, units, woningen (L-vorm), plat dak met dakrand, buitenverlichting, latwerk op vochtdoek, trasraam, sandwichpanelen en PDF-tekenbladen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
/*!
|
||||
* Tectum
|
||||
* Copyright © 2026 Machiel Heinen.
|
||||
* Alle rechten voorbehouden. Gebruik uitsluitend met schriftelijke toestemming.
|
||||
* Zie LICENTIE.md.
|
||||
*/
|
||||
// ============================================================
|
||||
// core/pdf-sheet.js — gedeelde bouwstenen voor de A3-tekenbladen (jsPDF):
|
||||
// kleuren, nieuw document, maatlijn en titelblok. Gebruikt door WallPdf,
|
||||
// FloorPdf en de unit-PDF, zodat elk blad er identiek uitziet.
|
||||
// Plain script (geen ES-module), geladen na jspdf.umd.min.js.
|
||||
// ============================================================
|
||||
|
||||
window.PdfSheet = (() => {
|
||||
// Kleurlogica: rood = houtwerk-omtrekken, blauw = hoofdmaatvoering,
|
||||
// zwart = opening-kruis, posnum-labels en de onderste maatketens.
|
||||
const COLORS = { RED: [190, 25, 25], BLUE: [25, 50, 180], BLACK: [0, 0, 0], GREY: [130, 130, 130] };
|
||||
|
||||
// Veldnamen van de "Project eigenschappen"-modal van de wand-/vloer-editor.
|
||||
const PROJECT_DOM_IDS = {
|
||||
naam: 'inp-proj-naam', plaats: 'inp-proj-plaats', straat: 'inp-proj-straat', nummer: 'inp-proj-nummer',
|
||||
tekenaar: 'inp-proj-tekenaar', titel: 'inp-proj-titel', element: 'inp-proj-element', opmerking: 'inp-proj-opmerking'
|
||||
};
|
||||
|
||||
function createDoc() {
|
||||
const { jsPDF } = window.jspdf;
|
||||
return new jsPDF({ orientation: 'landscape', unit: 'mm', format: 'a3' });
|
||||
}
|
||||
|
||||
function readProjectFromDom() {
|
||||
const project = {};
|
||||
Object.entries(PROJECT_DOM_IDS).forEach(([key, id]) => {
|
||||
const el = document.getElementById(id);
|
||||
project[key] = (el && el.value) || '';
|
||||
});
|
||||
return project;
|
||||
}
|
||||
|
||||
// Maatlijn met kleine loodrechte eindstreepjes ("|") op beide
|
||||
// uiteinden, zodat duidelijk is waar de maat precies begint/eindigt
|
||||
// i.p.v. een lijn die zonder markering in de lucht lijkt te eindigen.
|
||||
const DIM_TICK = 1.5;
|
||||
function dimLine(doc, x1, y1, x2, y2) {
|
||||
doc.line(x1, y1, x2, y2);
|
||||
const dx = x2 - x1, dy = y2 - y1;
|
||||
const len = Math.hypot(dx, dy) || 1;
|
||||
const tx = (-dy / len) * (DIM_TICK / 2), ty = (dx / len) * (DIM_TICK / 2);
|
||||
doc.line(x1 - tx, y1 - ty, x1 + tx, y1 + ty);
|
||||
doc.line(x2 - tx, y2 - ty, x2 + tx, y2 + ty);
|
||||
}
|
||||
|
||||
// Titelblok (rechtsonder), in twee kolommen zodat het weinig hoogte
|
||||
// inneemt, met het logo (core/logo-data.js) rechtsonder.
|
||||
// project: { naam, plaats, straat, nummer, tekenaar, opmerking };
|
||||
// opts: { titel, element, blad } (blad bijv. "2 / 7").
|
||||
function titleBlock(doc, project, opts) {
|
||||
const { BLACK, GREY } = COLORS;
|
||||
const p = project || {};
|
||||
const o = opts || {};
|
||||
const tbW = 118, tbH = 36;
|
||||
const tbX0 = 290, tbY0 = 289 - tbH;
|
||||
doc.setDrawColor(...BLACK);
|
||||
doc.setLineWidth(0.25);
|
||||
doc.rect(tbX0, tbY0, tbW, tbH, 'S');
|
||||
|
||||
const today = new Date().toLocaleDateString('nl-NL');
|
||||
const columns = [
|
||||
[['Projectnaam:', p.naam], ['Plaats:', p.plaats], ['Straat:', p.straat], ['Projectnummer:', p.nummer], ['Tekenaar:', p.tekenaar]],
|
||||
[['Titel:', o.titel], ['Element nummer:', o.element], ['Datum getekend:', today], ['Schaal:', '1:1'], ['Opmerking:', p.opmerking]]
|
||||
];
|
||||
const colW = tbW / 2, labelW = 19;
|
||||
doc.setFontSize(6.2);
|
||||
columns.forEach((rows, c) => {
|
||||
const x = tbX0 + 3 + c * colW;
|
||||
let rowY = tbY0 + 5;
|
||||
rows.forEach(([label, value]) => {
|
||||
doc.setTextColor(...GREY);
|
||||
doc.text(label, x, rowY);
|
||||
doc.setTextColor(...BLACK);
|
||||
const text = String(value || '-');
|
||||
doc.text(doc.splitTextToSize(text, colW - labelW - 5)[0], x + labelW, rowY);
|
||||
rowY += 4.2;
|
||||
});
|
||||
});
|
||||
|
||||
// Scheidingslijn + onderstrook: blad links, logo rechts.
|
||||
const stripY = tbY0 + 25;
|
||||
doc.setDrawColor(...GREY);
|
||||
doc.setLineWidth(0.15);
|
||||
doc.line(tbX0, stripY, tbX0 + tbW, stripY);
|
||||
if (o.blad) {
|
||||
doc.setTextColor(...GREY);
|
||||
doc.setFontSize(6);
|
||||
doc.text('Blad ' + o.blad, tbX0 + 3, tbY0 + tbH - 3.5);
|
||||
}
|
||||
const logoH = 7.5, logoW = logoH * (window.TECTUM_LOGO ? window.TECTUM_LOGO.aspect : 4.55);
|
||||
if (window.TECTUM_LOGO) {
|
||||
doc.addImage(window.TECTUM_LOGO.png, 'PNG', tbX0 + tbW - 3 - logoW, tbY0 + tbH - 2 - logoH, logoW, logoH, 'tectum-logo', 'FAST'); // alias: 1x in het bestand, gecomprimeerd
|
||||
} else {
|
||||
doc.setTextColor(...GREY);
|
||||
doc.setFontSize(6);
|
||||
doc.text('Van Emous Mantelzorgwoningen', tbX0 + tbW - 3, tbY0 + tbH - 3.5, { align: 'right' });
|
||||
}
|
||||
}
|
||||
|
||||
// Eenvoudige tabel: headers + rijen (arrays van strings) vanaf (x, y) met
|
||||
// vaste kolom-x'en. Geeft de y-positie onder de tabel terug.
|
||||
function table(doc, x, y, colX, headers, rows, opts) {
|
||||
const { BLACK, GREY } = COLORS;
|
||||
const o = opts || {};
|
||||
const rowH = o.rowH || 4.3;
|
||||
doc.setTextColor(...BLACK);
|
||||
if (o.title) {
|
||||
doc.setFontSize(o.titleSize || 9);
|
||||
doc.text(o.title, x, y);
|
||||
y += 6;
|
||||
}
|
||||
doc.setFontSize(o.fontSize || 6.5);
|
||||
headers.forEach((h, i) => doc.text(h, x + colX[i], y));
|
||||
y += 1.5;
|
||||
doc.setDrawColor(...GREY);
|
||||
doc.setLineWidth(0.15);
|
||||
doc.line(x, y, x + colX[colX.length - 1] + (o.lastColW || 14), y);
|
||||
y += 4;
|
||||
rows.forEach(r => {
|
||||
if (o.maxY && y > o.maxY) return;
|
||||
r.forEach((v, i) => doc.text(String(v), x + colX[i], y, i > 0 && o.alignRight ? { align: 'right' } : undefined));
|
||||
y += rowH;
|
||||
});
|
||||
return y;
|
||||
}
|
||||
|
||||
return { COLORS, createDoc, readProjectFromDom, dimLine, titleBlock, table };
|
||||
})();
|
||||
Reference in New Issue
Block a user