使用d3-hierarchy和动画在树根周围分布节点

dag*_*da1 7 d3.js reactjs

我附上了一个显示我的解决方案的代码沙箱.

我觉得我的解决方案不正确,因为我在NodesFanout组件中完成了所有计算.

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>
  );
};
Run Code Online (Sandbox Code Playgroud)

动画也没有正确地从中心散开.

我想实现像这样,所有的节点从中心展开.

有没有更好的方法呢?

Shu*_*han 6

我相信这实现了目标:https://codesandbox.io/s/w4n1v3xvw

我不认为代码是有问题的,它只是你所基于的例子是片面的,所以leave动画需要根据每个节点的一面进行更新.

这是在更改之前更改了注释的代码:

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]
        };
      }}
Run Code Online (Sandbox Code Playgroud)