Skip to content

Instantly share code, notes, and snippets.

@Adizbek
Created August 14, 2020 04:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Adizbek/4d015898121c25c2334c451ca0ffd189 to your computer and use it in GitHub Desktop.
Save Adizbek/4d015898121c25c2334c451ca0ffd189 to your computer and use it in GitHub Desktop.
Tree structure to html table, automatic colspan, rowspan
class Tree {
/** @type String */
val;
/** @type Tree[] */
children;
/**
* @param {String} val
* @param {Tree[]} children
*/
constructor(val, children = []) {
this.val = val;
this.children = children;
}
}
class Cell {
/** @type String */
val;
/** @type number */
row;
/** @type number */
col;
/** @type number */
rowspan;
/** @type number */
colspan;
/**
* @param {String} val
* @param {number} row
* @param {number} col
* @param {number} rowspan
* @param {number} colspan
*/
constructor(val, row, col, rowspan, colspan) {
this.val = val;
this.row = row;
this.col = col;
this.rowspan = rowspan;
this.colspan = colspan;
}
toTag() {
let cs = this.colspan === 1 ? "" : ` colspan='${this.colspan}'`;
let rs = this.rowspan === 1 ? "" : ` rowspan='${this.rowspan}'`;
return `<td${cs}${rs}>${this.val}</td>`;
}
}
class Table {
/**
* @param {Tree} t
* @return {number}
*/
width(t) {
if (t.children.length === 0)
return 1;
let w = 0;
for (let child of t.children)
w += this.width(child);
return w;
}
/**
* @param {number} a
* @param {number} b
* @return {number}
*/
lcm(a, b) {
let c = a * b;
while (b > 0) {
let t = b;
b = a % b;
a = t;
}
return c / a;
}
/**
* @param {Tree} t
* @return {*}
*/
rowsToUse(t) {
let childrenRows = t.children.length === 0 ? 0 : 1;
for (let child of t.children)
childrenRows = this.lcm(childrenRows, this.rowsToUse(child));
return 1 + childrenRows;
}
/**
* @param {Tree} t
* @param {number} row
* @param {number} col
* @param {number} rowsLeft
* @return {Cell[]}
*/
getCells(t, row, col, rowsLeft) {
// Add top-most cell corresponding to the root of the current tree.
let rootRows = rowsLeft / this.rowsToUse(t);
let cells = [];
cells.push(new Cell(t.val, row, col, rootRows, this.width(t)));
// Generate cells for subtrees.
for (let child of t.children) {
cells.push(...this.getCells(child, row + rootRows, col, rowsLeft - rootRows));
col += this.width(child);
}
return cells;
}
/**
* @param {Cell[]} cells
*/
getHtmlTable(cells) {
let sortedCells = cells.sort((a, b) => {
let pri = a.row - b.row
let sec = a.col - b.col
return pri !== 0 ? pri : sec;
})
let table = '<table border="1"><tbody>'
for (let i = 0, row = 0; i < sortedCells.length; row++) {
if (row === 0) {
i++;
continue;
}
table += '<tr>';
for (; i < sortedCells.length && sortedCells[i].row === row; i++) {
table += sortedCells[i].toTag();
}
table += '</tr>';
}
table += '</tbody></table>'
return table
}
/**
* @param {Tree} tree
*/
printTableTree(tree) {
let cells = this.getCells(tree, 0, 0, this.rowsToUse(tree))
return this.getHtmlTable(cells)
}
}
let myTableTree = new Tree(null, [
new Tree("A"), new Tree("B", [
new Tree("C"), new Tree("D"), new Tree("E")
])
]);
let table = new Table();
let html = table.printTableTree(myTableTree);
let fs = require('fs');
fs.writeFileSync('./index.html', html)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment