功能描述 x6
1、对象模型新增、编辑、删除
2、模型字段新增、编辑、删除
3、模型关系新增、编辑、删除
4、点击事件添加工具及选中样式
5、拖拽移动
6、属性的展示与隐藏
7、模型复制
创建拖拽画布
import { Addon } from '@antv/x6'
const dnd = new Addon.Dnd({
target: this.graph
})
自定义er节点对象模型
import HeaderNode from "./components/HeaderNode.vue";
//注册节点
Graph.registerVueComponent(
"header",
{
template: ` `,
components: {
HeaderNode,
},
},
true
);
// 节点类型(attrsList:字段属性)
let limit = 10//设置字段属性个数限制(折叠与隐藏标志)
handleRegisterNode(item) {
let nodeHeight =
(item.height || LINE_HEIGHT) *
(((item.attrsList.length > limit ? limit : item.attrsList.length) || 1) +
1) +
3;
let node = {
...item,
width: item.width || NODE_WIDTH,//节点宽度
height: nodeHeight,//节点高度
component: "header",//注册的vue组件
zIndex: 0,//层级
data: {//传值数据
nodeData: {
...item,
show: item.attrsList.length > limit ? false : true,//折叠与隐藏
hoverId: null,
},
height: item.height || LINE_HEIGHT,
},
ports: {
zIndex: -9,
groups: {
list: {
zIndex: -9,
markup: [
{
tagName: "rect",
attrs: {
width: NODE_WIDTH,
height: 10,
strokeWidth: 0,
stroke: "transparent",
fill: "transparent",
},
},
],
},
},
items: item.portsList || [],//需要属性连线的字段属性集合
},
};
return node;
},
header-node自定义页面
{{nodeData}}
自定义连线
Graph.registerEdge(
"complex-edge-label",
{
inherit: "edge",
attrs: {
line: {
stroke: "#A2B1C3",
strokeWidth: 2,
targetMarker: {
name: "classic",
fill: "#A2B1C3", // 使用自定义填充色
},
},
},
connector: {
name: "rounded",
args: { radius: 10 },
},
labels: [
// label1
{
markup: [
{
tagName: "circle",
selector: "labelBody",
},
{
tagName: "image",
selector: "label",
},
],
attrs: {
label: {
width: 16,
height: 16,
x: -8,
y: -8,
cursor: "pointer",
},
labelBody: {
ref: "label",
r: 12,
fill: "#fff",
cursor: "pointer",
stroke: "#A2B1C3",
},
},
position: {
distance: 0.2,
args: {
keepGradient: true,
ensureLegibility: true,
},
},
},
// label 2
{
markup: [
{
tagName: "rect",
selector: "labelBody",
},
{
tagName: "text",
selector: "label",
},
],
attrs: {
label: {
fill: "#808695",
textAnchor: "middle",
textVerticalAnchor: "middle",
cursor: "pointer",
},
labelBody: {
ref: "label",
refX: -8,
refY: -5,
refWidth: "100%",
refHeight: "100%",
refWidth2: 16,
refHeight2: 10,
// stroke: "#ffa940",
strokeWidth: 1,
rx: 5,
ry: 5,
cursor: "pointer",
stroke: "#A2B1C3",
},
},
position: {
distance: 0.5,
},
},
// label3
{
markup: [
{
tagName: "circle",
selector: "labelBody",
},
{
tagName: "image",
selector: "label",
},
],
attrs: {
label: {
width: 16,
height: 16,
x: -8,
y: -8,
cursor: "pointer",
},
labelBody: {
ref: "label",
refY: "100%",
refY2: -0,
r: 12,
fill: "#fff",
cursor: "pointer",
stroke: "#A2B1C3",
},
},
position: {
distance: 0.8,
args: {
keepGradient: true,
ensureLegibility: true,
},
},
},
],
},
true
);
数据渲染
let data = [
//对象模型数据格式
{
"shape": "vue-shape",//vue类型shape
"width": 200,
"position": {
"x": 35,
"y": 200
},
"bgcolor": "rgb(255,243,203)",
"color": "rgb(253,226,130)",
"height": 30,
"id": "1",
"label": "学生",
"attrsList": [//er属性
{
"attrName": "attr1(属性1)",
"attrType": "String",
"id": "1-1",
"type": "1"
},
{
"attrName": "attr2(属性2)",
"attrType": "String",
"id": "1-2",
"type": "1"
},
{
"attrName": "attr3(属性3)",
"attrType": "String",
"id": "1-3",
"type": "1"
}
],
//er关系的关联属性集合
"portsList": [
{
"id": "1-1",
"group": "list"
}
],
},
//关系线数据格式
{
"id": "edge1",
"shape": "complex-edge-label",
"labels": [
{
"attrs": {
"xlink:href": "/svg/star.svg"
}
},
{
"attrs": {
"text": "关系表"
}
},
{
"attrs": {
"xlink:href": "/svg/1.svg"
}
}
],
"source": {
"port": "200-1",
"cell": "200"
},
"target": {
"port": "1-1",
"cell": "1"
},
"zIndex": 0
}
]
let cells = []
data.map(item=>{
if(item.shape == 'vue-shape'){
cells.push(this.handleRegisterNode(item))
}else{
cells.push(this.graph.createEdge(item))
}
})
this.graph.resetCells(cell)
模型ER新增
//监听节点新增
this.graph.on('node:added',({node})=>{
const {x,y} = node.position()
})
let newModel = this.graph.handleRegisterNode(data)
this.graph.addCell(newModel)
点击模型
this.graph.on('node:click',()=>{
this.currentModel.setZIndex(9);
this.currentModel.addTools([
{ name: "boundary" },
{
name: "button-remove", // 工具名称
args: { x: 10, y: 10 }, // 工具对应的参数
},
]);
})
更改模型数据
let { nodeData } = view.cell.getData();
nodeData.attrsList = []
view.cell.setData(
{ nodeData },
{
overwrite: true,
silent: true,
}
);
更改模型高度
this.currentModel.setProp(
{
size:{height:height},
{
overwrite: true,
silent: true,
}
}
)
删除模型
this.graph.removeCell(this.currentModel)
清空模型选中
this.graph.cleanSelection()
设置模型选中
let newNode = this.handleRegisterNode(data)
this.graph.select(newNode)
新增关联线
//先判断模型上是否有关联属性的port节点
let {source,target} = data
//不同模型连线
if(source.cell !== target.cell){
let sourceModel = this.graph.getCellById(source.cell)
let targetModel = this.graph.getCellById(target.cell)
if(!sourceModel.hasPort(source.port)){
sourceModel.addPort({
id:source.port,
group:'list'
})
}
if(!targetModel.hasPort(target.port)){
targetModel.addPort({
id:target.port,
group:'list'
})
}
}else{
//同模型连线
let currentModel = this.graph.getCellById(source.cell)
if(!currentModel.hasPort(source.port)){
currentModel.addPort({
id:source.port,
group:'list'
})
}
if(!currentModel.hasPort(target.port)){
currentModel.addPort({
id:target.port,
group:'list'
})
}
}
let newEdge = this.graph.createEdge(data)
this.graph.addCell(newEdge)
模型移动
this.graph.on('node.moved',({view,node})=>{
const {x,y} = node.position()
let params = {
id:view.cell.id,
positionX:x,
positionY:y
}
})
模型复制
this.graph.bindKey('ctrl+c',()=>{
const cells = this.graph.getSelectedCells();
if(cells.length){
this.graph.copy(cells)
}
})
this.graph.bindKey('ctrl+v',()=>{
if(!this.graph.isClipboardEmpty){
this.graph.paste({offset:{dx:220,dy:0}})
}
})