UNPKG

phylogician-ts

Version:

Module to read, manipulate and write phylogenetic trees. Written in TypeScript

141 lines 4.96 kB
"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