「AntV」x6 节点换肤问题

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

场景来源于系统换肤,我的系统有换肤这个功能,一个是深色模式,一个是浅色模式,不同的模式要显示不同风格的节点配置,比如浅色模式下edge的颜色要为黑色,节点的图标也要换成浅色模式的......

如何重新初始化画布?

js 复制代码
// 使用计算属性获取当前系统模式(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
  });
  // 如果后面还有使用插件的地方就继续往下写
}

不通过加载画布配置?

如果不通过重载画布的方法,那我们就不需要定义两种配置了,只需要考虑怎么把所有的节点和线的配置给更新掉就行了。这里先说一下线的更改方法,因为线更新比较简单

js 复制代码
// 首先你得有监听主题色变化的方法
watch(theme, val => {
  // 先获取画布上的所有线
  const edges = graph.getEdges();
  // 对线进行遍历,根据主题动态设置线的颜色
  edges.forEach(item => {
    item.attr('line/stroke', val === 'light' ? '#4160ff' : '#028FA6'); // 将边的颜色设置为红色
  });
});

虽然现在把画布上所有线的颜色更新了,但是还有个问题:就是从连接桩拉出来的那个线的颜色还没有改,由于这个拉出来线的配置我是写在了一个单独的配置文件中,要想改这个配置那就必须得再重新加载画布配置,那岂不是又把问题引到通过初始化画布的方法去改样式了吗?于是乎开始在社区摇人,问问别人有没有遇到过类似的问题,果然有位大佬说她大概知道我的需求

监听从连接桩拉取线的事件,然后对这个edge进行更新颜色就行了

js 复制代码
graph.on('edge:changed', ({ edge }) => {
  edge.attr('line/stroke', theme.value === 'light' ? '#4160ff' : '#028FA6');
});

线的问题解决了,现在开始讲节点如何更新。我最初的想法是遍历所有的节点,然后把每一个节点data里面的图片字段更新下就行了,然后再重新渲染下节点;然而这个方法并没有奏效,反而还报错了......下面是我写的垃圾代码

js 复制代码
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又不报错......

js 复制代码
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来做,唉......,于是就有了下面这段终极代码

js 复制代码
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去挨个查询

html 复制代码
<div v-for="(item, index) in list" :key="index">
  <!-- 这个是画布容器,记得设置宽高 -->
	<div :id="'graph-' + item.id" class="model-img"></div>
</div>
js 复制代码
/**
 * 画布初始化配置
 * @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);
};
js 复制代码
// 节点渲染到对应的画布上
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模式


相关推荐
JarvanMo1 分钟前
我用 Ktor 替换了 Retrofit-我的网络代码减少了一半
前端
excel5 分钟前
WebGL 入门到进阶全解析:从 Canvas 上下文到 3D 绘制与 WebGL2 新特性
前端
掘金安东尼17 分钟前
用 WebGL + Solid.js 构建混合材质 Shader
前端·webgl
恋猫de小郭21 分钟前
Flutter 小技巧之有趣的 UI 骨架屏框架 skeletonizer
android·前端·flutter
江城开朗的豌豆22 分钟前
玩转React Hooks
前端·javascript·react.js
阿酷tony26 分钟前
教育场景下禁用html5播放器拖动进度条的例子
前端·html·html5·在线教育场景·禁止播放器拖动
前端小巷子1 小时前
Vue3 响应式革命
前端·vue.js·面试
一狐九1 小时前
Flutter如何通过GlobalKey调用组件内的方法
前端·flutter
wyzqhhhh1 小时前
前端如何处理首屏优化问题
前端
杨荧1 小时前
基于Python的反诈知识科普平台 Python+Django+Vue.js
大数据·前端·vue.js·python·数据分析