From f1f1dd9ccd1a7ef03c1f082c1b7c346624b364fa Mon Sep 17 00:00:00 2001 From: Yanyan-Wang Date: Wed, 18 Jan 2023 19:50:25 +0800 Subject: [PATCH] fix: indented layout with different node heights --- package.json | 2 +- src/indented.js | 11 +++++------ src/layout/indented.js | 23 +++++++++++++++++++---- src/util.js | 16 +++++++++++++++- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index ce7fde5..1fe6a51 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@antv/hierarchy", - "version": "0.6.8", + "version": "0.6.9", "description": "layout algorithms for visualizing hierarchical data", "main": "build/hierarchy.js", "browser": "build/hierarchy.js", diff --git a/src/indented.js b/src/indented.js index 9c6ae98..da19916 100644 --- a/src/indented.js +++ b/src/indented.js @@ -18,22 +18,21 @@ class IndentedLayout extends TreeLayout { const root = me.rootNode; options.isHorizontal = true; // default indent 20 and sink first children; - const { indent = 20, dropCap = true } = options; - const direction = options.direction || DEFAULT_DIRECTION; + const { indent = 20, dropCap = true, direction = DEFAULT_DIRECTION, align } = options; if (direction && VALID_DIRECTIONS.indexOf(direction) === -1) { throw new TypeError(`Invalid direction: ${direction}`); } if (direction === VALID_DIRECTIONS[0]) { // LR - indentedTree(root, indent, dropCap); + indentedTree(root, indent, dropCap, align); } else if (direction === VALID_DIRECTIONS[1]) { // RL - indentedTree(root, indent, dropCap); + indentedTree(root, indent, dropCap, align); root.right2left(); } else if (direction === VALID_DIRECTIONS[2]) { // H // separate into left and right trees const { left, right } = separateTree(root, options); - indentedTree(left, indent, dropCap); + indentedTree(left, indent, dropCap, align); left.right2left(); - indentedTree(right, indent, dropCap); + indentedTree(right, indent, dropCap, align); const bbox = left.getBoundingBox(); right.translate(bbox.width, 0); root.x = right.x - root.width / 2; diff --git a/src/layout/indented.js b/src/layout/indented.js index c3b0d30..f5216d5 100644 --- a/src/layout/indented.js +++ b/src/layout/indented.js @@ -1,4 +1,6 @@ -function positionNode(node, previousNode, indent, dropCap) { +const util = require('../util'); + +function positionNode(node, previousNode, indent, dropCap, align) { // caculate the node's horizontal offset DX, dx's type might be number or function const displacementX = typeof indent === 'function' ? indent(node) : indent * node.depth; @@ -15,13 +17,26 @@ function positionNode(node, previousNode, indent, dropCap) { } node.x += displacementX; - node.y = previousNode ? previousNode.y + previousNode.height : 0; + if (previousNode) { + node.y = previousNode.y + util.getHeight(previousNode, node, align); + if (node.parent.id !== previousNode.parent?.id) { + // previous node has different parent + const index = node.parent.children.findIndex(n => n.id === node.id); + const preNode = node.parent.children[index - 1]; + if (preNode) { + const preY = preNode.y + util.getHeight(preNode, node, align); + node.y = preY > node.y ? preY : node.y; + } + } + } else { + node.y = 0; + } return; } -module.exports = (root, indent, dropCap) => { +module.exports = (root, indent, dropCap, align) => { let previousNode = null; root.eachNode(node => { - positionNode(node, previousNode, indent, dropCap); + positionNode(node, previousNode, indent, dropCap, align); previousNode = node; }); }; diff --git a/src/util.js b/src/util.js index cdeee2a..f5abfbb 100644 --- a/src/util.js +++ b/src/util.js @@ -1,4 +1,18 @@ const { mix } = require('@antv/util'); + +/** + * Get average height or height for node's position calculation, according to align. + * @param {*} preNode previous node + * @param {*} node current node, whose position is going to be calculated + * @param {'center' | undefined} align 'center' means nodes align at the center, other value means align at the left-top + * @param {string} heightField field name for height value on preNode and node + * @return {number} the height for calculation + */ +function getHeight(preNode, node, align, heightField = 'height') { + return align === 'center' ? (preNode[heightField] + node[heightField]) / 2 : preNode.height; +} + module.exports = { - assign: mix + assign: mix, + getHeight };