From 57c4b6f2041ee49ab4472641f9dc4925c95bbe7a Mon Sep 17 00:00:00 2001 From: adrianbonpin Date: Tue, 18 Aug 2026 19:56:06 +0800 Subject: [PATCH] fix: match reference layout geometry (margins, student row zones, column spread, spacing) --- pdf.js | 54 ++++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/pdf.js b/pdf.js index f908553..6c4e3c5 100644 --- a/pdf.js +++ b/pdf.js @@ -101,9 +101,9 @@ const font = doc.embedStandardFont(StandardFonts.Helvetica); const bold = doc.embedStandardFont(StandardFonts.HelveticaBold); const italic = doc.embedStandardFont(StandardFonts.HelveticaOblique); - const margin = 50; - const contentWidth = 612 - margin * 2; - let y = 792 - 50; + const margin = 36; + const contentWidth = 612 - margin * 2; // 540; right edge = 576 + let y = 792 - 10; // near the very top, matching the reference logo position const black = rgb(0, 0, 0); const gray = rgb(0.3, 0.3, 0.3); @@ -132,7 +132,7 @@ const logoW = 292.5; const logoH = logoW * (logoImg.height / logoImg.width); page.drawImage(logoImg, { x: (612 - logoW) / 2, y: y - logoH, width: logoW, height: logoH }); - y -= logoH + 14; + y -= logoH + 10; } center("STUDENT'S STUDY LOAD", 9.5, bold, 16); if (header.semester) center(String(header.semester).toUpperCase(), 9, font, 14); @@ -140,34 +140,32 @@ if (dateRange) center(dateRange, 9, font, 14); if (header.dateEnrolled) left('Date Enrolled: ' + header.dateEnrolled, 8, italic, margin, 13); - // Student info row: ID (bold), name, program (compacted), "Year Level: N" - const studentParts = []; - if (header.studentId) studentParts.push({ text: header.studentId, f: bold }); - if (header.fullName) studentParts.push({ text: header.fullName, f: font }); - if (header.program) studentParts.push({ text: compactProgram(header.program), f: font }); - if (header.yearLevel) studentParts.push({ text: 'Year Level: ' + header.yearLevel, f: font }); - if (studentParts.length) { - let sx = margin; - for (const part of studentParts) { - const w = part.f.widthOfTextAtSize(part.text, 9); - page.drawText(part.text, { x: sx, y, size: 9, font: part.f, color: black }); - sx += w + 18; - } - y -= 16; + // Student info row, laid out in fixed zones across the page (matching the + // reference): ID (bold) left, name at ~100, program at ~338, and + // "Year Level: N" right-aligned to the right content edge (576). + const yearLevelText = header.yearLevel ? 'Year Level: ' + header.yearLevel : ''; + if (header.studentId) page.drawText(header.studentId, { x: margin, y, size: 9, font: bold, color: black }); + if (header.fullName) page.drawText(header.fullName, { x: 100, y, size: 9, font, color: black }); + if (header.program) page.drawText(compactProgram(header.program), { x: 338, y, size: 9, font, color: black }); + if (yearLevelText) { + const w = font.widthOfTextAtSize(yearLevelText, 9); + page.drawText(yearLevelText, { x: margin + contentWidth - w, y, size: 9, font, color: black }); } + if (header.studentId || header.fullName || header.program || yearLevelText) y -= 16; // ---- Table: GROUP, COURSE, COURSE DESCRIPTION, TEACHER, UNITS, NOTE ---- + // Column left edges + widths, tuned to the reference geometry (right edge 576). const cols = [ - { key: 'group', label: 'GROUP', x: margin, w: 26, align: 'left' }, - { key: 'courseCode', label: 'COURSE', x: margin + 26, w: 46, align: 'left' }, - { key: 'description', label: 'COURSE DESCRIPTION', x: margin + 72, w: 189, align: 'left' }, - { key: 'teacher', label: 'TEACHER', x: margin + 261, w: 123, align: 'left' }, - { key: 'units', label: 'UNITS', x: margin + 384, w: 31, align: 'right' }, - { key: 'status', label: 'NOTE', x: margin + 415, w: 97, align: 'right' } + { key: 'group', label: 'GROUP', x: margin, w: 38, align: 'left' }, + { key: 'courseCode', label: 'COURSE', x: margin + 38, w: 42, align: 'left' }, + { key: 'description', label: 'COURSE DESCRIPTION', x: margin + 80, w: 201, align: 'left' }, + { key: 'teacher', label: 'TEACHER', x: margin + 281, w: 128, align: 'left' }, + { key: 'units', label: 'UNITS', x: margin + 409, w: 31, align: 'right' }, + { key: 'status', label: 'NOTE', x: margin + 440, w: 100, align: 'right' } ]; const cellSize = 8; const headerSize = 8; - const lineH = 10; + const lineH = 12; function rowLines(cells) { return cols.map((c) => { @@ -187,11 +185,11 @@ const f = isHeader ? bold : font; const size = isHeader ? headerSize : cellSize; const linesPerCol = rowLines(cells); - const rowHeight = Math.max(...linesPerCol.map((l) => l.length)) * lineH + 8; + const rowHeight = Math.max(...linesPerCol.map((l) => l.length)) * lineH + 12; if (y - rowHeight < 50) { page = doc.addPage([612, 792]); - y = 792 - 50; + y = 792 - 10; drawHeaderRow(); } @@ -246,7 +244,7 @@ // ---- Footer ---- if (y < 90) { page = doc.addPage([612, 792]); - y = 792 - 50; + y = 792 - 10; } y -= 8; if (data.totalUnits) {