功能记录:根据业务需要对比echarts后使用antv X6的ER图,在基础上进行自定义样式修改。
- 使用前按需引入,可使用npm或者cdn连接,功能示例使用cnd在index.html中引入
- cdn引用地址:https://x6.antv.antgroup.com/tutorial/getting-started
- 官网示例地址:https://x6.antv.antgroup.com/examples
- 官网布局地址:https://x6.antv.antgroup.com/temp/layout#dagre
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>