🖼️ | 根据条件加载不同的配置
场景来源于系统换肤,我的系统有换肤这个功能,一个是深色模式,一个是浅色模式,不同的模式要显示不同风格的节点配置,比如浅色模式下edge的颜色要为黑色,节点的图标也要换成浅色模式的……
如何重新初始化画布?
// 使用计算属性获取当前系统模式(light/dark)
const getTheme = computed(() => {
return theme.value;
})
// watch 监听主题变化重新初始化画布,initGraph 方法里面就是x6的那些七七八八的配置
watch(theme, val => {
initGraph(val);
// if (route.query.id) {
// getModelInfo(route.query.id);
// }
});
// initGraph的方法 currentTheme就是当前监听到的主题模式
const initGraph = currentTheme => {
let tempConfig = currentTheme === 'light' ? graphConfigLight : graphConfig;
// 这里必须要先销毁下再初始化
if (graph) {
graph.dispose();
}
graph = null;
graph = new Graph({
container: proxy.$refs.container,
width: '100%',
...tempConfig
});
// 如果后面还有使用插件的地方就继续往下写
}
不通过加载画布配置?
如果不通过重载画布的方法,那我们就不需要定义两种配置了,只需要考虑怎么把所有的节点和线的配置给更新掉就行了。这里先说一下线的更改方法,因为线更新比较简单
// 首先你得有监听主题色变化的方法
watch(theme, val => {
// 先获取画布上的所有线
const edges = graph.getEdges();
// 对线进行遍历,根据主题动态设置线的颜色
edges.forEach(item => {
item.attr('line/stroke', val === 'light' ? '#4160ff' : '#028FA6'); // 将边的颜色设置为红色
});
});
虽然现在把画布上所有线的颜色更新了,但是还有个问题:就是从连接桩拉出来的那个线的颜色还没有改,由于这个拉出来线的配置我是写在了一个单独的配置文件中,要想改这个配置那就必须得再重新加载画布配置,那岂不是又把问题引到通过初始化画布的方法去改样式了吗?于是乎开始在社区摇人,问问别人有没有遇到过类似的问题,果然有位大佬说她大概知道我的需求
监听从连接桩拉取线的事件,然后对这个edge进行更新颜色就行了
graph.on('edge:changed', ({ edge }) => {
edge.attr('line/stroke', theme.value === 'light' ? '#4160ff' : '#028FA6');
});
线的问题解决了,现在开始讲节点如何更新。我最初的想法是遍历所有的节点,然后把每一个节点data里面的图片字段更新下就行了,然后再重新渲染下节点;然而这个方法并没有奏效,反而还报错了……下面是我写的垃圾代码
watch(theme, val => {
const nodes = graph.getNodes();
nodes.forEach(item => {
const { img } = item.data;
if(val === 'light') {
item.data.img = item.data.img && item.data.img.replace('/operator/','/operator-light/')
}else {
item.data.img = item.data.img && item.data.img.replace('/operator-light/','/operator/')
}
});
// 再重新渲染节点
graph.fromJSON({nodes,edges})
});
既然不行,那就开始百度吧,于是就发现了一个新的api方法:resetCells,试了之后行是行了,但是没办法更新线,更新线后也是报错,更新node又不报错……
watch(theme, val => {
const nodes = graph.getNodes();
nodes.forEach(item => {
const { img } = item.data;
if(val === 'light') {
item.data.img = item.data.img && item.data.img.replace('/operator/','/operator-light/')
}else {
item.data.img = item.data.img && item.data.img.replace('/operator-light/','/operator/')
}
});
// 再重新渲染节点
graph.resetCells(nodes);
graph.resetCells(edges); // 开始报错了
});
最后我又把页面代码重新看了一遍,看到了之前写的一段更新节点的代码,到此才恍然大悟,自己一直想的是更新节点、更新节点、更新节点,但是就没想到用节点更新的api来做,唉……,于是就有了下面这段终极代码
watch(theme, val => {
const edges = graph.getEdges();
edges.forEach(item => {
item.attr('line/stroke', val === 'light' ? '#4160ff' : '#028FA6'); // 将边的颜色设置为红色
});
const nodes = graph.getNodes();
nodes.forEach(item => {
const { img } = item.data;
const themeIcon =
img &&
img.replace(
val === 'light' ? '/operator/' : '/operator-light/',
val === 'light' ? '/operator-light/' : '/operator/'
);
item.updateData({ img: themeIcon });
});
});
🖼️ | 列表渲染多个画布
场景
问题发生的源头还是换肤,切换到浅色模式要显示浅色风格的画布和节点;如果问题到这就结束了也还好,那我直接加载不同的配置就行了,然而问题并没有如此简单……
我的业务场景:在保存模型的时候,前端会顺带着一个模型的截图给后端,而这个截图的作用仅仅是列表展示使用,其它一无是处,但是换肤的时候得把这个截图换成浅色模式的截图,而且截图里面的节点也得是浅色模式的,问题到这里是不是觉得有点荒唐,是的,就是这么荒唐,此时截图已经生成保存在服务器上了,我要插上翅膀去改服务器上的资源吗?不不不~
解决方法
直接渲染多个画布,也就是说后端返回多少的列表,我这里就渲染多少个画布,不过这里要说下,每一条数据对应的节点数据要后端返回给前端,而不是前端拿着每一条记录的id去挨个查询
<div v-for="(item, index) in list" :key="index">
<!-- 这个是画布容器,记得设置宽高 -->
<div :id="'graph-' + item.id" class="model-img"></div>
</div>
/**
* 画布初始化配置
* @param {*} ids:这个是我从后端列表里面取的id唯一值给画布容器id赋值的
*/
let allGraph = [];
const initGraph = ids => {
ids.forEach(item => {
let form = new Graph({
container: document.getElementById('graph-' + item),
width: '100%',
...graphConfig // 这个就是有关画布的一些基础配置
});
allGraph.push(form);
});
console.log('graph >>>', allGraph);
};
// 节点渲染到对应的画布上
const handleNodeData = nodes => {
for (let n = 0; n < nodes.length; n++) {
// 获取每一个模型对应的节点数据
const nodeList = nodes[n].nodeVoList;
console.log('nodeList >>>>', nodeList);
let tempNodes = [];
let tempEdges = [];
for (let i = 0; i < nodeList.length; i++) {
let item = nodeList[i];
tempNodes.push({
id: item.id, // 节点id
shape: 'cu-data-node', // 自定义节点的名称
x: Number(item.xindex), // x轴坐标
y: Number(item.yindex), // y轴坐标
width: 100, // 默认宽度
height: 104, // 默认高度
data: {
name: item.name, // 节点名称
desc: '', // 数据量
opType: item.opType, // 算子类型
type: item.type, // 1数据源 2算子
img: getNodeImg(item.opType) // 图标
},
// 节点的连接桩
ports: {
...port,
items: [
{ group: 'left', id: 'port-left' },
{ group: 'right', id: 'port-right' }
]
}
});
// 连线数据处理
let preIds = [];
if (item.preNodeIds && item.preNodeIds != '') {
preIds = item.preNodeIds.split(',');
}
let nextIds = [];
if (item.nextNodeIds && item.nextNodeIds != '') {
nextIds = item.nextNodeIds.split(',');
}
if (preIds.length > 0) {
tempEdges = Array.from(new Set(tempEdges.map(JSON.stringify)), JSON.parse);
preIds.map(v => {
tempEdges.push({
source: { cell: v, port: 'port-right' },
target: { cell: item.id, port: 'port-left' },
attrs: edgeAttrs
});
});
}
if (nextIds.length > 0) {
tempEdges = Array.from(new Set(tempEdges.map(JSON.stringify)), JSON.parse);
nextIds.map(v => {
tempEdges.push({
source: { cell: item.id, port: 'port-right' },
target: { cell: v, port: 'port-left' },
attrs: edgeAttrs
});
});
}
allGraph[n].fromJSON(useDagLayout(tempNodes, tempEdges));
// allGraph[n].fromJSON({ nodes: tempNodes, edges: tempEdges });
allGraph[n].zoomTo(0.1);
allGraph[n].centerContent();
}
console.log('处理后的节点数据 >>>', tempNodes);
console.log('处理后的edge数据 >>>', tempEdges);
}
};