This sample shows how to create a tagged PDF using the Expense Report sample as a base.
The sample uses the info.title, tagged, displayTitle and lang properties to satisfy the basic Tagged PDF requirements when creating the instance of the PdfDocument class.
The sample uses the tag method to create tags and mark content and the addTag method to add tags to the logical document tree. The artifact method is used to mark decorative content as artifacts.
Note: Tagged PDF requires document version 1.4 or higher.
import 'bootstrap.css';
import './styles.css';
import * as wijmo from '@mescius/wijmo';
import * as pdf from '@mescius/wijmo.pdf';
import { getEmployees } from './data';
//
var TableSection;
(function (TableSection) {
TableSection[TableSection["header"] = 0] = "header";
TableSection[TableSection["body"] = 1] = "body";
TableSection[TableSection["footer"] = 2] = "footer";
})(TableSection || (TableSection = {}));
//
document.readyState === 'complete' ? init() : window.onload = init;
//
function init() {
document.querySelector('#btnExport').addEventListener('click', () => {
let doc = new pdf.PdfDocument({
info: {
title: 'Expense Report'
},
tagged: true,
displayTitle: true,
lang: 'en-US',
version: pdf.PdfVersion.v1_5,
// The header will be automatically marked as a pagination artifact.
header: {
declarative: {
text: 'Expense Report\t&[Page]\\&[Pages]',
font: new pdf.PdfFont('times', 12),
brush: '#bfc1c2'
}
},
lineGap: 2,
pageSettings: {
margins: {
left: 36,
right: 36,
top: 36,
bottom: 36
}
},
ended: (_, args) => pdf.saveBlob(args.blob, 'Document.pdf')
});
//
getEmployees().forEach((employee, i, arr) => {
drawEmployee(doc, employee);
//
if (i < arr.length - 1) {
doc.addPage();
}
});
//
doc.end();
});
}
//
const ColWidth = 80, RowHeight = 18, ThinPen = new pdf.PdfPen('#000000', 0.5);
//
function drawEmployee(doc, employee) {
let tot = employee.expenses.totals, expenses = employee.expenses.items.sort((a, b) => a.date.getTime() - b.date.getTime()), minDate = expenses[0].date, maxDate = expenses[expenses.length - 1].date, columns = [
{ header: 'Date', binding: 'date', format: 'd' },
{ header: 'Description', binding: 'description', format: 'c' },
{ header: 'Hotel', binding: 'hotel', format: 'c' },
{ header: 'Transport', binding: 'transport', format: 'c' },
{ header: 'Meal', binding: 'meal', format: 'c' },
{ header: 'Fuel', binding: 'fuel', format: 'c' },
{ header: 'Misc', binding: 'misc', format: 'c' },
{ header: 'Total', binding: 'total', format: 'c' }
], bold = new pdf.PdfFont('times', 10, 'normal', 'bold');
//
// * draw captions *
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('Purpose: ', null, null, { font: bold, continued: true });
doc.drawText(employee.purpose);
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('From: ', 380, 0, { font: bold, continued: true });
doc.drawText(wijmo.changeType(minDate, wijmo.DataType.String, 'd'));
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('To: ', 470, 0, { font: bold, continued: true });
doc.drawText(wijmo.changeType(maxDate, wijmo.DataType.String, 'd'));
}));
//
doc.moveDown(2);
//
let y = doc.y;
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('Name: ', 20, y, { font: bold, continued: true });
doc.drawText(employee.name);
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('Position: ', 190, y, { font: bold, continued: true });
doc.drawText(employee.position);
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('SSN: ', 360, y, { font: bold, continued: true });
doc.drawText(employee.ssn);
}));
//
y = doc.y;
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('Department: ', 20, y, { font: bold, continued: true });
doc.drawText(employee.department);
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('Manager: ', 190, y, { font: bold, continued: true });
doc.drawText(employee.manager);
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('Employee ID: ', 360, y, { font: bold, continued: true });
doc.drawText(employee.id);
}));
//
doc.moveDown(2);
//
// * draw table *
doc.saveState();
//
y = 0;
let scale = doc.width / (columns.length * ColWidth), docY = doc.y;
//
if (scale > 1) {
scale = 1;
}
//
doc.scale(scale, scale, new wijmo.Point(0, docY));
doc.translate(0, docY);
//
let thead = doc.tag(pdf.PdfTagType.THead), tbody = doc.tag(pdf.PdfTagType.TBody), tfoot = doc.tag(pdf.PdfTagType.TFoot), table = doc.tag(pdf.PdfTagType.Table);
//
doc.addTag(table);
table.add(thead);
table.add(tbody);
table.add(tfoot);
//
// header
thead.add(renderRow(doc, TableSection.header, y, columns, (column) => column.header, null, bold, '#fad9cd'));
y = RowHeight;
//
// body
expenses.forEach(item => {
tbody.add(renderRow(doc, TableSection.body, y, columns, (column) => item[column.binding], (column) => column.format));
y += RowHeight;
});
//
// footer
let totRow = ['Total', '', tot.hotel, tot.transport, tot.meal, tot.fuel, tot.misc, tot.total];
tfoot.add(renderRow(doc, TableSection.footer, y, totRow, null, () => 'c', bold, '#fad9cd'));
y += RowHeight;
//
doc.y = docY + y * scale;
//
doc.restoreState();
//
doc.moveDown(2);
//
// * draw captions *
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('Subtotal: ', 400, doc.y, { font: bold, continued: true });
doc.drawText(wijmo.changeType(tot.total - employee.advance, wijmo.DataType.String, 'c'));
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('Cash Advance: ', 400, doc.y, { font: bold, continued: true });
doc.drawText(wijmo.changeType(employee.advance, wijmo.DataType.String, 'c'));
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('Total: ', 400, doc.y, { font: bold, continued: true });
doc.drawText(wijmo.changeType(tot.total, wijmo.DataType.String, 'c'));
}));
//
doc.moveDown(2);
checkLineAvailable(doc);
//
y = doc.y;
textWithPlaceholder(doc, 0, y, 'Employee signature:', 150);
textWithPlaceholder(doc, 300, y, 'Date:', 75);
//
doc.moveDown();
checkLineAvailable(doc);
//
y = doc.y;
textWithPlaceholder(doc, 0, y, 'Approved by:', 150);
textWithPlaceholder(doc, 300, y, 'Date:', 75);
}
//
function checkLineAvailable(doc) {
if (doc.height - doc.y < doc.lineHeight() + doc.lineGap) {
doc.addPage();
}
}
//
function renderRow(doc, section, y, values, valueGetter, formatGetter, font, brush) {
let trTag = doc.tag(pdf.PdfTagType.TR);
//
values.forEach((v, idx) => {
let x = idx * ColWidth;
//
doc.artifact(() => doc.paths.rect(x, y, ColWidth, RowHeight).fill(brush || '#f4b19b'), { type: pdf.PdfArtifactType.Layout });
//
let value = valueGetter != null ? valueGetter(v) : v || '', format = formatGetter != null ? formatGetter(v) : '';
//
if (value !== 'Total') {
value = wijmo.changeType(value, wijmo.DataType.String, format);
}
//
trTag.add(doc.tag(section === TableSection.header ? pdf.PdfTagType.TH : pdf.PdfTagType.TD, doc.tag(pdf.PdfTagType.P, () => {
doc.drawText(value, x + 3, y + 5, {
font: font,
height: RowHeight,
width: ColWidth
});
})));
});
//
return trTag;
}
//
function textWithPlaceholder(doc, x, y, text, placeholderWidth) {
let sz;
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
sz = doc.drawText(text, x, y);
}));
//
doc.artifact(() => {
doc.paths
.moveTo(x + sz.size.width, doc.y)
.lineTo(x + sz.size.width + placeholderWidth, doc.y)
.stroke(ThinPen);
});
}
Submit and view feedback for