word-table
Version:
word-table is simple browserjs / nodejs library for drawing tables in the terminal/console.
216 lines (187 loc) • 4.99 kB
JavaScript
/**
* Copyright (c) 2017 hustcc
* License: MIT
* GitHub: https://github.com/hustcc/word-table
**/
const WordWidth = require('word-width');
class WordTable {
/**
* @param header
* @param body
*/
constructor(header = [], body = []) {
// 标记内容是否修改
this._updated = true;
// ascii table 字符串缓存
this._stringTable = null;
// 表格每一列中最大的宽度
this._tableColLength = 0;
// table 的最大列数
this._maxCols = 0;
this._tableDatas = null;
// 缓存字符串宽度,防止后续重复计算
this._wordWidthMap = [];
// header 数据
this._tableHeader = header;
// 全部数据
this._tableBody = body;
}
_fillStr = (l, c) => {
let str = '';
let i;
for (i = 0; i < l; i += 1) {
str += c;
}
return str;
};
_initLength = (i, j, str) => {
this._maxCols = Math.max(j + 1, this._maxCols);
if (this._tableColLength.length <= j) {
this._tableColLength.push(0); // 长度不够,添加一个长度
}
const width = WordWidth(`${str}`); // 强制转字符串
// 补齐 map
while (this._wordWidthMap.length <= i) this._wordWidthMap.push([]);
if (this._wordWidthMap[i].length <= j) this._wordWidthMap[i].push(width);
else this._wordWidthMap[i][j] = width;
this._tableColLength[j] = Math.max(width, this._tableColLength[j]);
};
_initDatas = () => {
this._tableDatas = this._tableBody.concat();
this._tableDatas.splice(0, 0, this._tableHeader);
// reset
this._tableColLength = [];
this._maxCols = 0;
let i;
let j;
const rowlen = this._tableDatas.length;
let rowdata;
let collen;
// 遍历每一行数据
for (i = 0; i < rowlen; i += 1) {
rowdata = this._tableDatas[i];
// 遍历每一行的每一列,获取每一列的最大字符串长度
collen = rowdata.length;
for (j = 0; j < collen; j += 1) {
this._initLength(i, j, rowdata[j]);
}
}
};
// 绘制分割横线
_drawDivider = (sepWidth) => {
let i;
let width;
let str = '+';
for (i = 0; i < this._maxCols; i += 1) {
width = this._tableColLength[i] + sepWidth[i] * 2;
str += this._fillStr(width, '-');
str += '+';
}
return str;
};
// 绘制每一行数据
_drawLine = (rowdata, sepWidth, index) => {
let i;
let str = '|';
const collen = rowdata.length;
let temp;
let left;
let right;
for (i = 0; i < this._maxCols; i += 1) {
if (i >= collen) {
// 元素不足,需要使用空格补充
str += this._fillStr(this._tableColLength[i] + sepWidth[i] * 2, ' ');
str += '|';
} else {
// 元素存在
temp = (this._tableColLength[i] - this._wordWidthMap[index][i]) / 2;
left = Math.floor(temp);
right = Math.ceil(temp);
str += this._fillStr(sepWidth[i] + left, ' ');
str += rowdata[i];
str += this._fillStr(sepWidth[i] + right, ' ');
str += '|';
}
}
return str;
};
// 绘制 ascii table
_drawTable = () => {
let i;
const sepWidth = []; // 每列的间隔数量为字符串长度 / 4 向上取整
const rowlen = this._tableDatas.length;
for (i = 0; i < this._maxCols; i += 1) {
sepWidth.push(Math.ceil(this._tableColLength[i] / 4));
}
const divider = this._drawDivider(sepWidth); // 分割线
this._stringTable = [divider];
// 遍历每一行数据,绘制 table
for (i = 0; i < rowlen; i += 1) {
this._stringTable.push(this._drawLine(this._tableDatas[i], sepWidth, i));
this._stringTable.push(divider);
}
};
/**
* Get the ascii table of string.
*
* WordTable().string();
*/
string = () => this.array().join('\n');
/**
* Get the ascii table of array.
*
* WordTable().array();
*/
array = () => {
if (this._updated) {
// calculate
this._initDatas();
// draw
this._drawTable();
if (this._maxCols === 0) return [];
this._updated = false;
}
return this._stringTable;
};
/**
* Set the header of ascii table with API.
* - header (Array): the header of ascii table.
*
*/
setHeader = (header = []) => {
this._tableHeader = header;
this._updated = true;
return this;
};
/**
* Append data into ascii table with API.
* - data (Array): one table row data.
*
*/
appendBody = (tr) => {
this._tableBody.push(tr);
this._updated = true;
return this;
};
/**
* Reset data into ascii table with API.
* - datas (Array of Array): all records in table.
*
*/
setBody = (body) => {
this._tableBody = body;
this._updated = true;
return this;
};
/**
* Reset the instance.
*
*/
reset = () => {
this._updated = true;
this._tableHeader = [];
this._tableBody = [];
return this;
};
}
module.exports = WordTable;