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)
})
}
在地图上也能实现拓扑,涉及内部隐私不展示相关代码和图片