「AntV」x6 节点换肤问题

🖼️ | 根据条件加载不同的配置

场景来源于系统换肤,我的系统有换肤这个功能,一个是深色模式,一个是浅色模式,不同的模式要显示不同风格的节点配置,比如浅色模式下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);
  }
};

截图

dark模式

light模式


  • 30
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值