diff --git a/src/LayoutBuilder.js b/src/LayoutBuilder.js index b5feaf88b..b3c763ede 100644 --- a/src/LayoutBuilder.js +++ b/src/LayoutBuilder.js @@ -1072,7 +1072,7 @@ class LayoutBuilder { let rowTopPageY = this.cell._leftEndingCell._startingRowSpanY + this.cell._leftEndingCell._rowTopPageYPadding; return this.cell._leftEndingCell._rowTopPageY - rowTopPageY + this.cell._leftEndingCell._bottomY; } else { - if (this.cell.positions[0].pageNumber !== this.cell._leftEndingCell._lastPageNumber) { + if (this.cell._lastPageNumber !== this.cell._leftEndingCell._lastPageNumber) { return this.bottomY - this.cell._leftEndingCell._bottomY; } diff --git a/tests/integration/tables.spec.js b/tests/integration/tables.spec.js index 4568bbcc9..825eece9d 100644 --- a/tests/integration/tables.spec.js +++ b/tests/integration/tables.spec.js @@ -402,4 +402,64 @@ describe('Integration test: tables', function () { assert.ok(maxGap < 90, 'max gap between horizontal lines was ' + maxGap + 'pt, expected < 90pt'); }); + it('keeps rowSpan header verticalAlignment stable on repeated tables (#2925)', function () { + function createReportTable() { + var rows = [ + ['D-001', '500', '480', '-20', 'In Progress'], + ['D-002', '300', '350', '+50', 'Exceeded'], + ['D-003', '750', '750', '0', 'Achieved'], + ['D-004', '200', '180', '-20', 'Under Review'], + ['D-005', '400', '410', '+10', 'Achieved'] + ]; + + return { + margin: [0, 5, 0, 15], + table: { + headerRows: 2, + widths: ['auto', '*', '*', '*', 'auto'], + body: [ + [ + { text: 'Dept ID', style: 'tableHeader', rowSpan: 2, verticalAlignment: 'middle' }, + { text: 'Performance Indicators', style: 'tableHeader', colSpan: 3 }, + {}, + {}, + { text: 'Status', style: 'tableHeader', rowSpan: 2 } + ], + [{}, { text: 'Target', style: 'tableHeader' }, { text: 'Actual', style: 'tableHeader' }, { text: 'Gap', style: 'tableHeader' }, {}], + ...rows, + ...rows, + ...rows + ] + } + }; + } + + var content = []; + for (var i = 1; i <= 3; i++) { + content.push({ text: 'Statistical Report - Page ' + i, style: 'header' }); + content.push(createReportTable()); + if (i < 3) { + content.push({ text: '', pageBreak: 'after' }); + } + } + + var pages = testHelper.renderPages('A4', { + content, + styles: { + header: { fontSize: 18, bold: true, alignment: 'center' }, + tableHeader: { bold: true, fillColor: '#eeeeee' } + } + }); + + var viewHeights = pages.map(page => { + var verticalAlignmentMarker = page.items.find(node => node.type === 'beginVerticalAlignment'); + + return verticalAlignmentMarker.item.getViewHeight(); + }); + + assert.equal(pages.length, 3); + assert.deepEqual(viewHeights, [viewHeights[0], viewHeights[0], viewHeights[0]]); + assert.ok(viewHeights[0] > 0, 'rowSpan header view height must remain positive'); + }); + });