I have the attached a code sandbox showing my solution.
I feel my solution is not right as I have done all my calculations in the NodesFanout
component.
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>
);
};
The animation is also not fanning out from the center correctly.
I am trying to achieve something like this where all the nodes spread out from the center.
Is there a better way of doing this?
I believe this achieves the goal: https://codesandbox.io/s/w4n1v3xvw
I don't think the code is problematic, its just the example you based on was one-sided, so the leave
animation needed to be updated based on the side of each node.
This is the code changed with comments before changes:
leave={node => {
let left: number;
let top: number;
let nodeIndex: number;
const collapsedParent = findCollapsedParent(
node.parent
) as HierarchyPointNode<StructureItem>;
if (!collapsedParent.parent) {
// Get this nodes index from its' position in the parent
nodeIndex = findIndex(node.parent.children, node);
// Even indices go one side and odd go to the other
// So we add a modifier which changes sign based on NodeHeight
let modifier: number = NodeHeight;
if (nodeIndex % 2 == 1) {
modifier *= -1;
}
// We add the modifier in the left calculation
left = collapsedParent.y / 2 + modifier;
top = collapsedParent.x - NodeHeight;
} else {
left = collapsedParent.parent.y / 2;
top = collapsedParent.parent.x - NodeHeight;
}
return {
top: [top],
left: [left],
opacity: [0]
};
}}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With