Open dagda1 opened 6 years ago
I believe the technique Iāve seen using straight d3.js is to render 2 trees with each root at the middle/overlapping.
For example: http://bl.ocks.org/jdarling/2503502
You should be able to use 2 <Tree />
components to accomplish the same thing. See
https://vx-demo.now.sh/linkTypes for an example to change direction (you should be able to swap the x-scaleās min/max to go right/left.
@techniq the 2 trees approach did not work for me because I need zooming and panning which was difficult to keep the trees together so I ended up with 1 tree:
https://codesandbox.io/s/znj3ykqwj3
I ended up doing the calculations for the nodes in the ./src/components/NodesFanout
component but this feels wrong, is there a better way:
import * as React from "react";
import NodeGroup from "react-move/NodeGroup";
import { StructureItem } from "../../types";
import { Node } from "../Node";
import { HierarchyPointNode } from "d3-hierarchy";
import { HierarchyLabelProps } from "../HierarchyLabel";
import { findIndex } from "lodash";
import { NodeHeight } from "../Tree";
import { findCollapsedParent } from "../../util/node";
const { Group } = require("@vx/group");
export interface NodesProps {
nodes: HierarchyPointNode<StructureItem>[];
clickHandler: any;
shapeLength: number;
collapse: boolean;
Label: React.ComponentType<HierarchyLabelProps>;
LabelCollapsed: React.ComponentType<HierarchyLabelProps>;
}
const positionNodes = (
node: HierarchyPointNode<StructureItem>,
nodes: HierarchyPointNode<StructureItem>[]
) => {
let left: number;
let top: number;
if (!node.parent) {
left = node.y / 2 - NodeHeight;
top = node.x - NodeHeight;
} else if (node.data && node.data.isRight) {
const index = findIndex(nodes, node);
const lastLeft = nodes[index - 1];
top = lastLeft.x;
left = NodeHeight;
} else {
top = node.x;
left = node.y;
}
return {
top: [top],
left: [left],
opacity: [1]
};
};
export const NodesFanout: React.SFC<NodesProps> = ({
Label,
LabelCollapsed,
nodes,
shapeLength,
clickHandler,
collapse
}) => {
return (
<NodeGroup
data={nodes}
keyAccessor={(d: HierarchyPointNode<StructureItem>) => d.data.id}
start={(node: HierarchyPointNode<StructureItem>) => {
let left: number;
let top: number;
if (!node.parent) {
left = node.y / 2 - NodeHeight;
top = node.x - NodeHeight;
} else {
left = node.parent.y / 2;
top = node.parent.x;
}
return {
top,
left,
opacity: 0
};
}}
enter={node => positionNodes(node, nodes)}
update={node => positionNodes(node, nodes)}
leave={node => {
let left: number;
let top: number;
const collapsedParent = findCollapsedParent(
node.parent
) as HierarchyPointNode<StructureItem>;
if (!collapsedParent.parent) {
left = collapsedParent.y / 2;
top = collapsedParent.x - NodeHeight;
} else {
left = collapsedParent.parent.y / 2;
top = collapsedParent.parent.x - NodeHeight;
}
return {
top: [top],
left: [left],
opacity: [0]
};
}}
>
{nodes => (
<Group>
{nodes.map(({ key, data: node, state }, index) => {
return (
<Group
top={state.top}
left={state.left}
key={key}
opacity={state.opacity}
className={`node__${index}`}
>
<Node
Label={Label}
LabelCollapsed={LabelCollapsed}
node={node}
shapeLength={shapeLength}
clickHandler={(e: any) => {
clickHandler({ e, node });
}}
key={key}
collapse={collapse}
/>
</Group>
);
})}
</Group>
)}
</NodeGroup>
);
};
My animation is a bit wrong also.
Hmm, I've not done this myself so I can't be of much more help right now.
You might be able get away using a Polar coordinate system and adjust the size and separation props.
See: https://github.com/hshoff/vx/issues/162#issuecomment-365493922 for some experimentation with separation
@dagda1 @techniq I know this is a old post, but I have a use case requiring a tree with nodes on each side using vx/hierarchy
. Has anyone come up with a solution for this? I haven't had any luck finding a good example.
@aoloo Sorry I haven't had this use case myself thus far.
When I'm looking for new examples / approaches I'll typically look at d3 observables and port to React / visx.
This NCAA Bracket example might give you a start, I just quickly read through it but it does use d3.hierarchy / d3.tree:
It appears to be well written and has some good notes. I think it's rendering 4 trees (for each quadrant) and blending them together as 1, but I didn't analyze it deeply.
With hierarchies/trees, you need to have a single root node. You can sometimes work around this by creating a "pseudo" root that you hide visually. You could try that approach, but you'd have to create a tree left to right, as opposed to inside out (with the center being at the middle
of the nodes, at opposed to at the root).
This layout might be better represented as a graph structure made of nodes and links, but I think searching for "bracket" helps to identify this type of layout.
Sorry I can't be of more help.
I am looking to create something like this:
I need a tree but with the nodes on either side. I've had create success with vxtree but that has one root node.
Is there a way I could spread them out like the diagram below?