phylogician-ts
Version:
Module to read, manipulate and write phylogenetic trees. Written in TypeScript
141 lines • 4.96 kB
JavaScript
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const d3 = __importStar(require("d3"));
const TreeLayout_1 = require("./TreeLayout");
const loglevel_colored_prefix_1 = require("loglevel-colored-prefix");
class Vertical extends TreeLayout_1.TreeLayout {
constructor(tree, svgParams, loglevel = 'info') {
super(tree, svgParams);
this.logger = new loglevel_colored_prefix_1.Logger(loglevel);
}
/**
* Calculates all parameters of the tree
*
* @param {boolean} scaling
* @returns {this}
* @memberof Vertical
*/
calcTree(scaling) {
super.calcLabelDims();
this.calcPosX(scaling)
.calcPosY()
.calcBranchPath();
return this;
}
/**
* Calculates the position X of all nodes
*
* @param {boolean} [scaling=false]
* @returns {this}
* @memberof Vertical
*/
calcPosX(scaling = false) {
const log = this.logger.getLogger('VerticalTreeLayout::calcPosX');
const longestLabel = this.getLongestLabel();
if (scaling) {
const xDom = d3
.scaleLinear()
.domain([0, this.tree.getMaxDistanceToRoot()])
.range([this.svgParams.margin, this.svgParams.width - this.svgParams.margin - longestLabel]);
this.tree.nodes.forEach(node => {
const id = node.id;
const posX = xDom(this.tree.getDistanceToRoot(id));
node.setPosX(posX);
});
}
else {
const maxHops = this.tree.getMaxHopsToRoot();
log.debug(`Scale: ${scaling}, MaxHops: ${maxHops}`);
const xDom = d3
.scaleLinear()
.domain([maxHops, 0])
.range([this.svgParams.margin, this.svgParams.width - this.svgParams.margin - longestLabel]);
const nodeListCounter = this.tree.getAllMaxHopsToChildLeafs();
this.tree.nodes.forEach(node => {
const nodeId = node.id;
if (nodeId !== undefined) {
log.debug(`Node: ${nodeId}, MaxHopsToChildLeafs: ${nodeListCounter[nodeId]}, xDom: ${xDom(nodeListCounter[nodeId])} `);
node.setPosX(xDom(nodeListCounter[nodeId]));
}
});
}
return this;
}
/**
* Calculates the position Y of all nodes
*
* @returns {this}
* @memberof Vertical
*/
calcPosY() {
const leaves = this.tree.getAllLeafIds();
const yDom = d3
.scaleLinear()
.domain([0, this.tree.getNumberOfLeafs() - 1])
.range([this.svgParams.margin, this.svgParams.height - this.svgParams.margin]);
// const spacing = (this.height - this.margin * 2) / leaves.length
leaves.forEach((leaf, i) => this.tree.getNode(leaf).setPosY(yDom(i)));
const internalIds = this.tree.getInternalIds().reverse();
internalIds.forEach(internalId => {
const internal = this.tree.getNode(internalId);
const childrenPos = [];
internal.children.forEach(child => {
childrenPos.push(this.tree.getNode(child).getPosY());
});
internal.setPosY(childrenPos.reduce((sum, pos) => sum + pos) / childrenPos.length);
});
return this;
}
/**
* Calculates the branch path
*
* @returns {this}
* @memberof Vertical
*/
calcBranchPath() {
this.tree.nodes.forEach(node => {
const parentId = node.getParentNodeId();
if (parentId !== null) {
const branchCoords = [];
branchCoords.push([this.tree.getNode(parentId).getPosX(), this.tree.getNode(parentId).getPosY()]);
branchCoords.push([node.getPosX(), node.getPosY()]);
const branch = d3
.line()
.x((d) => d[0])
.y((d) => d[1])
.curve(d3.curveStepBefore);
node.setBranchPath(branch(branchCoords));
}
});
return this;
}
/**
* Helper function to place label by the corresponding node
*
* @param {number} id
* @returns {string}
* @memberof Vertical
*/
labelPlace(id) {
return 'translate(10)';
}
/**
* Helper function to determine the anchor of text
*
* @param {number} id
* @returns {string}
* @memberof Vertical
*/
labelAnchor(id) {
return 'start';
}
}
exports.Vertical = Vertical;
//# sourceMappingURL=VerticalTreeLayout.js.map