从0到1设计g6力拓扑图-光缆

109 阅读2分钟

g6力拓扑图使用

概念

Force 力导向布局

centeripetalOptions

1.1向心力配置
centripetalOptions 向心力配置
clustering 是否需要全部聚类
clusterNodeStrength 防止重叠的力强度
collideStrength 库伦系数

1.交互行为
G6内置了一系列交互行为,可以直接使用。可以一键开启交互
  • drag-canvas:拖拽画布
  • zoom-canvas:缩放画布
2.交互管理
Mode是G6 mode组合,
default默认交互模式,addNode增加节点交互模式,addEdge增加交互模式
 // 交互模式集合
  modes: {
    // 默认交互模式
    default: ['drag-node', 'click-select'],
    // 增加节点交互模式
    addNode: ['click-add-node', 'click-select'],
    // 增加边交互模式
    addEdge: ['click-add-edge', 'click-select'],
  },

1.注册组件

1.1注册节点

export function registerNode(css)
{
for(let i=0;i<17;i++)
{
  G6.registerNode('node-'+i,{
   draw(cfg,group)
   {
const ketShape = group.addShape('image',{
attrs:{
x:-15,
y:-15,
width: 30,
height:30,
img:ImgList[i-1]
},
name:'image'
})
group.addShape('text',{
attrs:{
x:0,
y:0,
text:cfg.label|| '',
fill:css=='dark'?'#fff':'#262626',
fontSize:12,
textAaligin:'center',
textBaseline:'middle'
},
name:'node-label'
})
return keyShape
}
},
'sigle-node'
)
}
}
2.1注册边
G6.registerEdge('edge-topo',{
option:{
   style:{
   stroke:'#009994',
   lineWidth:1
   }
},
draw(cfg,group)
{
const startPoint = cfg.startPoint
cosnt endPoint = cfg.endPoint
​
const path = [
['M',startPoint.x,startPoint.y],
['L',endPoint.x,endPoint.y]
]
const keyShape = group.addShape('path',{
attrs:{
path:path,
stroke:css=='dark'? '#fff':'#009994',
lineWidth:1
}
name:'edge-path'
})
//添加标签
if(cfg.label)
{
 cosnt midPointX = (startPoint.x  + endPointx) / 2
 const midPointY = (startPoint.y + endPoint.y)/2
 
 group.addShape('text',{
 attrs:{
 text:cfg.label,
 x:midPointX,
 y:midPointY,
 fill:css === 'dark'? '#fff':'#262626',
 fontSize:12,
 textAlign:'center',
 textBaseline:'middle'
 },
 name:'edge-label'
 })
 }
return keyShape
}
})

3.1注册高亮边

G6.registerEdge('edge-height',{
 options:{
 style:{
 stroke:'#6A9AF5',
 lineWidth:5
 }
 },
 draw(cfg,group)
 {
 const startPoint = cfg.startPoint
 const endPoint = cfg.endPoint
 const keyShape = group.addShape('path',{
 attrs:{
 path:[
 ['M',startPoint.x,startPoint.y],
 ['L',endPoint.x,endPont.y]
 ],
 stroke:'#6A9AF5',
 lineWidth:5
 },
 nmae:'edge-path'
 })
 
 return  keyShape
 }
​
})

2.添加组件到画布

export function addWyNode(meList, topoLinkList) {
  const nodes = []
  const edges = []
  const edgeCountMap = new Map()
​
  meList.forEach(point => {
    const typeIndex = wyTypeList.findIndex(item => item == point.dydj) + 1
    nodes.push({
      id: point.keyId,
      type: 'wy-node-' + typeIndex,
      label: point.name
    })
  })
​
  // 首先统计每条边的出现次数
  topoLinkList.forEach(line => {
    const edgeKey = `${line.source}-${line.target}`
    if (edgeCountMap.has(edgeKey)) {
      edgeCountMap.set(edgeKey, edgeCountMap.get(edgeKey) + 1)
    } else {
      edgeCountMap.set(edgeKey, 1)
    }
  })
​
  // 根据统计结果设置边的名称
  topoLinkList.forEach(line => {
    const valid1 = hasNode(line.source, meList)
    const valid2 = hasNode(line.target, meList)
    if (valid1 && valid2) {
      const edgeKey = `${line.source}-${line.target}`
      let edgeName
      let namebak = line.name
​
      if (edgeCountMap.get(edgeKey) === 1) {
        edgeName = line.name // 出现次数为1,使用原始名称
      } else {
        const count = edgeCountMap.get(edgeKey)
        edgeName = `${count}` // 出现次数大于1,使用数字
      }
​
      edges.push({
        id: line.id,
        type: 'edge-topo',
        source: line.source,
        target: line.target,
        name: edgeName,
        namebak: namebak
      })
    } else {
      console.log(
        'line.nativeEmsName:',
        line.nativeEmsName,
        'line.source:',
        line.aemsSn,
        'target',
        line.zemsSn
      )
    }
  })
​
  return { nodes, edges }
}

G6渲染

1.左侧树选择,右侧树渲染
2.查询光缆下的站点节点
3.注册g6组件
4.重复起点,终点的光缆,线显示重叠的数字,弹窗显示所有的名称
 const handleConfirm = () => {
    const checkedKeysString = checkedKeys.join(',')
​
    TestServer.getPatrolPointListByOpticalId({ // 
      opticalIds: checkedKeysString
    })
      .then(response => {
        const res = response.data
        const updatedMeList = res
        console.log('updatedMeList:', updatedMeList)
        registerNode(CssType)
        const { nodes, edges } = addWyNode(updatedMeList, topoLinkList)
        console.log('nodes:', nodes, 'edges:', edges)
​
        edges.forEach(edge => {
          edge.label = edge.name
        })
​
        // 销毁旧的图实例
        if (graphInstance.current) {
          graphInstance.current.destroy()
        }
        graphInstance.current = new G6.Graph({
          container: graphContainer.current,
          width: graphContainer.current.clientWidth,
          height: 800,
          background: { fill: '#000000' },
          modes: {
            default: [
              'drag-node',
              'zoom-canvas',
              'drag-canvas',
              {
                type: 'edge-tooltip',
                formatText: function formatText(model, e) {
                  const currentEdge = e.item.getModel()
                  const allEdges = graphInstance.current.getEdges()
                  let edgeNames = []
​
                  if (!isNaN(currentEdge.name)) {
                    allEdges.forEach(edge => {
                      const edgeModel = edge.getModel()
                      if (
                        edgeModel.source === currentEdge.source &&
                        edgeModel.target === currentEdge.target
                      ) {
                        edgeNames.push(edgeModel.namebak || '')
                      }
                    })
                  } else {
                    edgeNames.push(currentEdge.namebak || '')
                  }
​
                  return `<div class="${style.g6TooltipEdge}">${edgeNames.join(
                    '<br/>'
                  )}</div>`
                }
              }
            ]
          },
          layout: {
            type: 'force',
            preventOverlap: true,
            linkDistance: 180,
            nodeSpacing: 85,
            alpha: 1,
            alphaDecay: 0.05
          }
        })
​
        // 加载新数据并渲染
        graphInstance.current.data({ nodes, edges })
        graphInstance.current.render()
      })
      .catch(error => {
        console.error('接口调用错误:', error)
      })
  }

image-20250213125138247.png

image-20250213125105066.png 在地图上也能实现拓扑,涉及内部隐私不展示相关代码和图片