问题1. 部分分组中节点拖拽添加或操作后撤销重做操作不生效。
前提:使用Stencil插件,创建画布侧边栏的 UI 组件,同时使用其分组、折叠能力。分组包含固定分组、后台接口获取的动态分组和组件。
//固定分组初始化
initStencil (graph, stencil) {
//defaultGroup是固定分组和其节点信息,自行添加
defaultGroup.forEach((gp, index) => {
const groupName = 'common-group' + index
const group = { name: groupName, title: gp.name || '未命名', collapsable: true }
stencil.addGroup(group)
const nodes = gp.children.map(item => {
let node
if (item.data.nodeType !== specilNodeType.GroupNodeType) {
node = graph.createNode({
shape: 'custom-vue-node',
width: 166,
height: 32,
data: { nodeGroup: gp.key, ...item, ...(item.data || {}), isStencil: true, data: null }
})
} else {
node = graph.createNode({
shape: 'group-vue-node',
width: 166,
height: 32,
data: { nodeGroup: gp.key, ...item, ...(item.data || {}), isStencil: true, data: null }
})
}
return node
})
stencil.load(nodes, groupName)
})
// 重要,动态添加分组后手动调用一下startListening,否则新增的分组无法监听鼠标按下事件
stencil.startListening()
},
//动态分组创建
createStencilNode (graph, stencil, componentList) {
Object.keys(componentList).forEach((key, index) => {
const groupName = 'group' + index
const group = { name: groupName, title: key || '未命名', collapsable: true }
stencil.addGroup(group)
const nodes = componentList[key].map(item => {
const {
abilityParamList = [],
serviceName = '未知',
productType,
resType,
serviceId,
serviceType,
serviceDescription,
tags,
icon, priority
} = item
const node = graph.createNode({
shape: 'custom-vue-node',
width: 166,
height: 32,
data: {
name: serviceName,
icon,
nodeGroup: key, // 分组
productType,
resType,
serviceId,
serviceType,
serviceDescription,
tags,
priority,
strategyConfig: [],
isStencil: true
}
})
return node
})
stencil.load(nodes, groupName)
})
// 重要,动态添加分组后手动调用一下startListening,否则新增的分组无法监听鼠标按下事件
stencil.startListening()
},
**问题:**固定分组中的节点拖拽入画布后画布的撤销重做操作无法使用,如果不拖拽加入固定分组中的节点,撤销重做操作正常。
解决:
由于固定分组是画图初始化完就添加的,而动态分组时后面通过接口返回添加的,为了避免新增的分组无法监听鼠标按下事件,固分别执行了stencil.startListening()方法。导致固定分组中执行了两个监听。固在第二次执行该方法前,调用stencil.stopListening()
取消之前的监听事件,这里添加在动态创建分组方法中
//动态分组创建
createStencilNode (graph, stencil, componentList) {
// 避免之前初始化的侧边节点拖拽后无法使用撤销重做操作问题
stencil.stopListening()
Object.keys(componentList).forEach((key, index) => {
const groupName = 'group' + index
const group = { name: groupName, title: key || '未命名', collapsable: true }
stencil.addGroup(group)
const nodes = componentList[key].map(item => {
const {
abilityParamList = [],
serviceName = '未知',
productType,
resType,
serviceId,
serviceType,
serviceDescription,
tags,
icon, priority
} = item
const node = graph.createNode({
shape: 'custom-vue-node',
width: 166,
height: 32,
data: {
name: serviceName,
icon,
nodeGroup: key, // 分组
productType,
resType,
serviceId,
serviceType,
serviceDescription,
tags,
priority,
strategyConfig: [],
isStencil: true
}
})
return node
})
stencil.load(nodes, groupName)
})
// 重要,动态添加分组后手动调用一下startListening,否则新增的分组无法监听鼠标按下事件
stencil.startListening()
},
问题2、使用Stencil的过滤能力时,过滤后分组高度无法根据过滤后的组件自适应。仍然保持过滤前的高度
前提: 使用Stencil插件的过滤功能
问题: Stencil中分组容器的高度在加载分组时就确定了。后面不会根据里面的节点个数改变,且里面的节点是通过svg标签包裹的,没办法动态设置其高度。
过滤前:
过滤后:
解决: 在过滤方法中为满足过滤条件的节点添加一个属性设置其为true,最后获取分组中包含该属性的节点,即过滤展示的节点,根据节点个数动态设置分组的高度。
import { Stencil } from '@antv/x6-plugin-stencil'
export default class GraphFlow {
//其他方法自行定义
graph;
stencil;
timer;
refreshStencilHeight (model, stencil) {
if (this.timer) {
clearTimeout(this.timer)
}
this.timer = setTimeout(() => {
Object.keys(model.groups).forEach(name => {
const nodes = model.graphs?.[name]?.model?.getNodes() || []
const index = nodes.filter(it => {
return it.getData()?.isMatched
})
const height = index.length * 36 + 18
stencil.resizeGroup(name, { height })
})
}, 500)
}
initStencil (stencilContainer) {
const that = this
const stencil = new Stencil({
title: '',
target: this.graph,
search (cell, keyword) {
const { name } = cell.getData() || {}
that.refreshStencilHeight(this, stencil)
if (name && name.indexOf(keyword) !== -1) {
// 标识过滤匹配成功,解决过滤后分组高度显示无法自适应问题
cell.setData({ isMatched: true })
}
return name && name.indexOf(keyword) !== -1
},
placeholder: '请输入',
notFoundText: '暂无数据',
stencilGraphWidth: 200, // 组宽度
stencilGraphHeight: 0, // 模板画布高度。设置为 0 时高度会自适应
// collapsable: true, // 如果不设置则第一个group的title显示不出来
groups: [
],
layoutOptions: {
columns: 1,
columnWidth: 180, // 这个值要和group的值对应要不然可能会定位不准确
rowHeight: 36, // 行高,会影响节点之间的高度间隔
resizeToFit: true
}
})
stencilContainer.appendChild(stencil.container)
this.stencil = stencil
}
}