当前位置: 首页 > 工具软件 > AntV - G6 > 使用案例 >

AntV-G6 记录折叠节点,数据更后节点保持之前的折叠状态

荆钱明
2023-12-01

首先,在进行折叠操作的时候就用数组记录下被折叠的节点,因为setState函数只要改变了状态(节点展开和折叠)就会执行,所以在数据更新后渲染历史节点状态时也会执行,要注意 不要重复push

setState(name, value, item) {
        let flag = false; // 用来判断是否是历史数据用来初始化的,如果是历史数据就不push进数组
        if (name === 'collapsed') {
          if (value === true) {
            str.forEach((x) => {
              if (x._cfg.id === item._cfg.id) {
                flag = true;
              }
            });
            if (!flag) {
              str.push(item);
              flag = false;
            }
          } else {
            // 展开时如果历史数据有此item,则str不再记录此item
            str = str.filter(x => x._cfg.id !== item._cfg.id);
          }
          const marker = item.get('group').find(ele => ele.get('name') === 'collapse-icon');
          const icon = value ? G6.Marker.expand : G6.Marker.collapse;
          marker.attr('symbol', icon);
        }
      },

节点折叠状态的触发函数,str储存着被折叠的节点

   // 历史折叠节点初始化
    graph.getNodes().forEach((e) => {
      for (let i = 0; i < str.length; i += 1) {
        if (e._cfg.id === str[i]?._cfg.id) {
          e.getModel().collapsed = !e.getModel().collapsed;
          graph.setItemState(e, 'collapsed', e.getModel().collapsed);
          graph.layout();
        }
      }
    });

完整代码:

// 渲染树
  renderTree = () => {
    // 复制/新增/修改/删除 弹出框
    const that = this;
    const contextMenu = new G6.Menu({
      getContent() {
        const outDiv = document.createElement('div');
        outDiv.style.width = '100px';
        outDiv.style.textAlign = 'center';
        outDiv.innerHTML = `<div>
            <li><a code="copy">复制文本</a></li>
            <li><a code="add">新增节点</a></li>
            <li><a code="fix">修改节点</a></li>
            <li><a code="delete">删除节点</a></li>
            <textarea id="store">这是幕后黑手</textarea>
          </div>`;
        return outDiv;
      },

      handleMenuClick: (target, item) => {
        const code = target.getAttribute('code');
        // 复制
        if (code === 'copy') {
          const store = document.getElementById('store');
          store.value = item._cfg.id;
          store.select();
          document.execCommand('copy');
        }
        // 新增
        if (code === 'add') {
          // 初始化为空
          this.props.form.setFieldsValue({
            EnumerateCode: '',
            EnumerateValue: '',
          });
          this.setState({ visible: true, isAdd: true, modelTitle: '新增' });
          this.props.form.setFieldsValue({
            EnumerateType: getQuery('EnumerateType'),
            EnumerateTypeName: getQuery('EnumerateTypeName'),
            Up_EnumerateCode: item._cfg.model.EnumerateLevel === 0
              ? 0 : item._cfg.model.EnumerateCode,
            EnumerateLevel: item._cfg.model.EnumerateLevel + 1,
          });
        }
        // 删除
        if (code === 'delete') {
          confirm({
            title: '请确认是否删除该节点',
            okText: '确定',
            okType: 'danger',
            cancelText: '取消',
            onOk() {
              that.deleteNode(item._cfg.model.EnumerateCode);
            },
            onCancel() {
            },
          });
        }
        // 修改
        if (code === 'fix') {
          this.setState({ visible: true, modelTitle: '修改', oldCode: item._cfg.model.EnumerateCode, isAdd: false });
          const obj = {
            EnumerateType: getQuery('EnumerateType'),
            EnumerateTypeName: getQuery('EnumerateTypeName'),
            // 修改节点的Up_EnumerateCode为它自身的Up_EnumerateCode
            Up_EnumerateCode: item._cfg.model.Up_EnumerateCode,
            EnumerateLevel: item._cfg.model.EnumerateLevel,
            EnumerateCode: item._cfg.model.EnumerateCode,
            EnumerateValue: item._cfg.model.EnumerateValue,
          };
          // 保存原始编辑数据
          this.setState({ oldEditValue: obj });
          this.props.form.setFieldsValue({
            ...obj,
          });
        }
      },

      // offsetX and offsetY include the padding of the parent container
      // 需要加上父级容器的 padding-left 16 与自身偏移量 10
      offsetX: 16 + 10,
      // 需要加上父级容器的 padding-top 24 、画布兄弟元素高度、与自身偏移量 10
      offsetY: 0,
      // the types of items that allow the menu show up
      // 在哪些类型的元素上响应
      itemTypes: ['node'],
    });

    // 自定义节点
    G6.registerNode('card-node', {
      draw: function drawShape(cfg, group) {
        const r = 2;
        const color = '#5B8FF9';
        const w = cfg.size[0];
        const h = cfg.size[1];
        const shape = group.addShape('rect', {
          attrs: {
            x: -w / 2,
            y: -h / 2,
            width: w, // 200,
            height: h, // 60
            stroke: color,
            radius: r,
            fill: '#fff',
          },
          name: 'main-box',
          draggable: true,
        });

        // 节点的内容
        group.addShape('text', {
          attrs: {
            textAlign: 'center',
            textBaseline: 'middle',
            x: 0,
            y: 0,
            lineHeight: 20,
            text: cfg.id,
            fill: '#666',
          },
          name: 'title',
        });
        if (cfg.children && group) {
          group.addShape('marker', {
            attrs: {
              x: w / 2,
              y: 0,
              r: 6,
              cursor: 'pointer',
              symbol: cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse,
              stroke: '#666',
              lineWidth: 1,
              fill: '#fff',
            },
            name: 'collapse-icon',
          });
        }
        return shape;
      },
      setState(name, value, item) {
        let flag = false; // 用来判断是否是历史数据用来初始化的,如果是历史数据就不push进数组
        if (name === 'collapsed') {
          if (value === true) {
            str.forEach((x) => {
              if (x._cfg.id === item._cfg.id) {
                flag = true;
              }
            });
            if (!flag) {
              str.push(item);
              flag = false;
            }
          } else {
            // 展开时如果历史数据有此item,则str不再记录此item
            str = str.filter(x => x._cfg.id !== item._cfg.id);
          }
          const marker = item.get('group').find(ele => ele.get('name') === 'collapse-icon');
          const icon = value ? G6.Marker.expand : G6.Marker.collapse;
          marker.attr('symbol', icon);
        }
      },
    });

    const container = this.mountNode.current;
    const width = container.scrollWidth;
    const height = container.scrollHeight || 500;

    const minimap = new G6.Minimap({
      size: [150, 100],
    });

    const graph = new G6.TreeGraph({
      plugins: [contextMenu, minimap],
      container: this.mountNode.current,
      width,
      height,
      modes: {
        default: ['drag-canvas', 'zoom-canvas'],
      },
      defaultNode: {
        type: 'card-node',
        size: [200, 40],
      },
      defaultEdge: {
        type: 'cubic-horizontal',
        style: {
          endArrow: true,
        },
      },
      layout: {
        type: 'indented',
        direction: 'LR',
        dropCap: false,
        indent: 250,
        getHeight: () => {
          return 60;
        },
      },
    });
    this.state.contorlGraph = graph;
    // 渲染
    graph.data(this.state.treeData);
    graph.render();

    // 节点定位
    graph.focusItem(this.state.id, true, {
      easing: 'easeLinear',
      duration: 500,
    });

    // 历史折叠节点初始化
    graph.getNodes().forEach((e) => {
      for (let i = 0; i < str.length; i += 1) {
        if (e._cfg.id === str[i]?._cfg.id) {
          e.getModel().collapsed = !e.getModel().collapsed;
          graph.setItemState(e, 'collapsed', e.getModel().collapsed);
          graph.layout();
        }
      }
    });

    // 事件响应
    graph.on('node:click', (e) => {
      if (e.target.get('name') === 'collapse-icon') {
        e.item.getModel().collapsed = !e.item.getModel().collapsed;
        graph.setItemState(e.item, 'collapsed', e.item.getModel().collapsed);
        graph.layout();
      }
    });
  }
 类似资料: