美文网首页
G6配置实现折叠、路径高亮效果

G6配置实现折叠、路径高亮效果

作者: 海豚先生的博客 | 来源:发表于2020-04-10 12:58 被阅读0次
<template>
  <div class="tableau">
    <div id="container"></div>
  </div>
</template>
<script>
/* eslint-disable */
import G6 from "@antv/g6";
import { data } from "./json";
export default {
  data () {
    return {
      msg: "hello",
      branchData: [],
      isInit: true
    };
  },
  mounted () {
    let _this = this
    // 减号icon
    const COLLAPSE_ICON = function COLLAPSE_ICON (x, y, r) {
      return [
        ["M", x, y],
        ["a", r, r, 0, 1, 0, r * 2, 0],
        ["a", r, r, 0, 1, 0, -r * 2, 0],
        ["M", x + 2, y],
        ["L", x + 2 * r - 2, y]
      ];
    };
    // 加号icon
    const EXPAND_ICON = function EXPAND_ICON (x, y, r) {
      return [
        ["M", x, y],
        ["a", r, r, 0, 1, 0, r * 2, 0],
        ["a", r, r, 0, 1, 0, -r * 2, 0],
        ["M", x + 2, y],
        ["L", x + 2 * r - 2, y],
        ["M", x + r, y - r + 2],
        ["L", x + r, y + r - 2]
      ];
    };
    // 自定义节点名称,需要和defaultNode中的type类型一致
    G6.registerNode(
      "tree-node",
      {
        labelPosition: "center",
        labelAutoRotate: true,
        options: {
          style: {},
          stateStyles: {
            hover: {},
            selected: {}
          }
        },
        // 以下方法只用于自定义节点和边的情形
        draw (cfg, group) {

          let depth = cfg.depth
          let nodeid = cfg.id
          let attrs = {}
          // 对结构层级进行判断 level 为后端提供的参数
          if (cfg.depth === 0) {
            attrs = {
              stroke: '#665ba9'
            }
          }
          else if (cfg.depth === 1) {
            attrs = {
              stroke: '#356bb5'
            }
          }
          else if (cfg.depth === 2) {
            attrs = {
              stroke: '#49c8e8'
            }
          }
          else if (cfg.depth === 3) {
            attrs = {
              stroke: '#70be50'
            }
          }
          else if (cfg.depth === 4) {
            attrs = {
              stroke: '#f6ea46'
            }
          }
          // console.log('draw:', cfg)
          // 边中部显示文字
          graph.edge(() => {
            return {
              label: cfg.uv,
              style: {
                stroke: "blue"
              },
              labelCfg: {
                position: "center",
                // refX: -20,
                // refY: 0,
                style: {
                  fill: "green",
                  stroke: "#f4f7f8",
                  lineWidth: 10
                }
              }
            };
          });

          // 元素的形状、填充色、描边颜色
          attrs.fill = '#fff'
          const rect = group.addShape("rect", {
            attrs: attrs
          });
          // 指标描述 5项指标
          let nameList = [cfg.nameCN, cfg.name, 'visit:' + cfg.visit, 'uv:' + cfg.uv, 'pv:' + cfg.pv]
          let bbox
          for (let i = 0; i < 5; i++) {
            if (cfg.level !== 1) {
              if (i > 1) {
                continue
              }
            }
            // 节点内容超过19的长度后换行
            let content = nameList[i].replace(/(.{19})/g, "$1\n");
            // 节点内文本样式
            let texts = group.addShape("text", {
              attrs: {
                text: content,
                x: 0,
                y: i * 20 + 6,
                textAlign: "left",
                textBaseline: "middle",
                fill: "#666",
              }
            });
            // 使用第一行文字作为起始边界画矩形
            if (i === 0) {
              bbox = texts.getBBox();
            }
            let bboxOther = texts.getBBox();
          }
          // 文本左边padding,节点宽高
          // 是否显示展开和收起icon
          const hasChildren = cfg.children && cfg.children.length > 0;
          if (hasChildren) {
            group.addShape("marker", {
              attrs: {
                x: 150,
                y: cfg.level === 1 ? 50 : 13,
                // 是否有子项目的 icon,icon的位置
                r: 6,
                symbol: EXPAND_ICON,
                stroke: "#666",
                lineWidth: 2
              },
              className: "collapse-icon"
            });
            // 初始化时0层展开icon
            if (_this.isInit) {
              const icon = group.findByClassName("collapse-icon");
              if (cfg.depth === 0 && hasChildren) {
                icon.attr("symbol", COLLAPSE_ICON);
              } else {
                // 新增的展开的节点的状态
                if (hasChildren) {
                  icon.attr("symbol", EXPAND_ICON);
                  cfg.collapsed = true
                } else {
                  icon.attr("symbol", COLLAPSE_ICON);
                  cfg.collapsed = false

                }
              }
            }
          }
          rect.attr({
            x: bbox.minX - 4,
            y: bbox.minY - 6,
            width: 180,
            height: cfg.level === 1 ? 120 : 50,
            lineWidth: 2
          });
          console.log('draw:', cfg);
          // 必须有返回值
          return rect;
        }
      },
      // "single-shape"
      "rect"
    );

    const width = document.getElementById("container").scrollWidth || 800;
    // const width = 1000;
    const height = document.getElementById("container").scrollHeight;

    const graph = new G6.TreeGraph({
      container: "container",
      width,
      height,
      modes: {
        default: [
          {
            type: "collapse-expand",
            onChange (item, collapsed) {
              console.log('onchange:', item);

              _this.isInit = false
              // 点击node节点,展开此节点,收缩其他同级节点及其所有子节点
              // 是否有父节点
              let farNode = item._cfg.parent && item._cfg.parent._cfg.id
              console.log('是否有父节点', farNode);
              let siblingNode
              function collapseNode (children) {
                children.forEach(el => {
                  console.log('el:', children, el, el._cfg.id);
                  // debugger
                  const data = el.get('model');
                  const icon = el.get("group").findByClassName("collapse-icon");
                  if (!icon) return
                  icon.attr("symbol", EXPAND_ICON);
                  let isChildren = el._cfg.children && el._cfg.children.length > 0
                  if (isChildren) {
                    console.log('有子节点', el._cfg.children);
                    // debugger
                    collapseNode(el._cfg.children)
                    // 先关闭子节点后关闭父节点
                    console.log('关闭子节点');
                    data.collapsed = true;
                  }
                })
              }
              // 当前有父节点
              if (farNode) {
                // 获取兄弟节点
                siblingNode = item._cfg.parent._cfg.children
                if (siblingNode.length > 0 && siblingNode) {
                  collapseNode(siblingNode)
                }
              } else {
                // 当前是根节点
                collapseNode(item._cfg.children)
              }
              // let siblingNode = item._cfg.parent._cfg.children
              console.log('该节点的兄弟节点', siblingNode);
              console.log('item:', item);
              console.log('collapsed:', collapsed);



              // 折叠展开节点
              const data = item.get("model");
              const icon = item.get("group").findByClassName("collapse-icon");

              if (collapsed) {
                icon.attr("symbol", EXPAND_ICON);
              } else {
                icon.attr("symbol", COLLAPSE_ICON);
              }
              data.collapsed = collapsed;
              console.log("onchange collapsed:", collapsed);
              console.log("onchange item:", item)
              console.log("onchange data:", data)
              console.log("onchange icon:", icon)
              return true;
            }
          },
          {
            type: 'tooltip',
            formatText: function formatText (data, res) {
              if (data.level === 1) {
                return ''
              }
              return `<div class="tooltip-inner"><div>visit:${data.visit}</div>
              <div>uv:${data.uv}</div>
              <div>pv:${data.pv}</div></div>
              `;
            }
          },
          "drag-canvas",
          "zoom-canvas"
        ]
      },
      defaultNode: {
        type: "tree-node",
        anchorPoints: [
          [0, 0.5],
          [1, 0.5]
        ]
      },
      defaultEdge: {
        // 边的曲线类型
        type: "cubic-horizontal",
        style: {
          stroke: "#A3B1BF"
        }
      },
      // 节点在各状态下的样式
      nodeStateStyles: {
        // hover 状态为 true 时的样式
        hover: {
          fill: "lightsteelblue"
        },
        // click 状态为 true 时的样式
        click: {
          stroke: "red",
          lineWidth: 3
        }
      },
      // 边在各状态下的样式
      edgeStateStyles: {
        // click 状态为 true 时的样式
        click: {
          stroke: "red",
          lineWidth: 3
        }
      },
      layout: {
        type: "compactBox",
        direction: "LR",
        getId (d) {
          return d.id;
        },
        getHeight () {
          return 16;
        },
        getWidth () {
          return 10;
        },
        // 节点之间垂直距离
        getVGap () {
          return 30;
        },
        // 节点之间水平距离
        getHGap () {
          return 150;
        }
      }
    });
    // 事件
    // 监听鼠标点击节点
    graph.on("node:click", e => {
      // 先将所有当前有 click 状态的节点的 click 状态置为 false
      const clickNodes = graph.findAllByState("node", "click");
      clickNodes.forEach(cn => {
        graph.setItemState(cn, "click", false);
      });
      // 找到所有的节点
      let realnode = [];
      let nodeList = graph.getNodes();

      let id = e.item._cfg.id;
      realnode.push(e.item);
      let pid = e.item._cfg.model.pid;
      function deepMap (pid) {
        nodeList.forEach((item, i) => {
          if (item._cfg.id === pid) {
            realnode.push(item);
            if (item._cfg.model.pid) {
              deepMap(item._cfg.model.pid);
            }
          }
        });
      }
      deepMap(pid);
      realnode.forEach(cn => {
        graph.setItemState(cn, "click", true);
      });
      const nodeItem = e.item;
      // 设置目标节点的 click 状态 为 true
      // graph.setItemState(nodeItem, "click", true);
      // 先将所有当前有 click 状态的边的 click 状态置为 false
      {
        const clickEdges = graph.findAllByState("edge", "click");
        clickEdges.forEach(ce => {
          graph.setItemState(ce, "click", false);
        });
        let edgeList = graph.getEdges();
        let realedge = [];
        let ids = e.item._cfg.id;
        let pid = e.item._cfg.model.pid;
        function deepMap (pid) {
          edgeList.forEach((item, i) => {
            // console.log(item)
            // console.log(item._cfg.id)
            let id = item._cfg.id.split(":")[1];
            if (id == pid) {
              realedge.push(item);
              if (item._cfg.id.split(":")[0]) {
                deepMap(item._cfg.id.split(":")[0]);
              }
            }
            if (id == ids) {
              realedge.push(item);
            }
          });
        }
        deepMap(pid);

        realedge.forEach(ce => {
          graph.setItemState(ce, "click", true);
        });
        // graph.setItemState(edgeItem, 'click', true);
      }
    });
    console.log('data:', data)
    // 排序
    function sortNode (childList) {
      // console.log(childList)
      childList.sort((a, b) => b.uv - a.uv)
      childList.forEach(item => {
        if (item.childList) {
          sortNode(item.childList)
        }
      })
    }
    sortNode(data.childList)


    G6.Util.traverseTree(data, function (item) {
      // 折叠所有节点
      item.collapsed = true
      item.id = item.mid;
      item.children = item.childList;
      // console.log(item)
    });

    // 默认展开一层
    data.collapsed = false
    graph.data(data);
    graph.render();
    graph.fitView(50);
  }
};
</script>
<style lang="scss">
.tableau {
  height: 100%;
  #container {
    height: 100%;
    border: 2px solid green;
    .g6-tooltip {
      .tooltip-inner {
        border: 1px solid #e2e2e2;
        border-radius: 4px;
        font-size: 16px;
        color: #545454;
        background-color: rgb(255, 255, 255);
        padding: 10px 28px;
        box-shadow: rgb(174, 174, 174) 0px 0px 10px;
      }
    }
  }
}
</style>

相关文章

网友评论

      本文标题:G6配置实现折叠、路径高亮效果

      本文链接:https://www.haomeiwen.com/subject/koqrmhtx.html