@antv/x6 动态添加更新连接桩(port)
首先通过自定义html节点,生成一个可以迭代多个子节点的模块cell,然后再定义一个进线连接桩(左),定义一系列出线连接桩(erPortPosition),在对连接桩进线增删改的时候,进行条件判断。
let that = this
Shape.HTML.register({
shape: 'condition',
width: 120,
height: 24,
effect: ['data'],
html(cell) {
const { label, props } = cell.getData()
const div = document.createElement('div')
div.className = 'custom-html'
div.style.width = 120
const titleDiv = document.createElement('div')
titleDiv.style.width = '120px'
titleDiv.style.height = '24px'
titleDiv.style.background = '#d4380d'
titleDiv.style.color = 'white'
titleDiv.style.fontSize = '14px'
titleDiv.style.paddingLeft = '8px'
titleDiv.style.lineHeight = '24px'
titleDiv.style.boxSizing = 'border-box'
titleDiv.style.whiteSpace = 'nowrap'
titleDiv.style.textOverflow = 'ellipsis'
titleDiv.style.overflow = 'hidden'
titleDiv.style.fontSize = '14px'
titleDiv.className = 'custom--html-title'
titleDiv.textContent = label
div.append(titleDiv)
props.children.map((item, index) => {
const itemDiv = document.createElement('div')
itemDiv.className = 'custom--html-item'
itemDiv.style.width = '120px'
itemDiv.style.height = '24px'
itemDiv.style.background = 'rgba(212, 56, 13, 0.2)'
itemDiv.style.color = '#666'
itemDiv.style.fontSize = '14px'
itemDiv.style.padding = '0 4px'
itemDiv.style.lineHeight = '22px'
itemDiv.style.boxSizing = 'border-box'
itemDiv.style.fontSize = '12px'
itemDiv.style.whiteSpace = 'nowrap'
itemDiv.style.textOverflow = 'ellipsis'
itemDiv.style.overflow = 'hidden'
itemDiv.style.border = '1px solid rgb(212, 56, 13)'
itemDiv.style.borderTop = 'none'
if (item.key === 'qi_ta_tiao_jian') {
itemDiv.textContent = `${item.label}`
} else {
itemDiv.textContent = `${that.$t('tiao_jian')}_${index + 1}`
}
div.append(itemDiv)
})
return div
},
})
this.r11 = this.graph.createNode({
shape: 'condition',
data: {
props: {
children: [],
random: ''
},
label: this.$t('tiao_jian_pan_duan')
},
ports: {
groups: {
right: {
position: 'erPortPosition',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#389e0d',
strokeWidth: 1,
fill: '#fff',
style: {
visibility: 'visible',
},
},
},
},
left: {
position: {
name: 'absolute',
args: { x: 0, y: 12 },
},
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#cf1322',
strokeWidth: 1,
fill: '#fff',
style: {
visibility: 'visible',
},
},
},
},
},
items: [
{
group: 'left',
},
],
}
})
erPortPosition是声明的自定义连接桩布局;
group将连接桩分为左右两个类别,左侧为进线连接桩,右侧为出线的;
const LINE_HEIGHT = 24
const NODE_WIDTH = 120
Graph.registerPortLayout(
'erPortPosition',
(portsPositionArgs) => {
return portsPositionArgs.map((_, index) => {
return {
position: {
x: NODE_WIDTH,
y: (index + 1) * LINE_HEIGHT + 12,
},
angle: 0,
}
})
},
true,
)
如图,对连接桩进线编辑的时候,可能会删除或者添加,有的时候还会跳转顺序,所以单纯的addPort(一直会在末尾处添加连接桩)并不能满足此需求,解决的思路是:
// data.id是当前cell.id
let cell = this.graph.getCellById(data.id)
// form.delPortArr是明确要删除的port数组
if (form.delPortArr.length > 0) { // delete port
form.delPortArr.map((item) => {
cell.removePort(item)
})
}
let edges = []
this.graph.toJSON().cells.forEach((item1) => {
if (item1.shape === 'edge' && item1.source.cell === data.id) {
edges.push(item1)
}
})
// form.conditionList是当前节点包含的子节点数组
form.conditionList.map((item) => {
if (!item.id) { // add port
cell.addPort({
group: 'right'
})
} else { // edit port
// delete old port and add new port , update new port by old port ID
cell.removePort(item.id)
cell.addPort({
group: 'right'
})
let lastPortId = cell.port.ports.pop().id
cell.setPortProp(lastPortId, 'id', item.id)
edges.forEach((item1) => {
if (item1.source.port === item.id) {
this.graph.addEdge(item1)
}
})
}
})
// 将portid赋值给children,这样html自定义生产子节点的时候,可以保持子节点id和对应的portid一致。
let _children = form.conditionList.map((item, index) => {
return {
...item,
id: cell.port.ports[index + 1].id
}
})
// 更新节点数据,以驱动html节点重新渲染
cell.prop('data', {
props: {
url: form.url,
children: _children
},
label: form.name
})
// 调整cell的尺寸
cell.prop('size', {
height: 24 * (form.conditionList.length + 1),
width: 120
})