133 lines
2.8 KiB
JavaScript
133 lines
2.8 KiB
JavaScript
// wrap tree node
|
|
// TODO considering size
|
|
var util = require('../util');
|
|
|
|
function WrappedTree(height, children) {
|
|
if (height === void 0) {
|
|
height = 0;
|
|
}
|
|
|
|
if (children === void 0) {
|
|
children = [];
|
|
}
|
|
|
|
var me = this;
|
|
me.x = me.y = 0;
|
|
me.leftChild = me.rightChild = null;
|
|
me.height = 0;
|
|
me.children = children;
|
|
}
|
|
|
|
var DEFAULT_OPTIONS = {
|
|
isHorizontal: true,
|
|
nodeSep: 20,
|
|
nodeSize: 20,
|
|
rankSep: 200,
|
|
subTreeSep: 10
|
|
};
|
|
|
|
function convertBack(converted
|
|
/* WrappedTree */
|
|
, root
|
|
/* TreeNode */
|
|
, isHorizontal) {
|
|
if (isHorizontal) {
|
|
root.x = converted.x;
|
|
root.y = converted.y;
|
|
} else {
|
|
root.x = converted.y;
|
|
root.y = converted.x;
|
|
}
|
|
|
|
converted.children.forEach(function (child, i) {
|
|
convertBack(child, root.children[i], isHorizontal);
|
|
});
|
|
}
|
|
|
|
module.exports = function (root, options) {
|
|
if (options === void 0) {
|
|
options = {};
|
|
}
|
|
|
|
options = util.assign({}, DEFAULT_OPTIONS, options);
|
|
var maxDepth = 0;
|
|
|
|
function wrappedTreeFromNode(n) {
|
|
if (!n) return null;
|
|
n.width = 0;
|
|
|
|
if (n.depth && n.depth > maxDepth) {
|
|
maxDepth = n.depth; // get the max depth
|
|
}
|
|
|
|
var children = n.children;
|
|
var childrenCount = children.length;
|
|
var t = new WrappedTree(n.height, []);
|
|
children.forEach(function (child, i) {
|
|
var childWT = wrappedTreeFromNode(child);
|
|
t.children.push(childWT);
|
|
|
|
if (i === 0) {
|
|
// t.leftChild = childWT.leftChild ? childWT.leftChild : childWT
|
|
t.leftChild = childWT;
|
|
}
|
|
|
|
if (i === childrenCount - 1) {
|
|
// t.rightChild = childWT.rightChild ? childWT.rightChild : childWT
|
|
t.rightChild = childWT;
|
|
}
|
|
});
|
|
t.originNode = n;
|
|
t.isLeaf = n.isLeaf();
|
|
return t;
|
|
}
|
|
|
|
function getDrawingDepth(t) {
|
|
if (t.isLeaf || t.children.length === 0) {
|
|
t.drawingDepth = maxDepth;
|
|
} else {
|
|
var depths = t.children.map(function (child) {
|
|
return getDrawingDepth(child);
|
|
});
|
|
var minChildDepth = Math.min.apply(null, depths);
|
|
t.drawingDepth = minChildDepth - 1;
|
|
}
|
|
|
|
return t.drawingDepth;
|
|
}
|
|
|
|
var prevLeaf;
|
|
|
|
function position(t) {
|
|
t.x = t.drawingDepth * options.rankSep;
|
|
|
|
if (t.isLeaf) {
|
|
t.y = 0;
|
|
|
|
if (prevLeaf) {
|
|
t.y = prevLeaf.y + prevLeaf.height + options.nodeSep;
|
|
|
|
if (t.originNode.parent !== prevLeaf.originNode.parent) {
|
|
t.y += options.subTreeSep;
|
|
}
|
|
}
|
|
|
|
prevLeaf = t;
|
|
} else {
|
|
t.children.forEach(function (child) {
|
|
position(child);
|
|
});
|
|
t.y = (t.leftChild.y + t.rightChild.y) / 2;
|
|
}
|
|
} // wrap node
|
|
|
|
|
|
var wt = wrappedTreeFromNode(root); // get depth for drawing
|
|
|
|
getDrawingDepth(wt); // get position
|
|
|
|
position(wt); // get x, y
|
|
|
|
convertBack(wt, root, options.isHorizontal);
|
|
return root;
|
|
}; |