我对使用称为PDFmake的库生成的PDF表中的列有问题。有时我有很多列,所以我想将列宽更改为当前已自动设置为文本长度的静态值,但是我不能这样做-我在代码中所做的每一次宽度更改都是错误的,并且没有不能改变任何观点。
这是pdf-generator.ts文件:
declare var $;
declare var canvg;
declare var pdfMake;
/**
* This JS module provides PDF generating functionality.
*/
export class PdfGenerator {
private logger = new LoggerService('PdfGenerator');
scripts: any = {
'1': [
new Script('js/pdfmake/pdfmake.min.js')
],
'2': [
new Script('js/pdfmake/pdfmake.fonts.js')
]
};
constructor(private filters: FilterService, private scriptService: ScriptService) {
}
isInternetExplorer = this.isIE();
/**
* This function generates the PDF and saves it on user's disk.
*/
generatePDF(svg, database: Database, connectionState: EntityState<Connection>, statisticState: EntityState<StatisticData>, systemState: EntityState<System>, filteredData: FilteredData, tableColumns) {
Overlay.showOverlay();
from(this.scriptService.load(this.scripts['1']))
.pipe(
flatMap(response => from(this.scriptService.load(this.scripts['2']))),
tap(response => {
this.generatePDFDefinition(svg, database, connectionState, statisticState, systemState, filteredData, tableColumns, (pdfDefinition) => {
pdfMake.createPdf(pdfDefinition).download('Interface Scan.pdf');
Overlay.hideOverlay();
});
})
).subscribe();
}
/**
* This function processes current diagram SVG into a PNG in a form of a data URI.
* @param callback A function to invoke after processing the SVG. The first and the only argument is the PNG data URI.
*/
getDiagramAsPNG(svg, callback) {
const canv = this.isInternetExplorer ? canvg : undefined;
saveSvgAsPng.svgAsPngUri(document.getElementById('svg4'), {
height: svg.height(),
width: svg.width(),
/*
* This property is image quality - the higher the better.
* Be careful, as better images weigh a lot more.
* If CanvG is used, then use scale of 1,
* because CanvG misunderstands this property and changes image proportions. Use 2 otherwise.
*/
scale: canv ? 1 : 2,
encoderOptions: 1,
//CanvG only if IE
canvg: canv
}, callback);
}
/**
* This function generates a PDF definition for PDFMake.
* @param svg
* @param database
* @param callback A function to invoke after processing the SVG. The first and the only argument is the PDF definition.
*/
generatePDFDefinition(svg, database:Database, connectionState: EntityState<Connection>, statisticState: EntityState<StatisticData>, systemState: EntityState<System>, filteredData: FilteredData, tableColumns, callback) {
//Create base PDF definition
const pdf: any = {
pageSize: 'A4',
pageOrientation: 'landscape',
pageMargins: 0,
content: [],
styles: {},
/*
* Properties below are not configuration properties.
* They are put here to always have a reference with this PDF definition.
*/
pageWidth: 841.89, //Taken from PDFMake source
pageHeight: 595.28 //Taken from PDFMake source
};
//Set header and footer
this.getDiagramAsPNG(svg, (diagramPngUri) => {
//Set the diagram page definition
diagram(svg, diagramPngUri);
//Set the details table page definition
detailsTable();
//Invoke the callback function
callback(pdf);
});
/**
* This function sets the header definition.
*/
let header = () => {
/**
* This function formats given date as a string.
* @param date A date to format.
* @param withTime Whether the result string should contain time or not.
* @returns {string} A formatted date.
*/
let formatDate = (date, withTime = null) => {
//Make sure it is a date object
date = new Date(date);
//Get formatted date string
const year = date.getFullYear();
const month = date.getMonth() < 9 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1);
const day = date.getDate();
const dateString = [year, month, day].join('/');
if (withTime) {
//Get formatted time string
const hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours();
const minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes();
const seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
const timeString = [hours, minutes, seconds].join(':');
//Return both strings joined with a space
return [dateString, timeString].join(' ');
} else {
//Return only the date part
return dateString;
}
};
//Get current scan metadata
// const scan = this.ifs.selectedIfsScan();
//Create a style for the header
pdf.styles.header = {
fontSize: 10,
margin: [20, 20, 20, 0]
};
//Add header to the PDF
pdf.header = {
columns: [
{
text: 'Database \'' + database.name + '\'' ,
// text: 'Scan \'' + database.name + '\' from ' + formatDate(database.lastUpdate),
style: 'header'
},
{
text: 'Generated on ' + formatDate(Date.now(), true),
alignment: 'right',
style: 'header'
}
]
};
};
/**
* This function sets the footer definition.
*/
let footer = () => {
//Create a style for the footer
pdf.styles.footer = {
fontSize: 10,
margin: [20, 10, 20, 0]
};
/*
* Add footer to the PDF.
* It displays current page text in the bottom left corner, i.e.: "1 of 29".
*/
pdf.footer = (currentPage, pageCount) => {
return {
text: currentPage + ' of ' + pageCount,
style: 'footer'
};
};
};
/**
* This function adds a page with a diagram image to the PDF.
* @param diagramPngUri A diagram in a form of a PNG data URI.
*/
let diagram = (svg, diagramPngUri) => {
/*
* Compute image dimensions
*/
const diagramImageHeight = pdf.pageHeight;
const diagramImageWidth = svg.width() / svg.height() * pdf.pageHeight;
/*
* Add an image to the PDF.
* The image has no margins and fills the whole page.
* It fills page height and is centered horizontally.
* The horizontal overflow is hidden - the image is not stretched.
* The image should look nearly exactly as on the website.
*/
pdf.content.push({
image: diagramPngUri,
//Vertically: align to top, Horizontally: center.
absolutePosition: {
x: (pdf.pageWidth - diagramImageWidth) / 2,
y: (pdf.pageHeight - diagramImageHeight) / 2
},
//Fill page height, scale width
height: diagramImageHeight,
width: diagramImageWidth
});
};
/**
* This function adds a page with a details table to the PDF.
* If the details table is too long to be fit in one page,
* the rows that don't fill will be on the next page.
*/
let detailsTable = () => {
//Add needed styles to the PDF
pdf.styles.detailsTable = {
fontSize: 4,
};
pdf.styles.detailsTableHeader = {
bold: true,
fillColor: '#1abd9c',
color: '#ffffff'
};
const columnDefinitions = () => {
let columns = [];
tableColumns.columns.forEach(tableColumn => {
if(tableColumn.visible) {
columns.push({
text: tableColumn.name,
style: 'detailsTableHeader',
border: noBorders
})
}
});
return columns;
};
/*
* Create details table definition.
* Details table is wrapped in 'columns' to center it, as 'alignment' does not work.
* Do not remove '{width: "*", text: ""}' blocks, as they allow this trick to work.
*/
const noBorders = [false, false, false, false];
let pdfDetailsTable: any = {
columns: [
{width: '*', text: ''},
{
width: 'auto',
style: 'detailsTable',
table: {
headerRows: 1,
width: new Array(tableColumns.columns.filter(column => column.visible).length).fill('auto'),
body: new Array(columnDefinitions())
},
layout: {
hLineColor: '#d2d2d2',
vLineColor: '#d2d2d2',
hLineWidth: () => {
return 0.5;
},
vLineWidth: () => {
return 0.5;
}
},
pageBreak: 'before'
},
{width: '*', text: ''}
]
};
/*
* Fill the details table with proper content.
* The data is fetched directly from the details table on the website,
* so all filters, sorting and value formatting will be the same in PDF.
*/
const noTopBorder = [true, false, true, true];
const body = pdfDetailsTable.columns[1].table.body;
const getSystemFieldValue = (field, connection: Connection) => {
const system = connection[field.indexOf('sender') !== -1 ? 'sender' : 'receiver']
if(systemState.entities[system]) {
return systemState.entities[system][field.replace(/sender|receiver/gi, 'system')];
}
return '';
};
const getColumnValue = (id, column) => {
const statisticData: StatisticData = statisticState.entities[id];
const connection: Connection = connectionState.entities[statisticData.uniqueId];
if(statisticData[column.key] !== undefined) return statisticData[column.key];
else if(column.type === 'system') return getSystemFieldValue(column.key, connection);
else return connection[column.key];
};
for(const id of filteredData.StatisticsByConnections) {
let row = [];
tableColumns.columns.forEach(column => {
if(column.visible) {
row.push({
text: getColumnValue(id, column),
border: noTopBorder
})
}
});
body.push(row);
}
//Push the definition to the PDF
pdf.content.push(pdfDetailsTable);
};
header();
footer();
}
isIE() {
const userAgent = window.navigator.userAgent;
const msie = userAgent.indexOf('MSIE ');
if (msie > 0) {
this.logger.debug('isIE', 'Browser: \'IE10\'!');
//IE 10 or older => return version number
return parseInt(userAgent.substring(msie + 5, userAgent.indexOf('.', msie)), 10);
}
const trident = userAgent.indexOf('Trident/');
if (trident > 0) {
this.logger.debug('isIE', 'Browser: \'IE11\'!');
//IE 11 => return version number
let rv = userAgent.indexOf('rv:');
return parseInt(userAgent.substring(rv + 3, userAgent.indexOf('.', rv)), 10);
}
const edge = userAgent.indexOf('Edge/');
if (edge > 0) {
// Logger.debug("Browser: 'Edge'!");
//Edge (IE 12+) => return version number
return parseInt(userAgent.substring(edge + 5, userAgent.indexOf('.', edge)), 10);
}
// Logger.debug("Browser not IE/Edge.");
//Other browser
return false;
}
}
在pdfDetailsTable中,我已将表格中的宽度更改为100,但不会更改,也为以下内容添加了宽度:
tableColumns.columns.forEach(column => {
if(column.visible) {
row.push({
=> HERE WIDTH: 100,
text: getColumnValue(id, column),
border: noTopBorder
})
}
});
但这也没有帮助我。有人可以知道我在做什么,因为该属性仍设置为auto吗?