Antv G6 force分布式布局 icon“+“ “-“收缩自定义,关系图子节点

子节点收缩

javascript 复制代码
    const collapseIcon = (x, y, r) => {
       // 折叠
       return [
         ['M', x - r, y],
         ['a', r, r, 0, 1, 0, r * 2, 0],
         ['a', r, r, 0, 1, 0, -r * 2, 0],
         ['M', x - r + 4, y],
         ['L', x - r + 2 * r - 4, y]
       ]
     }
     const expandIcon = (x, y, r) => {
       // 拓展
       return [
         ['M', x - r, y],
         ['a', r, r, 0, 1, 0, r * 2, 0],
         ['a', r, r, 0, 1, 0, -r * 2, 0],
         ['M', x - r + 4, y],
         ['L', x - r + 2 * r - 4, y],
         ['M', x - r + r, y - r + 4],
         ['L', x, y + r - 4]
       ]
     }
draw(cfg, group) {
      const { noSubsetSty, collapsed } = cfg
      if (noSubsetSty) { // 需要折叠的节点标志,在数据中处理添加标记
        group.addShape('circle', {
          attrs: {
            x: size,
            y: 0,
            r: 13,
            fill: 'rgba(47, 84, 235, 0.15)',
            opacity: 0,
            zIndex: -2
          },
          name: 'collapse-icon-bg'
        })
        group.addShape('marker', {
          attrs: {
            x: size,
            y: 0,
            r: 7,
            symbol: collapsed ? collapseIcon : expandIcon,
            stroke: 'rgba(0,0,0,1)',
            fill: 'rgba(0,0,0,0)',
            lineWidth: 1,
            cursor: 'pointer'
          },
          name: 'collapse-icon'
        })
      }
    },
    afterDraw(cfg, group) {
      const icon = group.find(
        element => element.get('name') === 'collapse-icon'
      )
      if (icon) {
        const bg = group.find(
          element => element.get('name') === 'collapse-icon-bg'
        )
        icon.on('mouseenter', () => {
          bg.attr('opacity', 1)
        })
        icon.on('mouseleave', () => {
          bg.attr('opacity', 0)
        })
      }
    },
    setState(name, value, item) {
      const group = item.getContainer()
      if (group.get('children')) {
        if (name === 'collapsed') {
          const marker = item
            .get('group')
            .findAll(ele => ele.get('name') === 'collapse-icon')
          marker[0] &&
            marker[0].attr('symbol', value ? collapseIcon : expandIcon)
          if (item._cfg.model.depth === 0) {
            marker[1] &&
              marker[1].attr('symbol', value ? collapseIcon : expandIcon)
          }
        }
      }
    }
javascript 复制代码
 this.graph.on('node:click', e => {
        // 处理子节点展示问题 + -
        if (e.target.get('name') === 'collapse-icon') {
          const item = e.item
          const nodeId = item.get('id')
          const children = selectedWorks(nodeId, regroup.nodes, regroup.edges) // 查询相关子节点
          let newNodes = children.nodes
          if (newNodes.length) {
            if (e.item._cfg.model.collapsed) {
              for (let i = 0; i < newNodes.length; i++) {
                this.hiddenElements.push(newNodes[i].id)
                const item = this.graph.findById(newNodes[i].id)
                this.graph.hideItem(item, true)
                this.graph.paint()
              }
            } else {
              for (let i = 0; i < newNodes.length; i++) {
                this.hiddenElements.splice(
                  this.hiddenElements.indexOf(newNodes[i].id),
                  1
                )
                const item = this.graph.findById(newNodes[i].id)
                this.graph.showItem(item, true)
                this.graph.paint()
              }
            }
          }
          this.graph.layout({
            type: 'force',
            nodeSize: 50,
            preventOverlap: true,
            animate: false,
            linkDistance: d => {
              return 80
            },
            nodeStrength: -150,
            onTick: () => {
              this.graph.refreshPositions()
            },
            nodeSpacing: d => {
              return 80
            }
          })
          e.item._cfg.model.collapsed = !e.item._cfg.model.collapsed
          this.graph.setItemState(
            e.item,
            'collapsed',
            e.item._cfg.model.collapsed
          )
          this.graph.paint()
        }
      })

节点查找方法

javascript 复制代码
/**
 * 只有被指向的点并且没有指向的点  找最末端的点,并且被指向的方向只有一个
 * source ---->  target
 */
export function noSubsetHandle(nodeID, edges) {
  let idT = edges.map(i => i.target)
  let idS = edges.map(i => i.source)
  Array.prototype.countCertainElements = function(value) {
    return this.reduce((sum, element) => (element == value ? sum + 1 : sum), 0)
  }
  let index = idT.countCertainElements(nodeID)
  let results =
    idT.indexOf(nodeID + '') > -1 &&
    index === 1 &&
    idS.indexOf(nodeID + '') === -1
  return results
}
/**
 * @description 依据节点ID 查询 子集 和 相关 边
 * @param {*} nodeID
 * @param {*} nodes
 * @param {*} edges
 */
export function selectedWorks(nodeID, nodes, edges) {
  let edgesV = []
  let nodesV = []
  edges.map(e => {
    if (+e.source === +nodeID) {
      edgesV.push({ ...e })
    }
  })
  if (edgesV.length > 0) {
    nodes.map(e => {
      if (edgesV.findIndex(x => +x.target === +e.id) > -1) {
        if (noSubsetHandle(+e.id, edges)) {
          nodesV.push({ ...e })
        }
      }
    })
  }
  let edgesVv= []
  edgesV.length && edgesV.map(i => {
    if (nodesV.findIndex(x => +x.id === +i.target) > -1) {
      edgesVv.push({...i})
    }
  })
  let obj = {}
  obj.nodes = nodesV
  obj.edges = edgesVv
  return obj
}
相关推荐
不简说16 小时前
JS 代码技巧 vol.6 — 20 个性能优化野路子,从渲染到网络全栈提速
前端·javascript·程序员
小岛前端16 小时前
展示!我 Vibe 了一个 Codex HUD
前端·ai编程
我是大卫16 小时前
【图】React源码解析-从源码数据结构、执行机制对比、闭包陷阱与最佳实践四个维度,深挖useMemo和useCallback的底层原理
前端·react.js·源码
不一样的少年_16 小时前
不用 LangChain,手搓 AI Agent:给大模型装上“手”,让它自己读项目文件
前端·人工智能·agent
索西引擎16 小时前
【React】useState 函数式更新机制:闭包陷阱规避与状态一致性保障分析
前端·react.js·前端框架
anyup16 小时前
从文本到具身:我给 AI Agent 搭了套实时 3D 交互身体
前端·人工智能·aigc
lichenyang45316 小时前
给弱模型一本说明书:我把文档规范做成单文件 Skill,也终于分清了 Skill 和 MCP
前端
贺国亚17 小时前
模型训练-分布式与GPU调度
分布式·wpf
咖啡无伴侣17 小时前
Vue3 DOM 异步更新与性能优化全套学习笔记
前端·vue.js
为了摸鱼而战17 小时前
OpenSpec + Superpowers + gstack 三器合一:你的 AI 编程终于可以从"拍脑袋"进化到"流水线"了
前端