jsPDF AutoTable plugin

/**
  * jsPDF AutoTable plugin
  * Copyright (c) 2014 Simon Bengtsson, https://github.com/someatoms/jsPDF-AutoTable
  *
  * Licensed under the MIT License.
  * http://opensource.org/licenses/mit-license
  */
  (function (API) {
  'use strict';
   
  // On every new jsPDF object, clear variables
  API.events.push(['initialized', function () {
  doc = undefined;
  cellPos = undefined;
  pageCount = 1;
  settings = undefined;
  }], false);
   
  var MIN_COLUMN_WIDTH = 25;
   
  var doc, cellPos, pageCount = 1, settings;
   
  // See README.md or examples for documentation of the options
  // return a new instance every time to avoid references issues
  var defaultOptions = function () {
  return {
  padding: 5,
  fontSize: 10,
  lineHeight: 20,
  renderHeader: function (doc, pageNumber, settings) {
  },
  renderFooter: function (doc, lastCellPos, pageNumber, settings) {
  },
  renderHeaderCell: function (x, y, width, height, key, value, settings) {
  doc.setFillColor(52, 73, 94); // Asphalt
  doc.setTextColor(255, 255, 255);
  doc.setFontStyle('bold');
  doc.rect(x, y, width, height, 'F');
  y += settings.lineHeight / 2 + doc.internal.getLineHeight() / 2;
  doc.text(value, x + settings.padding, y);
  },
  renderCell: function (x, y, width, height, key, value, row, settings) {
  doc.setFillColor(row % 2 === 0 ? 245 : 255);
  doc.setTextColor(50);
  doc.rect(x, y, width, height, 'F');
  y += settings.lineHeight / 2 + doc.internal.getLineHeight() / 2 - 2.5;
  doc.text(value, x + settings.padding, y);
  },
  margins: {right: 40, left: 40, top: 50, bottom: 40},
  startY: false,
  overflow: 'ellipsize', // false, ellipsize or linebreak (false passes the raw text to renderCell)
  overflowColumns: false, // Specify which colums that gets subjected to the overflow method chosen. false indicates all
  avoidPageSplit: false,
  extendWidth: true
  }
  };
   
  /**
  * Create a table from a set of rows and columns.
  *
  * @param {Object[]|String[]} columns Either as an array of objects or array of strings
  * @param {Object[][]|String[][]} data Either as an array of objects or array of strings
  * @param {Object} [options={}] Options that will override the default ones (above)
  */
  API.autoTable = function (columns, data, options) {
  options = options || {};
  columns = columns || [];
  doc = this;
   
  var userFontSize = doc.internal.getFontSize();
   
  initData({columns: columns, data: data});
  initOptions(options);
   
  cellPos = {
  x: settings.margins.left,
  y: settings.startY === false ? settings.margins.top : settings.startY
  };
   
  var tableHeight = settings.margins.bottom + settings.margins.top + settings.lineHeight * (data.length + 1) + 5 + settings.startY;
  if (settings.startY !== false && settings.avoidPageSplit && tableHeight > doc.internal.pageSize.height) {
  pageCount++;
  doc.addPage();
  cellPos.y = settings.margins.top;
  }
   
  settings.renderHeader(doc, pageCount, settings);
  var columnWidths = calculateColumnWidths(data, columns);
  printHeader(columns, columnWidths);
  printRows(columns, data, columnWidths);
  settings.renderFooter(doc, cellPos, pageCount, settings);
   
  doc.setFontSize(userFontSize);
   
  return this;
  };
   
  /**
  * Returns the Y position of the last drawn cell
  * @returns int
  */
  API.autoTableEndPosY = function () {
  // If cellPos is not set, autoTable() has probably not been called
  return cellPos ? cellPos.y : false;
  };
   
  /**
  * @deprecated Use autoTableEndPosY()
  */
  API.autoTableEndPos = function () {
  return cellPos;
  };
   
  /**
  * Parses an html table. To draw a table, use it like this:
  * `doc.autoTable(false, doc.autoTableHtmlToJson(tableDomElem))`
  *
  * @param table Html table element
  * @param indexBased Boolean flag if result should be returned as seperate cols and data
  * @returns []|{} Array of objects with object keys as headers or based on indexes if indexBased is set to true
  */
  API.autoTableHtmlToJson = function (table, indexBased) {
  var data = [], headers = {}, header = table.rows[0], i, tableRow, rowData, j;
  if (indexBased) {
  headers = [];
  for (i = 0; i < header.cells.length; i++) {
  headers.push(header.cells[i] ? header.cells[i].textContent : '');
  }
   
  for (i = 1; i < table.rows.length; i++) {
  tableRow = table.rows[i];
  rowData = [];
  for (j = 0; j < header.cells.length; j++) {
  rowData.push(tableRow.cells[j] ? tableRow.cells[j].textContent : '');
  }
  data.push(rowData);
  }
  return {columns: headers, data: data};
  } else {
  for (i = 0; i < header.cells.length; i++) {
  headers[i] = header.cells[i] ? header.cells[i].textContent : '';
  }
   
  for (i = 1; i < table.rows.length; i++) {
  tableRow = table.rows[i];
  rowData = {};
  for (j = 0; j < header.cells.length; j++) {
  rowData[headers[j]] = tableRow.cells[j] ? tableRow.cells[j].textContent : '';
  }
  data.push(rowData);
  }
   
  return data;
  }
  };
   
  /**
  * Transform all to the object initialization form
  * @param params
  */
  function initData(params) {
   
  // Object only initial
  if (!params.columns || params.columns.length === 0) {
  var keys = Object.keys(params.data[0]);
  Array.prototype.push.apply(params.columns, keys);
  params.columns.forEach(function (title, i) {
  params.columns[i] = {title: title, key: keys[i]};
  });
  }
  // Array initialization form
  else if (typeof params.columns[0] === 'string') {
  params.data.forEach(function (row, i) {
  var obj = {};
  for (var j = 0; j < row.length; j++) {
  obj[j] = params.data[i][j];
  }
  params.data[i] = obj;
  });
  params.columns.forEach(function (title, i) {
  params.columns[i] = {title: title, key: i};
  });
  } else {
  // Use options as is
  }
  }
   
  function initOptions(raw) {
  settings = defaultOptions();
  Object.keys(raw).forEach(function (key) {
  settings[key] = raw[key];
  });
  doc.setFontSize(settings.fontSize);
   
  // Backwards compatibility
  if(settings.margins.horizontal !== undefined) {
  settings.margins.left = settings.margins.horizontal;
  settings.margins.right = settings.margins.horizontal;
  } else {
  settings.margins.horizontal = settings.margins.left;
  }
  }
   
  function calculateColumnWidths(rows, columns) {
  var widths = {};
   
  // Optimal widths
  var optimalTableWidth = 0;
  columns.forEach(function (header) {
  var widest = getStringWidth(header.title || '', true);
  if(typeof header.width == "number") {
  widest = header.width;
  } else {
  rows.forEach(function (row) {
  if (!header.hasOwnProperty('key'))
  throw new Error("The key attribute is required in every header");
  var w = getStringWidth(stringify(row, header.key));
  if (w > widest) {
  widest = w;
  }
  });
  }
  widths[header.key] = widest;
  optimalTableWidth += widest;
  });
   
  var paddingAndMargin = settings.padding * 2 * columns.length + settings.margins.left + settings.margins.right;
  var spaceDiff = doc.internal.pageSize.width - optimalTableWidth - paddingAndMargin;
   
  var keys = Object.keys(widths);
  if (spaceDiff < 0) {
  // Shrink columns
  var shrinkableColumns = [];
  var shrinkableColumnWidths = 0;
  if (settings.overflowColumns === false) {
  keys.forEach(function (key) {
  if (widths[key] > MIN_COLUMN_WIDTH) {
  shrinkableColumns.push(key);
  shrinkableColumnWidths += widths[key];
  }
  });
  } else {
  shrinkableColumns = settings.overflowColumns;
  shrinkableColumns.forEach(function (col) {
  shrinkableColumnWidths += widths[col];
  });
  }
   
  shrinkableColumns.forEach(function (key) {
  widths[key] += spaceDiff * (widths[key] / shrinkableColumnWidths);
  });
  } else if (spaceDiff > 0 && settings.extendWidth) {
  // Fill page horizontally
  keys.forEach(function (key) {
  widths[key] += spaceDiff / keys.length;
  });
  }
   
  return widths;
  }
   
  function printHeader(headers, columnWidths) {
  if (!headers) return;
   
  // First calculate the height of the row
  // (to do that the maxium amount of rows first need to be found)
  var maxRows = 1;
  if (settings.overflow === 'linebreak') {
  headers.forEach(function (header) {
  if (isOverflowColumn(header)) {
  var value = header.title || '';
  var arr = doc.splitTextToSize(value, columnWidths[header.key]);
  if (arr.length > maxRows) {
  maxRows = arr.length;
  }
  }
  });
  }
  var rowHeight = settings.lineHeight + (maxRows - 1) * doc.internal.getLineHeight() + 5;
   
  headers.forEach(function (header) {
  var width = columnWidths[header.key] + settings.padding * 2;
  var value = header.title || '';
  if (settings.overflow === 'linebreak') {
  if (isOverflowColumn(header)) {
  value = doc.splitTextToSize(value, columnWidths[header.key]);
  }
  } else if (settings.overflow === 'ellipsize') {
  value = ellipsize(columnWidths[header.key], value);
  }
  settings.renderHeaderCell(cellPos.x, cellPos.y, width, rowHeight, header.key, value, settings);
  cellPos.x += width;
  });
  doc.setTextColor(70, 70, 70);
  doc.setFontStyle('normal');
   
  cellPos.y += rowHeight;
  cellPos.x = settings.margins.left;
  }
   
  function printRows(headers, rows, columnWidths) {
  for (var i = 0; i < rows.length; i++) {
  var row = rows[i];
   
  // First calculate the height of the row
  // (to do that the maxium amount of rows first need to be found)
  var maxRows = 1;
  if (settings.overflow === 'linebreak') {
  headers.forEach(function (header) {
  if (isOverflowColumn(header)) {
  var value = stringify(row, header.key);
  var arr = doc.splitTextToSize(value, columnWidths[header.key]);
  if (arr.length > maxRows) {
  maxRows = arr.length;
  }
  }
  });
  }
  var rowHeight = settings.lineHeight + (maxRows - 1) * doc.internal.getLineHeight();
   
   
  // Render the cell
  headers.forEach(function (header) {
  var value = stringify(row, header.key);
  if (settings.overflow === 'linebreak') {
  if (isOverflowColumn(header)) {
  value = doc.splitTextToSize(value, columnWidths[header.key]);
  }
  } else if (settings.overflow === 'ellipsize') {
  value = ellipsize(columnWidths[header.key], value);
  }
  var width = columnWidths[header.key] + settings.padding * 2;
  settings.renderCell(cellPos.x, cellPos.y, width, rowHeight, header.key, value, i, settings);
  cellPos.x = cellPos.x + columnWidths[header.key] + settings.padding * 2;
  });
   
  // Add a new page if cellpos is at the end of page
  var newPage = (cellPos.y + settings.margins.bottom + settings.lineHeight * 2) >= doc.internal.pageSize.height;
  if (newPage) {
  settings.renderFooter(doc, cellPos, pageCount, settings);
  doc.addPage();
  cellPos = {x: settings.margins.left, y: settings.margins.top};
  pageCount++;
  settings.renderHeader(doc, pageCount, settings);
  printHeader(headers, columnWidths);
  } else {
  cellPos.y += rowHeight;
  cellPos.x = settings.margins.left;
  }
  }
  }
   
  function isOverflowColumn(header) {
  return settings.overflowColumns === false || settings.overflowColumns.indexOf(header.key) !== -1;
  }
   
  /**
  * Ellipsize the text to fit in the width
  * @param width
  * @param text
  */
  function ellipsize(width, text) {
  if (width >= getStringWidth(text)) {
  return text;
  }
  while (width < getStringWidth(text + "...")) {
  if (text.length < 2) {
  break;
  }
  text = text.substring(0, text.length - 1);
  }
  text += "...";
  return text;
  }
   
  function stringify(row, key) {
  return row.hasOwnProperty(key) ? '' + row[key] : '';
  }
   
  function getStringWidth(txt, isBold) {
  if(isBold) {
  doc.setFontStyle('bold');
  }
  var strWidth = doc.getStringUnitWidth(txt) * doc.internal.getFontSize();
  if(isBold) {
  doc.setFontStyle('normal');
  }
  return strWidth;
  }
   
  })(jsPDF.API);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值