美文网首页
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