基于antv X6的ER图自定义功能样式

功能记录:根据业务需要对比echarts后使用antv X6的ER图,在基础上进行自定义样式修改。
demo截图示例

在这里插入图片描述

  • 上为demo图片,边框阴影部分为自定义配置项background,下面列表展示为配置项list,红字标注对应下面代码的key便于理解。
  • 有别于官网示例的表头和下面内容各自为主,主要将表头动态增加高度,使其展示在一个盒子内共用表头div,边框阴影部分定位到最顶层,下面内容配置区间高度动态渲染。
代码块
// html
<template>
  <div class="X6Echarts" id="X6Echarts"></div>
</template>

<script>
// 使用CDN引入布局功能,DagreLayout需要从window中取值
const { DagreLayout } = window.layout
// 自定义宽高变量
const LINE_HEIGHT = 24
const NODE_WIDTH = 240

export default {
  data() {
    return {
      graph: null,
    }
  },
  //mounted内为官网提供基础配置项,在其基础上增加background用于页面需求开发
  mounted() {
    X6.Graph.registerPortLayout(
      'erPortPosition',
      (portsPositionArgs) => {
        return portsPositionArgs.map((_, index) => {
          return {
            position: {
              x: 0,
              y: index ? (index + 1) * LINE_HEIGHT + 31 : 56,
            },
            angle: 0,
          }
        })
      },
      true,
    )

    // table头部默认配置项
    Graph.registerNode(
      'er-rect',
      {
        inherit: 'rect',
        // 区块定义
        markup: [
          {
            tagName: 'rect',
            selector: 'body',
          },
        ],
        // 区块默认样式定义
        attrs: {
          // 背景颜色
          rect: {
            strokeWidth: 1,
            stroke: '#1e2b3e',
          },
        },
        // table表格样式配置
        ports: {
          groups: {
            // background为自定义属性配置名称
            background: {
              position: {
                name: 'top',
                args: {
                  dx: -120, //表头偏移量,避免错位
                },
              },
              // 定义区块格式
              markup: [
                {
                  tagName: 'rect', //容器配置,必须项
                  selector: 'portBody',
                },
                {
                  tagName: 'image',
                  selector: 'bodyBg',
                },
                {
                  tagName: 'image',
                  selector: 'labelIcon',
                },
                {
                  tagName: 'text',
                  selector: 'portNameLabel',
                },
                {
                  tagName: 'image',
                  selector: 'img',
                },
                {
                  tagName: 'image',
                  selector: 'imgTopLine',
                }
              ],
              // 定义内容配置
              attrs: {
                portBody: {
                  width: NODE_WIDTH,
                  height: LINE_HEIGHT, //根据高度动态调整
                  strokeWidth: 0,
                  stroke: '#5F95FF',
                  fill: '#061e38',
                  magnet: false, // 关闭连线
                },
                bodyBg: {
                  'xlink:href': require('background.png'),
                  width: NODE_WIDTH,
                  height: 56,
                  x: 6,
                  y: 8,
                },
                labelIcon: {
                  'xlink:href': require('icon.png'),
                  width: 46,
                  height: 46,
                  x: 6,
                  y: 8,
                },
                portNameLabel: {
                  fontWeight: 'bold',
                  fill: '#fafafa',
                  fontSize: 12,
                  x: 55,
                  y: 28,
                },
                img: {
                  'xlink:href': require('status.png'),
                  width: 34,
                  height: 34,
                  x: 190,
                  y: 8,
                },
                imgTopLine: {
                  'xlink:href': require('topLine.png'),
                  width: 156,
                  height: 6,
                  x: 55,
                  y: 40,
                }
              }
            },
            // 表格内展示列表样式参数配置
            list: {
              markup: [
                {
                  tagName: 'rect',
                  selector: 'portBody',
                },
                {
                  tagName: 'text',
                  selector: 'portNameLabel',
                },
                {
                  tagName: 'text',
                  selector: 'portTypeLabel',
                },
              ],
              attrs: {
                portBody: {
                  width: NODE_WIDTH,
                  height: LINE_HEIGHT,
                  strokeWidth: 0,
                  fill: '#02060f',
                  magnet: false, // 关闭连线
                },
                portNameLabel: {
                  ref: 'portBody',
                  refX: 6,
                  refY: 6,
                  fontSize: 12,
                },
                portTypeLabel: {
                  ref: 'portBody',
                  refX: 95,
                  refY: 6,
                  fontSize: 12,
                  fill: '#a5cef8',
                },
              },
              position: 'erPortPosition',
            },
          },
        },
      },
      true,
    )

    this.graph = new X6.Graph({
      container: document.getElementById('X6Echarts'),
      interacting: true, // 表格节点是否可以拖动
      panning: {
        enabled: true, // 画布是否拖动
      },
      // 连接目标的连接点
      connecting: {
        router: 'orth',
        connector: {
          name: 'rounded',
          args: {},
        },
      },
      mouseWheel: true //鼠标是否缩放
    })
  },
  
  // methods内方法为处理后台数据,可根据需要自行优化
  methods: {
    // 调用后台接口进行数据赋值
    async handGetNodeData(taskId) {
      let data = await getTaskNode(taskId) //getTaskNode为封装过的接口请求
      let dataArr = data.value || []

      // 定义cells为转换获取到的数据格式为X6节点连线使用,内部key值不可更改
      const cells = {
        nodes: [],
        edges: [],
      }

      dataArr.forEach((item) => {
        // newitem为将后台返回数据转换为渲染节点数据,需要进行动态赋值
        let newitem = this.handSortItem(item)
        newitem.ports = [...this.getPortsByType(item), ...newitem.ports]
        cells.nodes.push(newitem)

        // item.targets为后台告诉前台哪些需要连线的节点,格式可[节点1]
        if (item.targets) {
          item.targets.forEach((v) => {
            let newLine = this.HandSortLine(item, v)
            cells.edges.push(newLine)
          })
        }
      })

      // 根据当前要展示的数据动态修改表头整体高度
      cells.nodes.forEach((node) => {
        node.height = node.ports.length * 24 + 24
      })

      // 添加插件布局,可参考官网配置项
      const dagreLayout = new DagreLayout({
        type: 'dagre', //布局类型
        rankdir: 'LR', //布局的方向
        align: 'UL', //节点对齐方式
        ranksep: 30, //层间距
        nodesep: 15, //节点之间间距
      })
      // 节点渲染
      const model = dagreLayout.layout(cells)
      this.graph.fromJSON(model)
    },
    // 动态转换数据渲染格式并返回
    handSortItem(item) {
      let obj = {}
      // 定义表头key及样式
      obj = {
        id: item.id,
        shape: 'er-rect',
        label: item.label,
        width: NODE_WIDTH,
        height: LINE_HEIGHT,
        attrs: {
          rect: {
            fill: '#02060f',
          },
        },
        ports: [],
      }
      // 动态渲染表格内列表展示数据
      item.portArr.forEach((v) => {
        obj.ports.push({
          id: v.id,
          group: 'list', // 列表样式使用上面定义的list配置
          // portNameLabel这些key要对应上面在mounted里面初始化定义的配置
          attrs: {
            portNameLabel: {
              text: v.text,
            },
            portTypeLabel: {
              text: v.status,
            },
          }
        })
      })
      return obj
    },
    // 自定义ports节点数据
    getPortsByType(item) {
      let ports = []
      ports = [
        {
          id: 'header',
          group: 'background', // 使用上面自定义的background配置
          // 根据返回数据节点重新赋值
          attrs: {
            portNameLabel: {
              text: item.text, //返回的节点名称
            },
            img: {
              'xlink:href': item.imgUrl,
            },
          },
        },
      ]
      return ports
    },
    // 节点连线
    handSortLine(item, lineKey) {
      let lineItem = {}
      // 默认key需要参考官网
      lineItem = {
        id: item.id,
        shape: 'edge',
        source: item.id, // 从哪个节点出发
        target: lineKey, //连接到哪个节点
        connector: {
          name: 'rounded',
          args: {
            radius: 20,
          }
        },
        zIndex: 0,
      }
      return lineItem
    },
  }
}
</script>
  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值