이 샘플은 경비 보고서 샘플을 기반으로 태그가 지정된 PDF를 만드는 방법을 보여줍니다.
샘플은 PdfDocument 클래스의 인스턴스를 생성할 때, 기본 Tagged PDF 요구 사항을 충족하기 위해 info.title, tagged, displayTitle 및 lang 속성을 사용합니다.
샘플에서는 tag 메서드를 사용하여 태그를 만들고 콘텐츠를 표시하고, addTag 메서드를 사용하여 문서 트리에 해당 태그들을 추가합니다.
artifact 매서드는 콘텐츠를 꾸밀때 사용한 요소를 아티팩트로 표시하는 데 사용됩니다.
참고: 태그가 지정된 PDF에는 문서 버전 1.4 이상이 필요합니다.
import 'bootstrap.css';
import '@mescius/wijmo.styles/wijmo.css';
import './styles.css';
//
import * as wijmo from '@mescius/wijmo';
import * as grid from '@mescius/wijmo.grid';
import * as chart from '@mescius/wijmo.chart';
import '@mescius/wijmo.chart.render';
import * as pdf from '@mescius/wijmo.pdf';
import * as gridPdf from '@mescius/wijmo.grid.pdf';
//
import { getEmployee } from './data';
//
document.readyState === 'complete' ? init() : window.onload = init;
//
function init() {
let employee = getEmployee();
//
let flexGrid = new grid.FlexGrid('#flexGrid', {
autoGenerateColumns: false,
headersVisibility: grid.HeadersVisibility.Column,
allowMerging: grid.AllowMerging.All,
itemsSource: employee.expenses.items,
columns: [
{ header: 'Date', binding: 'date', format: 'd', minWidth: 80 },
{ header: 'Hotel', binding: 'hotel', format: 'c' },
{ header: 'Transport', binding: 'transport', format: 'c', minWidth: 80 },
{ header: 'Meal', binding: 'meal', format: 'c' },
{ header: 'Fuel', binding: 'fuel', format: 'c' },
{ header: 'Misc', binding: 'misc', format: 'c' }
]
});
//
let flexPie = new chart.FlexPie('#flexPie', {
itemsSource: ((totals) => [
{ name: 'Hotel', value: totals.hotel },
{ name: 'Transport', value: totals.transport },
{ name: 'Meal', value: totals.meal },
{ name: 'Fuel', value: totals.fuel },
{ name: 'Misc', value: totals.misc }
])(employee.expenses.totals),
binding: 'value',
bindingName: 'name',
innerRadius: 0.75,
dataLabel: {
content: '{value:c1}',
position: chart.PieLabelPosition.Inside
}
});
//
document.querySelector('#btnExport').addEventListener('click', () => {
let doc = new pdf.PdfDocument({
info: {
title: 'Expense Analysis 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 Analysis Report',
font: new pdf.PdfFont('times', 12),
brush: '#bfc1c2'
}
},
lineGap: 2,
pageSettings: {
margins: {
left: 12,
right: 12,
top: 12,
bottom: 12
}
},
ended: (_, args) => pdf.saveBlob(args.blob, 'FlexGrid.pdf')
});
//
drawText(doc);
//
drawEmployee(doc, flexGrid, flexPie, employee, () => {
doc.artifact(() => drawWatermark(doc), { type: pdf.PdfArtifactType.Pagination });
doc.end();
});
});
}
//
function drawText(doc) {
doc.addTag(doc.tag(pdf.PdfTagType.H1, () => {
doc.drawText('What is an expense report?', undefined, undefined, {
font: new pdf.PdfFont('times', 20, 'normal', 'bold')
});
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText(`An expense report is a form of document that contains all the expenses that an
individual has incurred as a result of the business operation. For example, if the owner of a business
travels to another location for a meeting, the cost of travel, the meals, and all other expenses that
he/she has incurred may be added to the expense report.`.replace(/\n/g, ''));
}));
}
//
function drawEmployee(doc, flexGrid, flexPie, employee, done) {
let expenses = employee.expenses.items.sort((a, b) => a.date.getTime() - b.date.getTime()), minDate = expenses[0].date, maxDate = expenses[expenses.length - 1].date, bold = new pdf.PdfFont('times', 10, 'normal', 'bold');
//
doc.moveDown(2);
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('Name: ', undefined, undefined, { font: bold, continued: true });
doc.drawText(employee.name);
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('From: ', undefined, undefined, { font: bold, continued: true });
doc.drawText(wijmo.changeType(minDate, wijmo.DataType.String, 'd'));
}));
//
doc.addTag(doc.tag(pdf.PdfTagType.P, () => {
doc.drawText('To: ', undefined, undefined, { 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('Expense details:', 0, y);
}));
//
gridPdf.FlexGridPdfConverter.draw(flexGrid, doc, doc.width * 0.5, null, {
styles: {
cellStyle: {
backgroundColor: '#ffffff',
borderColor: '#c6c6c6'
},
altCellStyle: {
backgroundColor: '#f9f9f9'
},
groupCellStyle: {
font: { weight: 'bold' },
backgroundColor: '#dddddd'
},
headerCellStyle: {
backgroundColor: '#eaeaea'
}
}
});
//
flexPie.saveImageToDataUrl(chart.ImageFormat.Png, (url) => {
doc.addTag(doc.tag(pdf.PdfTagType.Figure, [
doc.tag(pdf.PdfTagType.Caption, () => {
doc.drawText('Total expenses by category:', doc.width * 0.5 + 20, y);
}),
() => {
doc.drawImage(url, doc.width * 0.5 + 20, doc.y, { width: doc.width * 0.5 - 20 });
}
], { actual: 'The chart' }));
// Finish the document.
done();
});
}
//
function drawWatermark(doc) {
let docX = doc.x, docY = doc.y, font = new pdf.PdfFont('times', 120), color = wijmo.Color.fromRgba(59, 59, 109, 0.05), pgc = new wijmo.Point(doc.width / 2, doc.height / 2), text = 'Wijmo', offs = 10;
//
doc.x = 0;
doc.y = 0;
//
let sz = doc.measureText(text, font), szCx = sz.size.width / 2, szCy = sz.size.height / 2;
//
doc.saveState();
//
doc.rotate(45, pgc);
//
doc.drawText(text, pgc.x - szCx, pgc.y - szCy, {
font: font,
brush: color,
baseline: pdf.PdfTextBaseline.Top
});
//
doc.paths
.rect(pgc.x - szCx - offs, pgc.y - szCy - offs, sz.size.width + 2 * offs, sz.size.height - offs)
.stroke(new pdf.PdfPen(color, 10));
//
doc.restoreState();
//
doc.x = docX;
doc.y = docY;
}