ertop图完成
This commit is contained in:
parent
f6bfe30d7e
commit
4752ce1d4c
|
|
@ -1,93 +0,0 @@
|
||||||
/**
|
|
||||||
* @author: clay
|
|
||||||
* @data: 2019/07/05
|
|
||||||
* @description: edit mode: 通过先后点击两个节点来添加连线(容易和节点点击动作交叉,已弃用)
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'click-add-edge',
|
|
||||||
options: {
|
|
||||||
getEvents() {
|
|
||||||
return {
|
|
||||||
'node:click': 'onNodeClick',
|
|
||||||
'canvas:mousemove': 'onMousemove',
|
|
||||||
'edge:click': 'onEdgeClick' // 点击空白处,取消边
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onNodeClick(event) {
|
|
||||||
let graph = this.graph
|
|
||||||
let node = event.item
|
|
||||||
let point = { x: event.x, y: event.y }
|
|
||||||
let model = node.getModel()
|
|
||||||
let edgeShape = self.currentEdgeShape.guid || 'line'
|
|
||||||
if (this.addingEdge && this.edge) {
|
|
||||||
// 点击第二个节点
|
|
||||||
graph.updateItem(this.edge, {
|
|
||||||
target: model.id
|
|
||||||
})
|
|
||||||
this.edge = null
|
|
||||||
this.addingEdge = false
|
|
||||||
// 记录【连线】前后的数据状态
|
|
||||||
if (this.historyData) {
|
|
||||||
let graph = this.graph
|
|
||||||
// 如果当前点过【撤销】了,连线后没有【重做】功能
|
|
||||||
// 重置undoCount,连线后的数据给(当前所在historyIndex + 1),且清空这个时间点之后的记录
|
|
||||||
if (self.undoCount > 0) {
|
|
||||||
self.historyIndex = self.historyIndex - self.undoCount // 此时的historyIndex应当更新为【撤销】后所在的索引位置
|
|
||||||
for (let i = 1; i <= self.undoCount; i++) {
|
|
||||||
let key = `graph_history_${self.historyIndex + i}`
|
|
||||||
self.removeHistoryData(key)
|
|
||||||
}
|
|
||||||
self.undoCount = 0
|
|
||||||
} else {
|
|
||||||
// 正常顺序执行的情况,记录【连线】前的数据状态
|
|
||||||
let key = `graph_history_${self.historyIndex}`
|
|
||||||
self.addHistoryData(key, this.historyData)
|
|
||||||
}
|
|
||||||
// 记录【连线】后的数据状态
|
|
||||||
self.historyIndex += 1
|
|
||||||
let key = `graph_history_${self.historyIndex}`
|
|
||||||
let currentData = JSON.stringify(graph.save())
|
|
||||||
self.addHistoryData(key, currentData)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 点击第一个节点
|
|
||||||
this.historyData = JSON.stringify(graph.save())
|
|
||||||
if (edgeShape === 'stepline') {
|
|
||||||
this.edge = graph.addItem('edge', {
|
|
||||||
source: model.id,
|
|
||||||
target: point,
|
|
||||||
type: edgeShape,
|
|
||||||
controlPoints: [{ x: 100, y: 70 }]
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.edge = graph.addItem('edge', {
|
|
||||||
source: model.id,
|
|
||||||
target: point,
|
|
||||||
type: edgeShape
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.addingEdge = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onMousemove(event) {
|
|
||||||
const point = { x: event.x, y: event.y }
|
|
||||||
if (this.addingEdge && this.edge) {
|
|
||||||
this.graph.updateItem(this.edge, {
|
|
||||||
target: point
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onEdgeClick(ev) {
|
|
||||||
let graph = this.graph
|
|
||||||
const currentEdge = ev.item
|
|
||||||
// 拖拽过程中,点击会点击到新增的边上
|
|
||||||
if (this.addingEdge && this.edge === currentEdge) {
|
|
||||||
graph.removeItem(this.edge)
|
|
||||||
this.edge = null
|
|
||||||
this.addingEdge = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,173 +0,0 @@
|
||||||
/**
|
|
||||||
* @author: winyuan
|
|
||||||
* @data: 2019/07/16
|
|
||||||
* @repository: https://github.com/winyuan
|
|
||||||
* @description: edit mode: 鼠标点击交互
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 用来获取调用此js的vue组件实例(this)
|
|
||||||
let vm = null;
|
|
||||||
|
|
||||||
const sendThis = (_this) => {
|
|
||||||
vm = _this;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
sendThis, // 暴露函数
|
|
||||||
name: "click-event-edit",
|
|
||||||
options: {
|
|
||||||
getEvents() {
|
|
||||||
return {
|
|
||||||
"node:click": "onNodeClick",
|
|
||||||
"node:contextmenu": "onNodeRightClick",
|
|
||||||
"edge:click": "onEdgeClick",
|
|
||||||
"edge:contextmenu": "onEdgeRightClick",
|
|
||||||
"canvas:click": "onCanvasClick",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
onNodeClick(event) {
|
|
||||||
// todo..."selected"是g6自带的状态,在"drag-add-edge"中的"node:mouseup"事件也会触发,故此处不需要设置"selected"状态
|
|
||||||
// let clickNode = event.item;
|
|
||||||
// clickNode.setState('selected', !clickNode.hasState('selected'));
|
|
||||||
|
|
||||||
|
|
||||||
vm.currentFocus = "node";
|
|
||||||
vm.rightMenuShow = false;
|
|
||||||
this.updateVmData(event);
|
|
||||||
},
|
|
||||||
onNodeRightClick(event) {
|
|
||||||
let graph = vm.graph;
|
|
||||||
let clickNode = event.item;
|
|
||||||
let clickNodeModel = clickNode.getModel();
|
|
||||||
let selectedNodes = graph.findAllByState("node", "selected");
|
|
||||||
let selectedNodeIds = selectedNodes.map(item => {
|
|
||||||
return item.getModel().id;
|
|
||||||
});
|
|
||||||
vm.selectedNode = clickNode;
|
|
||||||
// 如果当前点击节点是之前选中的某个节点,就进行下面的处理
|
|
||||||
if (selectedNodes.length > 1 && selectedNodeIds.indexOf(clickNodeModel.id) > -1) {
|
|
||||||
vm.rightMenuShow = true;
|
|
||||||
let rightMenu = vm.$refs.rightMenu;
|
|
||||||
rightMenu.style.left = event.clientX + "px";
|
|
||||||
rightMenu.style.top = event.clientY + "px";
|
|
||||||
} else {
|
|
||||||
// 隐藏右键菜单
|
|
||||||
vm.rightMenuShow = false;
|
|
||||||
// 先取消所有节点的选中状态
|
|
||||||
selectedNodes.forEach(node => {
|
|
||||||
node.setState("selected", false);
|
|
||||||
});
|
|
||||||
// 再添加该节点的选中状态
|
|
||||||
clickNode.setState("selected", true);
|
|
||||||
vm.currentFocus = "node";
|
|
||||||
this.updateVmData(event);
|
|
||||||
}
|
|
||||||
graph.paint();
|
|
||||||
},
|
|
||||||
onEdgeClick(event) {
|
|
||||||
let clickEdge = event.item;
|
|
||||||
clickEdge.setState("selected", !clickEdge.hasState("selected"));
|
|
||||||
vm.currentFocus = "edge";
|
|
||||||
this.updateVmData(event);
|
|
||||||
},
|
|
||||||
onEdgeRightClick(event) {
|
|
||||||
let graph = vm.graph;
|
|
||||||
let clickEdge = event.item;
|
|
||||||
let clickEdgeModel = clickEdge.getModel();
|
|
||||||
let selectedEdges = graph.findAllByState("edge", "selected");
|
|
||||||
// 如果当前点击节点不是之前选中的单个节点,才进行下面的处理
|
|
||||||
if (!(selectedEdges.length === 1 && clickEdgeModel.id === selectedEdges[0].getModel().id)) {
|
|
||||||
// 先取消所有节点的选中状态
|
|
||||||
graph.findAllByState("edge", "selected").forEach(edge => {
|
|
||||||
edge.setState("selected", false);
|
|
||||||
});
|
|
||||||
// 再添加该节点的选中状态
|
|
||||||
clickEdge.setState("selected", true);
|
|
||||||
vm.currentFocus = "edge";
|
|
||||||
this.updateVmData(event);
|
|
||||||
}
|
|
||||||
let point = { x: event.x, y: event.y };
|
|
||||||
},
|
|
||||||
onCanvasClick() {
|
|
||||||
vm.currentFocus = "canvas";
|
|
||||||
vm.rightMenuShow = false;
|
|
||||||
},
|
|
||||||
updateVmData(event) {
|
|
||||||
let self = this
|
|
||||||
if (event.item._cfg.type === "node") {
|
|
||||||
|
|
||||||
// const item = event.item;
|
|
||||||
// let group = item.getContainer();
|
|
||||||
// let children = group.get("children");
|
|
||||||
// for (let i = 0, len = children.length; i < len; i++) {
|
|
||||||
// const shape = children[i];
|
|
||||||
// if (shape.get("name") === "collapses") {
|
|
||||||
// console.log(shape.get("name"),"dkfjg");
|
|
||||||
// self.graph.updateItem(item, {
|
|
||||||
// collapsed: true,
|
|
||||||
// size: [300, 50]
|
|
||||||
// });
|
|
||||||
// setTimeout(() => graph.layout(), 100);
|
|
||||||
// } else if (shape.get("name") === "expands") {
|
|
||||||
//
|
|
||||||
// console.log(shape.get("name"),"expands");
|
|
||||||
// self.graph.updateItem(item, {
|
|
||||||
// collapsed: false,
|
|
||||||
// size: [300, 500]
|
|
||||||
// });
|
|
||||||
// setTimeout(() => graph.layout(), 100);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// 更新vm的data: selectedNode 和 selectedNodeParams
|
|
||||||
|
|
||||||
|
|
||||||
let clickNode = event.item;
|
|
||||||
// console.log(clickNode)
|
|
||||||
if (clickNode.hasState("selected")) {
|
|
||||||
let clickNodeModel = clickNode.getModel();
|
|
||||||
vm.selectedNode = clickNode;
|
|
||||||
let nodeAppConfig = { ...vm.nodeAppConfig };
|
|
||||||
Object.keys(nodeAppConfig).forEach(function(key) {
|
|
||||||
nodeAppConfig[key] = "";
|
|
||||||
});
|
|
||||||
vm.selectedNodeParams = {
|
|
||||||
label: clickNodeModel.label || "",
|
|
||||||
appConfig: { ...nodeAppConfig, ...clickNodeModel.appConfig }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (event.item._cfg.type === "edge") {
|
|
||||||
console.log("jshdjhd")
|
|
||||||
// 更新vm的data: selectedEdge 和 selectedEdgeParams
|
|
||||||
let clickEdge = event.item;
|
|
||||||
if (clickEdge.hasState("selected")) {
|
|
||||||
let clickEdgeModel = clickEdge.getModel();
|
|
||||||
vm.selectedEdge = clickEdge;
|
|
||||||
let edgeAppConfig = { ...vm.edgeAppConfig };
|
|
||||||
Object.keys(edgeAppConfig).forEach(function(key) {
|
|
||||||
edgeAppConfig[key] = "";
|
|
||||||
});
|
|
||||||
vm.selectedEdgeParams = {
|
|
||||||
label: clickEdgeModel.label || "",
|
|
||||||
appConfig: { ...edgeAppConfig, ...clickEdgeModel.appConfig }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const isInBBox = (point, bbox) => {
|
|
||||||
const {
|
|
||||||
x,
|
|
||||||
y
|
|
||||||
} = point;
|
|
||||||
const {
|
|
||||||
minX,
|
|
||||||
minY,
|
|
||||||
maxX,
|
|
||||||
maxY
|
|
||||||
} = bbox;
|
|
||||||
|
|
||||||
return x < maxX && x > minX && y > minY && y < maxY;
|
|
||||||
};
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
/**
|
|
||||||
* @author: clay
|
|
||||||
* @data: 2021/5/18 14:21
|
|
||||||
* @email: clay@hchyun.com
|
|
||||||
* @description: node
|
|
||||||
*/
|
|
||||||
let vm = null;
|
|
||||||
const sendThis = (_this) => {
|
|
||||||
vm = _this;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
sendThis,
|
|
||||||
name: 'dice-er-edge',
|
|
||||||
options: {
|
|
||||||
getDefaultCfg() {
|
|
||||||
return {
|
|
||||||
multiple: true,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getEvents() {
|
|
||||||
return {
|
|
||||||
"edge:click": "onEdgeClick",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onEdgeClick(event) {
|
|
||||||
let clickEdge = event.item;
|
|
||||||
console.log(789)
|
|
||||||
console.log(clickEdge);
|
|
||||||
clickEdge.setState("selected", !clickEdge.hasState("selected"));
|
|
||||||
console.log(clickEdge);
|
|
||||||
let model = clickEdge.getModel();
|
|
||||||
console.log(model);
|
|
||||||
model.label = "4564654"
|
|
||||||
model.stroke='#e2e2e2'
|
|
||||||
clickEdge.update(model)
|
|
||||||
|
|
||||||
// console.log(vm)
|
|
||||||
// vm.currentFocus = "edge";
|
|
||||||
this.updateVmData(event);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -19,7 +19,14 @@ const isInBBox = (point, bbox) => {
|
||||||
return x < maxX && x > minX && y > minY && y < maxY;
|
return x < maxX && x > minX && y > minY && y < maxY;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let vm = null;
|
||||||
|
|
||||||
|
const sendThis = (_this) => {
|
||||||
|
vm = _this;
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
sendThis,
|
||||||
name: 'dice-er-node',
|
name: 'dice-er-node',
|
||||||
options: {
|
options: {
|
||||||
getDefaultCfg() {
|
getDefaultCfg() {
|
||||||
|
|
@ -31,8 +38,11 @@ export default {
|
||||||
return {
|
return {
|
||||||
itemHeight: 50,
|
itemHeight: 50,
|
||||||
wheel: "scroll",
|
wheel: "scroll",
|
||||||
"node:click": "click",
|
"node:click": "onNodeClick",
|
||||||
// "node:mousemove": "moves",
|
"edge:click": "onEdgeClick",
|
||||||
|
"node:contextmenu": "onNodeRightClick",
|
||||||
|
"edge:contextmenu": "onEdgeRightClick",
|
||||||
|
"canvas:click": "onCanvasClick",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
scroll(e) {
|
scroll(e) {
|
||||||
|
|
@ -73,7 +83,113 @@ export default {
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
click(e) {
|
onNodeClick(event) {
|
||||||
|
this.shrinkage(event)
|
||||||
|
vm.currentFocus = "node";
|
||||||
|
vm.rightMenuShow = false;
|
||||||
|
this.updateVmData(event);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 点击连线
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
onEdgeClick(event) {
|
||||||
|
let clickEdge = event.item;
|
||||||
|
clickEdge.setState("selected", !clickEdge.hasState("selected"));
|
||||||
|
vm.currentFocus = "edge";
|
||||||
|
|
||||||
|
this.updateVmData(event);
|
||||||
|
},
|
||||||
|
onNodeRightClick(event) {
|
||||||
|
let graph = vm.graph;
|
||||||
|
let clickNode = event.item;
|
||||||
|
let clickNodeModel = clickNode.getModel();
|
||||||
|
let selectedNodes = graph.findAllByState("node", "selected");
|
||||||
|
let selectedNodeIds = selectedNodes.map(item => {
|
||||||
|
return item.getModel().id;
|
||||||
|
});
|
||||||
|
vm.selectedNode = clickNode;
|
||||||
|
// 如果当前点击节点是之前选中的某个节点,就进行下面的处理
|
||||||
|
if (selectedNodes.length > 1 && selectedNodeIds.indexOf(clickNodeModel.id) > -1) {
|
||||||
|
vm.rightMenuShow = true;
|
||||||
|
let rightMenu = vm.$refs.rightMenu;
|
||||||
|
rightMenu.style.left = event.clientX + "px";
|
||||||
|
rightMenu.style.top = event.clientY + "px";
|
||||||
|
} else {
|
||||||
|
// 隐藏右键菜单
|
||||||
|
vm.rightMenuShow = false;
|
||||||
|
// 先取消所有节点的选中状态
|
||||||
|
selectedNodes.forEach(node => {
|
||||||
|
node.setState("selected", false);
|
||||||
|
});
|
||||||
|
// 再添加该节点的选中状态
|
||||||
|
clickNode.setState("selected", true);
|
||||||
|
vm.currentFocus = "node";
|
||||||
|
this.updateVmData(event);
|
||||||
|
}
|
||||||
|
graph.paint();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
onEdgeRightClick(event) {
|
||||||
|
let graph = vm.graph;
|
||||||
|
let clickEdge = event.item;
|
||||||
|
let clickEdgeModel = clickEdge.getModel();
|
||||||
|
let selectedEdges = graph.findAllByState("edge", "selected");
|
||||||
|
// 如果当前点击节点不是之前选中的单个节点,才进行下面的处理
|
||||||
|
if (!(selectedEdges.length === 1 && clickEdgeModel.id === selectedEdges[0].getModel().id)) {
|
||||||
|
// 先取消所有节点的选中状态
|
||||||
|
graph.findAllByState("edge", "selected").forEach(edge => {
|
||||||
|
edge.setState("selected", false);
|
||||||
|
});
|
||||||
|
// 再添加该节点的选中状态
|
||||||
|
clickEdge.setState("selected", true);
|
||||||
|
vm.currentFocus = "edge";
|
||||||
|
this.updateVmData(event);
|
||||||
|
}
|
||||||
|
let point = { x: event.x, y: event.y };
|
||||||
|
},
|
||||||
|
onCanvasClick() {
|
||||||
|
vm.currentFocus = "canvas";
|
||||||
|
vm.rightMenuShow = false;
|
||||||
|
},
|
||||||
|
updateVmData(event) {
|
||||||
|
if (event.item._cfg.type === "node") {
|
||||||
|
let clickNode = event.item;
|
||||||
|
if (clickNode.hasState("selected")) {
|
||||||
|
let clickNodeModel = clickNode.getModel();
|
||||||
|
vm.selectedNode = clickNode;
|
||||||
|
let nodeAppConfig = { ...vm.nodeAppConfig };
|
||||||
|
Object.keys(nodeAppConfig).forEach(function(key) {
|
||||||
|
nodeAppConfig[key] = "";
|
||||||
|
});
|
||||||
|
vm.selectedNodeParams = {
|
||||||
|
label: clickNodeModel.label || "",
|
||||||
|
appConfig: { ...nodeAppConfig, ...clickNodeModel.appConfig }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else if (event.item._cfg.type === "edge") {
|
||||||
|
// 更新vm的data: selectedEdge 和 selectedEdgeParams
|
||||||
|
let clickEdge = event.item;
|
||||||
|
if (clickEdge.hasState("selected")) {
|
||||||
|
let clickEdgeModel = clickEdge.getModel();
|
||||||
|
vm.selectedEdge = clickEdge;
|
||||||
|
let edgeAppConfig = { ...vm.edgeAppConfig };
|
||||||
|
Object.keys(edgeAppConfig).forEach(function(key) {
|
||||||
|
edgeAppConfig[key] = "";
|
||||||
|
});
|
||||||
|
vm.selectedEdgeParams = {
|
||||||
|
label: clickEdgeModel.label || "",
|
||||||
|
sourceAttrs:clickEdgeModel.sourceAttrs,
|
||||||
|
targetAttrs:clickEdgeModel.targetAttrs,
|
||||||
|
appConfig: { ...edgeAppConfig, ...clickEdgeModel.appConfig }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shrinkage(e){
|
||||||
const {
|
const {
|
||||||
graph
|
graph
|
||||||
} = this;
|
} = this;
|
||||||
|
|
@ -100,7 +216,6 @@ export default {
|
||||||
// console.log(JSON.stringify(model));
|
// console.log(JSON.stringify(model));
|
||||||
// console.log(model.style.default.fill = '#4eb922');
|
// console.log(model.style.default.fill = '#4eb922');
|
||||||
// console.log(model.style.selected.shadowColor = '#4eb922');
|
// console.log(model.style.selected.shadowColor = '#4eb922');
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
moves(e) {
|
moves(e) {
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ export default {
|
||||||
|
|
||||||
let sourceAnchor = self.evtInfo.node.getAnchorPoints();
|
let sourceAnchor = self.evtInfo.node.getAnchorPoints();
|
||||||
let sourceNodeModel = self.evtInfo.node.getModel();
|
let sourceNodeModel = self.evtInfo.node.getModel();
|
||||||
|
console.log("sourceNodeModel",sourceNodeModel)
|
||||||
// 锚点数据
|
// 锚点数据
|
||||||
let anchorPoints = self.evtInfo.node.getAnchorPoints();
|
let anchorPoints = self.evtInfo.node.getAnchorPoints();
|
||||||
// 处理线条目标点
|
// 处理线条目标点
|
||||||
|
|
@ -94,6 +95,7 @@ export default {
|
||||||
id: utils.generateUUID(),
|
id: utils.generateUUID(),
|
||||||
// 起始节点
|
// 起始节点
|
||||||
source: sourceNodeModel.id,
|
source: sourceNodeModel.id,
|
||||||
|
sourceAttrs:sourceNodeModel.attrs,
|
||||||
sourceAnchor: sourceAnchor ? sourceAnchor.anchorIndex : "",
|
sourceAnchor: sourceAnchor ? sourceAnchor.anchorIndex : "",
|
||||||
// 终止节点/位置
|
// 终止节点/位置
|
||||||
target: {
|
target: {
|
||||||
|
|
@ -139,7 +141,8 @@ export default {
|
||||||
}
|
}
|
||||||
self.graph.updateItem(self.drawEdge.currentLine, {
|
self.graph.updateItem(self.drawEdge.currentLine, {
|
||||||
target: targetNodeModel.id,
|
target: targetNodeModel.id,
|
||||||
targetAnchor: targetAnchor ? targetAnchor.anchorIndex : ""
|
targetAnchor: targetAnchor ? targetAnchor.anchorIndex : "",
|
||||||
|
targetAttrs:targetNodeModel.attrs,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ************** 记录historyData的逻辑 start **************
|
// ************** 记录historyData的逻辑 start **************
|
||||||
|
|
|
||||||
|
|
@ -6,20 +6,16 @@
|
||||||
|
|
||||||
import dragAddEdge from './drag-add-edge'
|
import dragAddEdge from './drag-add-edge'
|
||||||
import hoverEventEdit from './hover-event-edit'
|
import hoverEventEdit from './hover-event-edit'
|
||||||
import clickEventEdit from './click-event-edit'
|
|
||||||
import dragEventEdit from './drag-event-edit'
|
import dragEventEdit from './drag-event-edit'
|
||||||
import keyupEventEdit from './keyup-event-edit'
|
import keyupEventEdit from './keyup-event-edit'
|
||||||
import diceErNode from './dice-er-node'
|
import diceErNode from './dice-er-node'
|
||||||
import diceErEdge from './dice-er-edge'
|
|
||||||
|
|
||||||
const obj = {
|
const obj = {
|
||||||
dragAddEdge,
|
dragAddEdge,
|
||||||
hoverEventEdit,
|
hoverEventEdit,
|
||||||
// clickEventEdit,
|
|
||||||
dragEventEdit,
|
dragEventEdit,
|
||||||
keyupEventEdit,
|
keyupEventEdit,
|
||||||
diceErNode,
|
diceErNode,
|
||||||
diceErEdge
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
/**
|
|
||||||
* @author: clay
|
|
||||||
* @data: 2021/5/13 23:14
|
|
||||||
* @email: clay@hchyun.com
|
|
||||||
* @description: node
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "wheel-node",
|
|
||||||
options: {
|
|
||||||
getEvents() {
|
|
||||||
return {
|
|
||||||
wheel: "scorll"
|
|
||||||
};
|
|
||||||
},
|
|
||||||
scorll(e) {
|
|
||||||
console.log(456)
|
|
||||||
e.preventDefault();
|
|
||||||
const {
|
|
||||||
graph
|
|
||||||
} = this;
|
|
||||||
const nodes = graph.getNodes().filter((n) => {
|
|
||||||
const bbox = n.getBBox();
|
|
||||||
|
|
||||||
return isInBBox(graph.getPointByClient(e.clientX, e.clientY), bbox);
|
|
||||||
});
|
|
||||||
if (nodes) {
|
|
||||||
nodes.forEach((node) => {
|
|
||||||
const model = node.getModel();
|
|
||||||
if (model.attrs.length < 9) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const idx = model.startIndex || 0;
|
|
||||||
let startX = model.startX || 0.5;
|
|
||||||
let startIndex = idx + e.deltaY * 0.02;
|
|
||||||
startX -= e.deltaX;
|
|
||||||
if (startIndex < 0) {
|
|
||||||
startIndex = 0;
|
|
||||||
}
|
|
||||||
if (startX > 0) {
|
|
||||||
startX = 0;
|
|
||||||
}
|
|
||||||
if (startIndex > model.attrs.length - 1) {
|
|
||||||
startIndex = model.attrs.length - 1;
|
|
||||||
}
|
|
||||||
graph.update(node, {
|
|
||||||
startIndex,
|
|
||||||
startX,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
@ -8,6 +8,6 @@ export default {
|
||||||
type: 'top-cubic',
|
type: 'top-cubic',
|
||||||
style: {
|
style: {
|
||||||
startArrow: false,
|
startArrow: false,
|
||||||
endArrow: false
|
endArrow: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* @author: winyuan
|
* @author: Clay
|
||||||
* @data: 2019/07/18
|
* @data: 2019/07/18
|
||||||
* @repository: https://github.com/winyuan
|
|
||||||
* @description: 线公共方法
|
* @description: 线公共方法
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -21,6 +20,7 @@ export default {
|
||||||
},
|
},
|
||||||
name: 'edge-shape'
|
name: 'edge-shape'
|
||||||
})
|
})
|
||||||
|
console.log(keyShape.attrs.endArrow = true)
|
||||||
return keyShape
|
return keyShape
|
||||||
},
|
},
|
||||||
setState(name, value, item) {
|
setState(name, value, item) {
|
||||||
|
|
|
||||||
|
|
@ -1,275 +0,0 @@
|
||||||
/**
|
|
||||||
* 带圆角折线连线的策略
|
|
||||||
* 文档:https://www.yuque.com/antv/blog/eyi70n
|
|
||||||
* 参考:https://github.com/guozhaolong/wfd/blob/master/src/item/edge.js
|
|
||||||
* 引用:https://github.com/OXOYO/X-Flowchart-Vue/blob/master/src/global/lib/g6/edge/polylineFinding.js
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 折线寻径
|
|
||||||
export const polylineFinding = function(sNode, tNode, sPort, tPort, offset = 10) {
|
|
||||||
const sourceBBox = sNode && sNode.getBBox ? sNode.getBBox() : getPointBBox(sPort)
|
|
||||||
const targetBBox = tNode && tNode.getBBox ? tNode.getBBox() : getPointBBox(tPort)
|
|
||||||
// 获取节点带 offset 的区域(扩展区域)
|
|
||||||
const sBBox = getExpandedBBox(sourceBBox, offset)
|
|
||||||
const tBBox = getExpandedBBox(targetBBox, offset)
|
|
||||||
// 获取扩展区域上的起始和终止连接点
|
|
||||||
const sPoint = getExpandedPort(sBBox, sPort)
|
|
||||||
const tPoint = getExpandedPort(tBBox, tPort)
|
|
||||||
// 获取合法折点集
|
|
||||||
let points = getConnectablePoints(sBBox, tBBox, sPoint, tPoint)
|
|
||||||
// 过滤合法点集,预处理、剪枝等
|
|
||||||
filterConnectablePoints(points, sBBox)
|
|
||||||
// 过滤合法点集,预处理、剪枝等
|
|
||||||
filterConnectablePoints(points, tBBox)
|
|
||||||
// 用 A-Star 算法寻径
|
|
||||||
let polylinePoints = AStar(points, sPoint, tPoint, sBBox, tBBox)
|
|
||||||
return polylinePoints
|
|
||||||
}
|
|
||||||
|
|
||||||
const getPointBBox = function(t) {
|
|
||||||
return {
|
|
||||||
centerX: t.x,
|
|
||||||
centerY: t.y,
|
|
||||||
minX: t.x,
|
|
||||||
minY: t.y,
|
|
||||||
maxX: t.x,
|
|
||||||
maxY: t.y,
|
|
||||||
height: 0,
|
|
||||||
width: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取扩展区域
|
|
||||||
const getExpandedBBox = function(bbox, offset) {
|
|
||||||
if (bbox.width === 0 && bbox.height === 0) {
|
|
||||||
return bbox
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
centerX: bbox.centerX,
|
|
||||||
centerY: bbox.centerY,
|
|
||||||
minX: bbox.minX - offset,
|
|
||||||
minY: bbox.minY - offset,
|
|
||||||
maxX: bbox.maxX + offset,
|
|
||||||
maxY: bbox.maxY + offset,
|
|
||||||
height: bbox.height + 2 * offset,
|
|
||||||
width: bbox.width + 2 * offset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取扩展区域上的连接点
|
|
||||||
const getExpandedPort = function(bbox, point) {
|
|
||||||
// 判断连接点在上下左右哪个区域,相应地给x或y加上或者减去offset
|
|
||||||
if (Math.abs(point.x - bbox.centerX) / bbox.width > Math.abs(point.y - bbox.centerY) / bbox.height) {
|
|
||||||
return {
|
|
||||||
x: point.x > bbox.centerX ? bbox.maxX : bbox.minX,
|
|
||||||
y: point.y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
x: point.x,
|
|
||||||
y: point.y > bbox.centerY ? bbox.maxY : bbox.minY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取合法折点集合
|
|
||||||
const getConnectablePoints = function(sBBox, tBBox, sPoint, tPoint) {
|
|
||||||
let lineBBox = getBBoxFromVertexes(sPoint, tPoint)
|
|
||||||
let outerBBox = combineBBoxes(sBBox, tBBox)
|
|
||||||
let sLineBBox = combineBBoxes(sBBox, lineBBox)
|
|
||||||
let tLineBBox = combineBBoxes(tBBox, lineBBox)
|
|
||||||
let points = [
|
|
||||||
...vertexOfBBox(sLineBBox),
|
|
||||||
...vertexOfBBox(tLineBBox),
|
|
||||||
...vertexOfBBox(outerBBox)
|
|
||||||
]
|
|
||||||
const centerPoint = { x: outerBBox.centerX, y: outerBBox.centerY }
|
|
||||||
let bboxes = [outerBBox, sLineBBox, tLineBBox, lineBBox]
|
|
||||||
bboxes.forEach(bbox => {
|
|
||||||
// 包含 bbox 延长线和线段的相交线
|
|
||||||
points = [
|
|
||||||
...points,
|
|
||||||
...crossPointsByLineAndBBox(bbox, centerPoint)
|
|
||||||
]
|
|
||||||
})
|
|
||||||
points.push({ x: sPoint.x, y: tPoint.y })
|
|
||||||
points.push({ x: tPoint.x, y: sPoint.y })
|
|
||||||
return points
|
|
||||||
}
|
|
||||||
|
|
||||||
const getBBoxFromVertexes = function(sPoint, tPoint) {
|
|
||||||
const minX = Math.min(sPoint.x, tPoint.x)
|
|
||||||
const maxX = Math.max(sPoint.x, tPoint.x)
|
|
||||||
const minY = Math.min(sPoint.y, tPoint.y)
|
|
||||||
const maxY = Math.max(sPoint.y, tPoint.y)
|
|
||||||
|
|
||||||
return {
|
|
||||||
centerX: (minX + maxX) / 2,
|
|
||||||
centerY: (minY + maxY) / 2,
|
|
||||||
maxX: maxX,
|
|
||||||
maxY: maxY,
|
|
||||||
minX: minX,
|
|
||||||
minY: minY,
|
|
||||||
height: maxY - minY,
|
|
||||||
width: maxX - minX
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const combineBBoxes = function(sBBox, tBBox) {
|
|
||||||
const minX = Math.min(sBBox.minX, tBBox.minX)
|
|
||||||
const minY = Math.min(sBBox.minY, tBBox.minY)
|
|
||||||
const maxX = Math.max(sBBox.maxX, tBBox.maxX)
|
|
||||||
const maxY = Math.max(sBBox.maxY, tBBox.maxY)
|
|
||||||
|
|
||||||
return {
|
|
||||||
centerX: (minX + maxX) / 2,
|
|
||||||
centerY: (minY + maxY) / 2,
|
|
||||||
minX: minX,
|
|
||||||
minY: minY,
|
|
||||||
maxX: maxX,
|
|
||||||
maxY: maxY,
|
|
||||||
height: maxY - minY,
|
|
||||||
width: maxX - minX
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const vertexOfBBox = function(bbox) {
|
|
||||||
return [
|
|
||||||
{ x: bbox.minX, y: bbox.minY },
|
|
||||||
{ x: bbox.maxX, y: bbox.minY },
|
|
||||||
{ x: bbox.maxX, y: bbox.maxY },
|
|
||||||
{ x: bbox.minX, y: bbox.maxY }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const crossPointsByLineAndBBox = function(bbox, centerPoint) {
|
|
||||||
let crossPoints = []
|
|
||||||
if (!(centerPoint.x < bbox.minX || centerPoint.x > bbox.maxX)) {
|
|
||||||
crossPoints = [
|
|
||||||
...crossPoints,
|
|
||||||
{ x: centerPoint.x, y: bbox.minY },
|
|
||||||
{ x: centerPoint.x, y: bbox.maxY }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
if (!(centerPoint.y < bbox.minY || centerPoint.y > bbox.maxY)) {
|
|
||||||
crossPoints = [
|
|
||||||
...crossPoints,
|
|
||||||
{ x: bbox.minX, y: centerPoint.y },
|
|
||||||
{ x: bbox.maxX, y: centerPoint.y }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
return crossPoints
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过滤连接点
|
|
||||||
const filterConnectablePoints = function(points, bbox) {
|
|
||||||
return points.filter(point => {
|
|
||||||
return point.x <= bbox.minX || point.x >= bbox.maxX || point.y <= bbox.minY || point.y >= bbox.maxY
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const crossBBox = function(bboxes, p1, p2) {
|
|
||||||
for (let i = 0; i < bboxes.length; i++) {
|
|
||||||
const bbox = bboxes[i]
|
|
||||||
if (p1.x === p2.x && bbox.minX < p1.x && bbox.maxX > p1.x) {
|
|
||||||
if ((p1.y < bbox.maxY && p2.y >= bbox.maxY) || (p2.y < bbox.maxY && p1.y >= bbox.maxY)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else if (p1.y === p2.y && bbox.minY < p1.y && bbox.maxY > p1.y) {
|
|
||||||
if ((p1.x < bbox.maxX && p2.x >= bbox.maxX) || (p2.x < bbox.maxX && p1.x >= bbox.maxX)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCost = function(p1, p2) {
|
|
||||||
return Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y)
|
|
||||||
}
|
|
||||||
|
|
||||||
// aStar 寻径
|
|
||||||
const AStar = function(points, sPoint, tPoint, sBBox, tBBox) {
|
|
||||||
const openList = [sPoint]
|
|
||||||
const closeList = []
|
|
||||||
points.forEach(item => {
|
|
||||||
item.id = item.x + '-' + item.y
|
|
||||||
})
|
|
||||||
let tmpArr = []
|
|
||||||
points.forEach(item => {
|
|
||||||
if (!tmpArr.includes(target => target.id === item.id)) {
|
|
||||||
tmpArr.push(item)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
points = [
|
|
||||||
...tmpArr,
|
|
||||||
tPoint
|
|
||||||
]
|
|
||||||
let endPoint
|
|
||||||
while (openList.length > 0) {
|
|
||||||
let minCostPoint
|
|
||||||
openList.forEach((p, i) => {
|
|
||||||
if (!p.parent) {
|
|
||||||
p.f = 0
|
|
||||||
}
|
|
||||||
if (!minCostPoint) {
|
|
||||||
minCostPoint = p
|
|
||||||
}
|
|
||||||
if (p.f < minCostPoint.f) {
|
|
||||||
minCostPoint = p
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (minCostPoint.x === tPoint.x && minCostPoint.y === tPoint.y) {
|
|
||||||
endPoint = minCostPoint
|
|
||||||
break
|
|
||||||
}
|
|
||||||
openList.splice(openList.findIndex(o => o.x === minCostPoint.x && o.y === minCostPoint.y), 1)
|
|
||||||
closeList.push(minCostPoint)
|
|
||||||
const neighbor = points.filter(p => {
|
|
||||||
return (p.x === minCostPoint.x || p.y === minCostPoint.y) &&
|
|
||||||
!(p.x === minCostPoint.x && p.y === minCostPoint.y) &&
|
|
||||||
!crossBBox([sBBox, tBBox], minCostPoint, p)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
neighbor.forEach(p => {
|
|
||||||
const inOpen = openList.find(o => o.x === p.x && o.y === p.y)
|
|
||||||
const currentG = getCost(p, minCostPoint)
|
|
||||||
if (!closeList.find(o => o.x === p.x && o.y === p.y)) {
|
|
||||||
if (inOpen) {
|
|
||||||
if (p.g > currentG) {
|
|
||||||
p.parent = minCostPoint
|
|
||||||
p.g = currentG
|
|
||||||
p.f = p.g + p.h
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
p.parent = minCostPoint
|
|
||||||
p.g = currentG
|
|
||||||
let h = getCost(p, tPoint)
|
|
||||||
if (crossBBox([tBBox], p, tPoint)) {
|
|
||||||
// 如果穿过bbox则增加该点的预估代价为bbox周长的一半
|
|
||||||
h += (tBBox.width / 2 + tBBox.height / 2)
|
|
||||||
}
|
|
||||||
p.h = h
|
|
||||||
p.f = p.g + p.h
|
|
||||||
openList.push(p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (endPoint) {
|
|
||||||
const result = []
|
|
||||||
result.push({
|
|
||||||
x: endPoint.x,
|
|
||||||
y: endPoint.y
|
|
||||||
})
|
|
||||||
while (endPoint.parent) {
|
|
||||||
endPoint = endPoint.parent
|
|
||||||
result.push({
|
|
||||||
x: endPoint.x,
|
|
||||||
y: endPoint.y
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return result.reverse()
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
/**
|
/**
|
||||||
* @author: winyuan
|
* @author: Clay
|
||||||
* @data: 2019/07/18
|
* @data: 2019/07/18
|
||||||
* @repository: https://github.com/winyuan
|
|
||||||
* @description: 曲线
|
* @description: 曲线
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import utils from "../utils";
|
|
||||||
import base from './base'
|
import base from './base'
|
||||||
import { polylineFinding } from './polyline-finding'
|
|
||||||
export default {
|
export default {
|
||||||
name: 'top-cubic',
|
name: 'top-cubic',
|
||||||
extendName: 'cubic',
|
extendName: 'cubic',
|
||||||
|
|
|
||||||
|
|
@ -74,15 +74,15 @@ export default {
|
||||||
r: 3,
|
r: 3,
|
||||||
symbol: 'circle',
|
symbol: 'circle',
|
||||||
lineWidth: 1,
|
lineWidth: 1,
|
||||||
fill: 'white',
|
fill: '#FFFFFF',
|
||||||
fillOpacity: 1,
|
fillOpacity: 1,
|
||||||
stroke: '#096DD9',
|
stroke: '#096DD9',
|
||||||
strokeOpacity: 1,
|
strokeOpacity: 1,
|
||||||
cursor: 'crosshair'
|
cursor: 'crosshair'
|
||||||
},
|
},
|
||||||
hover: {
|
hover: {
|
||||||
fillOpacity: 1,
|
fillOpacity: 0.3,
|
||||||
strokeOpacity: 1
|
strokeOpacity: 0.5
|
||||||
},
|
},
|
||||||
unhover: {
|
unhover: {
|
||||||
fillOpacity: 0,
|
fillOpacity: 0,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -4,6 +4,7 @@
|
||||||
ref="topology"
|
ref="topology"
|
||||||
:graph-data="graphData"
|
:graph-data="graphData"
|
||||||
:node-app-config="nodeAppConfig"
|
:node-app-config="nodeAppConfig"
|
||||||
|
:edge-app-config="edgeAppConfig"
|
||||||
@doAutoRefresh="doAutoRefresh"
|
@doAutoRefresh="doAutoRefresh"
|
||||||
@doManualRefresh="doManualRefresh"
|
@doManualRefresh="doManualRefresh"
|
||||||
@doChangeMode="doChangeMode"
|
@doChangeMode="doChangeMode"
|
||||||
|
|
@ -15,146 +16,246 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/* 局部注册 */
|
/* 局部注册 */
|
||||||
import Topology from "./packages/topology/src/topology";
|
import Topology from './packages/topology/src/topology'
|
||||||
import { deepClone } from "./utils/index";
|
import { deepClone } from './utils/index'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "DemoTopology",
|
name: 'DemoTopology',
|
||||||
components: {
|
components: {
|
||||||
"topology": Topology
|
'topology': Topology
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
graphData: {
|
graphData: {
|
||||||
nodes: [
|
'nodes': [{
|
||||||
// {
|
'id': 'a72f9f56-d3b6-4f7b-a42f-bf9cc45e7c3c',
|
||||||
// "id": "info",
|
'x': 144.47865794573642,
|
||||||
// "label": "Employee",
|
'y': -12.739970930232559,
|
||||||
// "attrs": [{
|
'labels': '服务器',
|
||||||
// "key": "id",
|
'table': 'test_table',
|
||||||
// "type": "number(6)"
|
'type': 'dice-er-box',
|
||||||
// },
|
'attrs': [{ 'key': 'id', 'type': 'number(6)', 'comment': '主键id' }, {
|
||||||
// {
|
'key': 'key',
|
||||||
// "key": "key",
|
'type': 'varchar(255)',
|
||||||
// "type": "varchar(255)"
|
'comment': '关键字'
|
||||||
// },
|
}, { 'key': 'gender', 'type': 'enum(M, F)', 'comment': 'gender' }, {
|
||||||
// {
|
'key': 'birthday',
|
||||||
// "key": "gender",
|
'type': 'date',
|
||||||
// "type": "enum(M, F)"
|
'comment': '生日'
|
||||||
// },
|
}, { 'key': 'hometown', 'type': 'varchar(255)', 'comment': '家乡' }, {
|
||||||
// {
|
'key': 'country',
|
||||||
// "key": "birthday",
|
'type': 'varchar(255)',
|
||||||
// "type": "date"
|
'comment': '国家'
|
||||||
// },
|
}, { 'key': 'nation', 'type': 'varchar(255)', 'comment': 'nation' }, {
|
||||||
// {
|
'key': 'jobId',
|
||||||
// "key": "hometown",
|
'type': 'number(3)',
|
||||||
// "type": "varchar(255)"
|
'comment': '工作id'
|
||||||
// },
|
}, { 'key': 'phone', 'type': 'varchar(255)', 'comment': '电话' }],
|
||||||
// {
|
'size': [55, 55],
|
||||||
// "key": "country",
|
'width': 250,
|
||||||
// "type": "varchar(255)"
|
'height': 316,
|
||||||
// },
|
'anchorPoints': [[0.5, 0], [1, 0.5], [0.5, 1], [0, 0.5]],
|
||||||
// {
|
'appState': { 'alert': false },
|
||||||
// "key": "nation",
|
'labelCfg': { 'position': 'bottom' },
|
||||||
// "type": "varchar(255)"
|
'style': {
|
||||||
// },
|
'default': {
|
||||||
// {
|
'stroke': '#CED4D9',
|
||||||
// "key": "jobId",
|
'fill': 'transparent',
|
||||||
// "type": "number(3)",
|
'shadowBlur': 10,
|
||||||
// "relation": [{
|
'shadowColor': 'rgba(13, 26, 38, 0.08)',
|
||||||
// "key": "id",
|
'lineWidth': 1,
|
||||||
// "nodeId": "job"
|
'radius': 4,
|
||||||
// }]
|
'strokeOpacity': 0.7
|
||||||
// },
|
}, 'selected': { 'shadowColor': '#ff240b', 'shadowBlur': 2 }, 'unselected': { 'shadowColor': '' }
|
||||||
// {
|
|
||||||
// "key": "phone",
|
|
||||||
// "type": "varchar(255)"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "key": "deptId",
|
|
||||||
// "type": "number(6)",
|
|
||||||
// "relation": [{
|
|
||||||
// "key": "id",
|
|
||||||
// "nodeId": "dept"
|
|
||||||
// }]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "key": "startTime",
|
|
||||||
// "type": "date"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "key": "leaveTime",
|
|
||||||
// "type": "date"
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "job",
|
|
||||||
// "label": "Job",
|
|
||||||
// "attrs": [{
|
|
||||||
// "key": "id",
|
|
||||||
// "type": "number(3)"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "key": "title",
|
|
||||||
// "type": "varchar(255)"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "key": "level",
|
|
||||||
// "type": "number(3)"
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "dept",
|
|
||||||
// "label": "Department",
|
|
||||||
// "attrs": [{
|
|
||||||
// "key": "id",
|
|
||||||
// "type": "number(6)"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "key": "title",
|
|
||||||
// "type": "varchar(255)"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "key": "desc",
|
|
||||||
// "type": "text"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "key": "parent",
|
|
||||||
// "type": "number(6)",
|
|
||||||
// "relation": [{
|
|
||||||
// "key": "id",
|
|
||||||
// "nodeId": "dept"
|
|
||||||
// }]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "key": "manager",
|
|
||||||
// "type": "number(6)"
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
],
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
"source": "info",
|
|
||||||
"target": "job",
|
|
||||||
"sourceKey": "jobId",
|
|
||||||
"targetKey": "id"
|
|
||||||
},
|
},
|
||||||
{
|
'selectedIndex': null,
|
||||||
"source": "info",
|
'label': '',
|
||||||
"target": "dept",
|
'appConfig': { 'ip': '', 'port': '', 'sysName': '' },
|
||||||
"sourceKey": "deptId",
|
'depth': 0
|
||||||
"targetKey": "id"
|
}, {
|
||||||
|
'id': '933f5158-258e-44c9-8e1f-70aa701729a8',
|
||||||
|
'x': 494.37013081395366,
|
||||||
|
'y': 132.21506782945744,
|
||||||
|
'labels': '数据库',
|
||||||
|
'table': 'test_table',
|
||||||
|
'type': 'dice-er-box',
|
||||||
|
'attrs': [{ 'key': 'id', 'type': 'number(6)', 'comment': '主键id' }, {
|
||||||
|
'key': 'key',
|
||||||
|
'type': 'varchar(255)',
|
||||||
|
'comment': '关键字'
|
||||||
|
}, { 'key': 'gender', 'type': 'enum(M, F)', 'comment': 'gender' }, {
|
||||||
|
'key': 'birthday',
|
||||||
|
'type': 'date',
|
||||||
|
'comment': '生日'
|
||||||
|
}, { 'key': 'hometown', 'type': 'varchar(255)', 'comment': '家乡' }, {
|
||||||
|
'key': 'country',
|
||||||
|
'type': 'varchar(255)',
|
||||||
|
'comment': '国家'
|
||||||
|
}, { 'key': 'nation', 'type': 'varchar(255)', 'comment': 'nation' }, {
|
||||||
|
'key': 'jobId',
|
||||||
|
'type': 'number(3)',
|
||||||
|
'comment': '工作id'
|
||||||
|
}, { 'key': 'phone', 'type': 'varchar(255)', 'comment': '电话' }],
|
||||||
|
'size': [55, 55],
|
||||||
|
'width': 250,
|
||||||
|
'height': 316,
|
||||||
|
'anchorPoints': [[0.5, 0], [1, 0.5], [0.5, 1], [0, 0.5]],
|
||||||
|
'appState': { 'alert': false },
|
||||||
|
'labelCfg': { 'position': 'bottom' },
|
||||||
|
'style': {
|
||||||
|
'default': {
|
||||||
|
'stroke': '#CED4D9',
|
||||||
|
'fill': 'transparent',
|
||||||
|
'shadowBlur': 10,
|
||||||
|
'shadowColor': 'rgba(13, 26, 38, 0.08)',
|
||||||
|
'lineWidth': 1,
|
||||||
|
'radius': 4,
|
||||||
|
'strokeOpacity': 0.7
|
||||||
|
}, 'selected': { 'shadowColor': '#ff240b', 'shadowBlur': 2 }, 'unselected': { 'shadowColor': '' }
|
||||||
},
|
},
|
||||||
{
|
'selectedIndex': null,
|
||||||
"source": "dept",
|
'label': '',
|
||||||
"target": "dept",
|
'appConfig': { 'ip': '', 'port': '', 'sysName': '' },
|
||||||
"sourceKey": "parent",
|
'depth': 0
|
||||||
"targetKey": "id"
|
}], 'edges': [{
|
||||||
}
|
'id': 'b424996b-62cf-487c-bd7b-83210e8a6866',
|
||||||
]
|
'source': '933f5158-258e-44c9-8e1f-70aa701729a8',
|
||||||
|
'sourceAttrs': [{ 'key': 'id', 'type': 'number(6)', 'comment': '主键id' }, {
|
||||||
|
'key': 'key',
|
||||||
|
'type': 'varchar(255)',
|
||||||
|
'comment': '关键字'
|
||||||
|
}, { 'key': 'gender', 'type': 'enum(M, F)', 'comment': 'gender' }, {
|
||||||
|
'key': 'birthday',
|
||||||
|
'type': 'date',
|
||||||
|
'comment': '生日'
|
||||||
|
}, { 'key': 'hometown', 'type': 'varchar(255)', 'comment': '家乡' }, {
|
||||||
|
'key': 'country',
|
||||||
|
'type': 'varchar(255)',
|
||||||
|
'comment': '国家'
|
||||||
|
}, { 'key': 'nation', 'type': 'varchar(255)', 'comment': 'nation' }, {
|
||||||
|
'key': 'jobId',
|
||||||
|
'type': 'number(3)',
|
||||||
|
'comment': '工作id'
|
||||||
|
}, { 'key': 'phone', 'type': 'varchar(255)', 'comment': '电话' }],
|
||||||
|
'sourceAnchor': 3,
|
||||||
|
'target': '933f5158-258e-44c9-8e1f-70aa701729a8',
|
||||||
|
'type': 'top-cubic',
|
||||||
|
'style': {
|
||||||
|
'active': { 'stroke': 'rgb(95, 149, 255)', 'lineWidth': 1 },
|
||||||
|
'selected': {
|
||||||
|
'stroke': 'rgb(95, 149, 255)',
|
||||||
|
'lineWidth': 2,
|
||||||
|
'shadowColor': 'rgb(95, 149, 255)',
|
||||||
|
'shadowBlur': 10,
|
||||||
|
'text-shape': { 'fontWeight': 500 }
|
||||||
|
},
|
||||||
|
'highlight': { 'stroke': 'rgb(95, 149, 255)', 'lineWidth': 2, 'text-shape': { 'fontWeight': 500 } },
|
||||||
|
'inactive': { 'stroke': 'rgb(234, 234, 234)', 'lineWidth': 1 },
|
||||||
|
'disable': { 'stroke': 'rgb(245, 245, 245)', 'lineWidth': 1 },
|
||||||
|
'edgeStyle': {
|
||||||
|
'default': { 'stroke': '#e2e2e2', 'lineWidth': 3, 'lineAppendWidth': 10 },
|
||||||
|
'selected': { 'shadowColor': '#626262', 'shadowBlur': 3 }
|
||||||
|
},
|
||||||
|
'stroke': '#A3B1BF',
|
||||||
|
'lineWidth': 2,
|
||||||
|
'strokeOpacity': 0.92,
|
||||||
|
'lineAppendWidth': 10
|
||||||
|
},
|
||||||
|
'labelCfg': { 'position': 'center', 'autoRotate': false },
|
||||||
|
'startPoint': { 'x': 493.87013081395366, 'y': 290.21506782945744, 'anchorIndex': 3 },
|
||||||
|
'endPoint': { 'x': 493.87013081395366, 'y': 290.21506782945744, 'anchorIndex': 3 },
|
||||||
|
'targetAnchor': 3,
|
||||||
|
'targetAttrs': [{ 'key': 'id', 'type': 'number(6)', 'comment': '主键id' }, {
|
||||||
|
'key': 'key',
|
||||||
|
'type': 'varchar(255)',
|
||||||
|
'comment': '关键字'
|
||||||
|
}, { 'key': 'gender', 'type': 'enum(M, F)', 'comment': 'gender' }, {
|
||||||
|
'key': 'birthday',
|
||||||
|
'type': 'date',
|
||||||
|
'comment': '生日'
|
||||||
|
}, { 'key': 'hometown', 'type': 'varchar(255)', 'comment': '家乡' }, {
|
||||||
|
'key': 'country',
|
||||||
|
'type': 'varchar(255)',
|
||||||
|
'comment': '国家'
|
||||||
|
}, { 'key': 'nation', 'type': 'varchar(255)', 'comment': 'nation' }, {
|
||||||
|
'key': 'jobId',
|
||||||
|
'type': 'number(3)',
|
||||||
|
'comment': '工作id'
|
||||||
|
}, { 'key': 'phone', 'type': 'varchar(255)', 'comment': '电话' }],
|
||||||
|
'curveOffset': [-20, 20],
|
||||||
|
'curvePosition': [0.5, 0.5],
|
||||||
|
'depth': 0
|
||||||
|
}, {
|
||||||
|
'id': '22cefcd1-5d30-4a89-a061-81d7c111a99d',
|
||||||
|
'source': '933f5158-258e-44c9-8e1f-70aa701729a8',
|
||||||
|
'sourceAttrs': [{ 'key': 'id', 'type': 'number(6)', 'comment': '主键id' }, {
|
||||||
|
'key': 'key',
|
||||||
|
'type': 'varchar(255)',
|
||||||
|
'comment': '关键字'
|
||||||
|
}, { 'key': 'gender', 'type': 'enum(M, F)', 'comment': 'gender' }, {
|
||||||
|
'key': 'birthday',
|
||||||
|
'type': 'date',
|
||||||
|
'comment': '生日'
|
||||||
|
}, { 'key': 'hometown', 'type': 'varchar(255)', 'comment': '家乡' }, {
|
||||||
|
'key': 'country',
|
||||||
|
'type': 'varchar(255)',
|
||||||
|
'comment': '国家'
|
||||||
|
}, { 'key': 'nation', 'type': 'varchar(255)', 'comment': 'nation' }, {
|
||||||
|
'key': 'jobId',
|
||||||
|
'type': 'number(3)',
|
||||||
|
'comment': '工作id'
|
||||||
|
}, { 'key': 'phone', 'type': 'varchar(255)', 'comment': '电话' }],
|
||||||
|
'sourceAnchor': 3,
|
||||||
|
'target': 'a72f9f56-d3b6-4f7b-a42f-bf9cc45e7c3c',
|
||||||
|
'type': 'top-cubic',
|
||||||
|
'style': {
|
||||||
|
'active': { 'stroke': 'rgb(95, 149, 255)', 'lineWidth': 1 },
|
||||||
|
'selected': {
|
||||||
|
'stroke': 'rgb(95, 149, 255)',
|
||||||
|
'lineWidth': 2,
|
||||||
|
'shadowColor': 'rgb(95, 149, 255)',
|
||||||
|
'shadowBlur': 10,
|
||||||
|
'text-shape': { 'fontWeight': 500 }
|
||||||
|
},
|
||||||
|
'highlight': { 'stroke': 'rgb(95, 149, 255)', 'lineWidth': 2, 'text-shape': { 'fontWeight': 500 } },
|
||||||
|
'inactive': { 'stroke': 'rgb(234, 234, 234)', 'lineWidth': 1 },
|
||||||
|
'disable': { 'stroke': 'rgb(245, 245, 245)', 'lineWidth': 1 },
|
||||||
|
'edgeStyle': {
|
||||||
|
'default': { 'stroke': '#e2e2e2', 'lineWidth': 3, 'lineAppendWidth': 10 },
|
||||||
|
'selected': { 'shadowColor': '#626262', 'shadowBlur': 3 }
|
||||||
|
},
|
||||||
|
'stroke': '#A3B1BF',
|
||||||
|
'lineWidth': 2,
|
||||||
|
'strokeOpacity': 0.92,
|
||||||
|
'lineAppendWidth': 10
|
||||||
|
},
|
||||||
|
'labelCfg': { 'position': 'center', 'autoRotate': false },
|
||||||
|
'startPoint': { 'x': 493.87013081395366, 'y': 290.21506782945744, 'anchorIndex': 3 },
|
||||||
|
'endPoint': { 'x': 394.9786579457364, 'y': 145.26002906976743, 'anchorIndex': 1 },
|
||||||
|
'curveOffset': [-20, 20],
|
||||||
|
'curvePosition': [0.5, 0.5],
|
||||||
|
'targetAnchor': 1,
|
||||||
|
'targetAttrs': [{ 'key': 'id', 'type': 'number(6)', 'comment': '主键id' }, {
|
||||||
|
'key': 'key',
|
||||||
|
'type': 'varchar(255)',
|
||||||
|
'comment': '关键字'
|
||||||
|
}, { 'key': 'gender', 'type': 'enum(M, F)', 'comment': 'gender' }, {
|
||||||
|
'key': 'birthday',
|
||||||
|
'type': 'date',
|
||||||
|
'comment': '生日'
|
||||||
|
}, { 'key': 'hometown', 'type': 'varchar(255)', 'comment': '家乡' }, {
|
||||||
|
'key': 'country',
|
||||||
|
'type': 'varchar(255)',
|
||||||
|
'comment': '国家'
|
||||||
|
}, { 'key': 'nation', 'type': 'varchar(255)', 'comment': 'nation' }, {
|
||||||
|
'key': 'jobId',
|
||||||
|
'type': 'number(3)',
|
||||||
|
'comment': '工作id'
|
||||||
|
}, { 'key': 'phone', 'type': 'varchar(255)', 'comment': '电话' }],
|
||||||
|
'depth': 0,
|
||||||
|
'label': '',
|
||||||
|
'appConfig': { 'associated': 'left', 'tableComment': 'id', 'relComment': 'key' }
|
||||||
|
}], 'combos': []
|
||||||
},
|
},
|
||||||
nodeTypeList: [
|
nodeTypeList: [
|
||||||
// { guid: "blue", label: "蓝色", imgSrc: require("../../assets/images/blue.svg") },
|
// { guid: "blue", label: "蓝色", imgSrc: require("../../assets/images/blue.svg") },
|
||||||
|
|
@ -163,50 +264,55 @@ export default {
|
||||||
],
|
],
|
||||||
// 节点配置
|
// 节点配置
|
||||||
nodeAppConfig: {
|
nodeAppConfig: {
|
||||||
ip: "节点IP",
|
// ip: '节点IP',
|
||||||
port: "节点端口",
|
// port: '节点端口',
|
||||||
sysName: "设备名称"
|
// sysName: '设备名称'
|
||||||
|
},
|
||||||
|
edgeAppConfig: {
|
||||||
|
associated: '查询方式',
|
||||||
|
tableComment: '主表字段',
|
||||||
|
relComment: '关联字段'
|
||||||
},
|
},
|
||||||
autoRefreshTimer: null
|
autoRefreshTimer: null
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
let graphData = deepClone(this.graphData);
|
let graphData = deepClone(this.graphData)
|
||||||
this.$refs.topology.initTopo(graphData);
|
this.$refs.topology.initTopo(graphData)
|
||||||
this.randomChange();
|
this.randomChange()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
doAutoRefresh(interval) {
|
doAutoRefresh(interval) {
|
||||||
if (interval === -1) {
|
if (interval === -1) {
|
||||||
clearInterval(this.autoRefreshTimer);
|
clearInterval(this.autoRefreshTimer)
|
||||||
} else {
|
} else {
|
||||||
clearInterval(this.autoRefreshTimer);
|
clearInterval(this.autoRefreshTimer)
|
||||||
this.autoRefreshTimer = setInterval(() => {
|
this.autoRefreshTimer = setInterval(() => {
|
||||||
this.randomChange();
|
this.randomChange()
|
||||||
}, interval);
|
}, interval)
|
||||||
this.$once("hook:beforeDestroy", () => {
|
this.$once('hook:beforeDestroy', () => {
|
||||||
clearInterval(this.autoRefreshTimer);
|
clearInterval(this.autoRefreshTimer)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
doChangeMode(graphMode) {
|
doChangeMode(graphMode) {
|
||||||
clearInterval(this.autoRefreshTimer);
|
clearInterval(this.autoRefreshTimer)
|
||||||
let graphData = deepClone(this.graphData);
|
let graphData = deepClone(this.graphData)
|
||||||
this.$refs.topology.changeGraphMode(graphData, graphMode);
|
this.$refs.topology.changeGraphMode(graphData, graphMode)
|
||||||
},
|
},
|
||||||
doManualRefresh() {
|
doManualRefresh() {
|
||||||
this.randomChange();
|
this.randomChange()
|
||||||
},
|
},
|
||||||
doSaveData(graphData) {
|
doSaveData(graphData) {
|
||||||
console.log(JSON.stringify(graphData));
|
console.log(JSON.stringify(graphData))
|
||||||
},
|
},
|
||||||
randomChange() {
|
randomChange() {
|
||||||
let graphData = deepClone(this.$refs.topology.getGraphData());
|
let graphData = deepClone(this.$refs.topology.getGraphData())
|
||||||
let { nodes } = graphData;
|
let { nodes } = graphData
|
||||||
this.$refs.topology.changeGraphData(graphData);
|
this.$refs.topology.changeGraphData(graphData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue