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;
|
||||
};
|
||||
|
||||
let vm = null;
|
||||
|
||||
const sendThis = (_this) => {
|
||||
vm = _this;
|
||||
};
|
||||
|
||||
export default {
|
||||
sendThis,
|
||||
name: 'dice-er-node',
|
||||
options: {
|
||||
getDefaultCfg() {
|
||||
|
|
@ -31,8 +38,11 @@ export default {
|
|||
return {
|
||||
itemHeight: 50,
|
||||
wheel: "scroll",
|
||||
"node:click": "click",
|
||||
// "node:mousemove": "moves",
|
||||
"node:click": "onNodeClick",
|
||||
"edge:click": "onEdgeClick",
|
||||
"node:contextmenu": "onNodeRightClick",
|
||||
"edge:contextmenu": "onEdgeRightClick",
|
||||
"canvas:click": "onCanvasClick",
|
||||
};
|
||||
},
|
||||
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 {
|
||||
graph
|
||||
} = this;
|
||||
|
|
@ -82,7 +198,7 @@ export default {
|
|||
if (!item) {
|
||||
return;
|
||||
}
|
||||
if (shape.get("name") === "collapse") {
|
||||
if (shape.get("name") === "collapse") {
|
||||
graph.updateItem(item, {
|
||||
collapsed: true,
|
||||
size: [300, 50],
|
||||
|
|
@ -95,13 +211,12 @@ export default {
|
|||
});
|
||||
setTimeout(() => graph.layout(), 100);
|
||||
}else {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const model = item.getModel();
|
||||
// console.log(JSON.stringify(model));
|
||||
// console.log(model.style.default.fill = '#4eb922');
|
||||
// console.log(model.style.selected.shadowColor = '#4eb922');
|
||||
|
||||
}
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const model = item.getModel();
|
||||
// console.log(JSON.stringify(model));
|
||||
// console.log(model.style.default.fill = '#4eb922');
|
||||
// console.log(model.style.selected.shadowColor = '#4eb922');
|
||||
}
|
||||
},
|
||||
moves(e) {
|
||||
const name = e.shape.get("name");
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ export default {
|
|||
|
||||
let sourceAnchor = self.evtInfo.node.getAnchorPoints();
|
||||
let sourceNodeModel = self.evtInfo.node.getModel();
|
||||
console.log("sourceNodeModel",sourceNodeModel)
|
||||
// 锚点数据
|
||||
let anchorPoints = self.evtInfo.node.getAnchorPoints();
|
||||
// 处理线条目标点
|
||||
|
|
@ -94,6 +95,7 @@ export default {
|
|||
id: utils.generateUUID(),
|
||||
// 起始节点
|
||||
source: sourceNodeModel.id,
|
||||
sourceAttrs:sourceNodeModel.attrs,
|
||||
sourceAnchor: sourceAnchor ? sourceAnchor.anchorIndex : "",
|
||||
// 终止节点/位置
|
||||
target: {
|
||||
|
|
@ -139,7 +141,8 @@ export default {
|
|||
}
|
||||
self.graph.updateItem(self.drawEdge.currentLine, {
|
||||
target: targetNodeModel.id,
|
||||
targetAnchor: targetAnchor ? targetAnchor.anchorIndex : ""
|
||||
targetAnchor: targetAnchor ? targetAnchor.anchorIndex : "",
|
||||
targetAttrs:targetNodeModel.attrs,
|
||||
});
|
||||
|
||||
// ************** 记录historyData的逻辑 start **************
|
||||
|
|
|
|||
|
|
@ -6,20 +6,16 @@
|
|||
|
||||
import dragAddEdge from './drag-add-edge'
|
||||
import hoverEventEdit from './hover-event-edit'
|
||||
import clickEventEdit from './click-event-edit'
|
||||
import dragEventEdit from './drag-event-edit'
|
||||
import keyupEventEdit from './keyup-event-edit'
|
||||
import diceErNode from './dice-er-node'
|
||||
import diceErEdge from './dice-er-edge'
|
||||
|
||||
const obj = {
|
||||
dragAddEdge,
|
||||
hoverEventEdit,
|
||||
// clickEventEdit,
|
||||
dragEventEdit,
|
||||
keyupEventEdit,
|
||||
diceErNode,
|
||||
diceErEdge
|
||||
}
|
||||
|
||||
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',
|
||||
style: {
|
||||
startArrow: false,
|
||||
endArrow: false
|
||||
endArrow: true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
/**
|
||||
* @author: winyuan
|
||||
* @author: Clay
|
||||
* @data: 2019/07/18
|
||||
* @repository: https://github.com/winyuan
|
||||
* @description: 线公共方法
|
||||
*/
|
||||
|
||||
|
|
@ -21,6 +20,7 @@ export default {
|
|||
},
|
||||
name: 'edge-shape'
|
||||
})
|
||||
console.log(keyShape.attrs.endArrow = true)
|
||||
return keyShape
|
||||
},
|
||||
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
|
||||
* @repository: https://github.com/winyuan
|
||||
* @description: 曲线
|
||||
*/
|
||||
|
||||
import utils from "../utils";
|
||||
import base from './base'
|
||||
import { polylineFinding } from './polyline-finding'
|
||||
export default {
|
||||
name: 'top-cubic',
|
||||
extendName: 'cubic',
|
||||
|
|
|
|||
|
|
@ -74,15 +74,15 @@ export default {
|
|||
r: 3,
|
||||
symbol: 'circle',
|
||||
lineWidth: 1,
|
||||
fill: 'white',
|
||||
fill: '#FFFFFF',
|
||||
fillOpacity: 1,
|
||||
stroke: '#096DD9',
|
||||
strokeOpacity: 1,
|
||||
cursor: 'crosshair'
|
||||
},
|
||||
hover: {
|
||||
fillOpacity: 1,
|
||||
strokeOpacity: 1
|
||||
fillOpacity: 0.3,
|
||||
strokeOpacity: 0.5
|
||||
},
|
||||
unhover: {
|
||||
fillOpacity: 0,
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -4,6 +4,7 @@
|
|||
ref="topology"
|
||||
:graph-data="graphData"
|
||||
:node-app-config="nodeAppConfig"
|
||||
:edge-app-config="edgeAppConfig"
|
||||
@doAutoRefresh="doAutoRefresh"
|
||||
@doManualRefresh="doManualRefresh"
|
||||
@doChangeMode="doChangeMode"
|
||||
|
|
@ -15,146 +16,246 @@
|
|||
|
||||
<script>
|
||||
/* 局部注册 */
|
||||
import Topology from "./packages/topology/src/topology";
|
||||
import { deepClone } from "./utils/index";
|
||||
import Topology from './packages/topology/src/topology'
|
||||
import { deepClone } from './utils/index'
|
||||
|
||||
export default {
|
||||
name: "DemoTopology",
|
||||
name: 'DemoTopology',
|
||||
components: {
|
||||
"topology": Topology
|
||||
'topology': Topology
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
graphData: {
|
||||
nodes: [
|
||||
// {
|
||||
// "id": "info",
|
||||
// "label": "Employee",
|
||||
// "attrs": [{
|
||||
// "key": "id",
|
||||
// "type": "number(6)"
|
||||
// },
|
||||
// {
|
||||
// "key": "key",
|
||||
// "type": "varchar(255)"
|
||||
// },
|
||||
// {
|
||||
// "key": "gender",
|
||||
// "type": "enum(M, F)"
|
||||
// },
|
||||
// {
|
||||
// "key": "birthday",
|
||||
// "type": "date"
|
||||
// },
|
||||
// {
|
||||
// "key": "hometown",
|
||||
// "type": "varchar(255)"
|
||||
// },
|
||||
// {
|
||||
// "key": "country",
|
||||
// "type": "varchar(255)"
|
||||
// },
|
||||
// {
|
||||
// "key": "nation",
|
||||
// "type": "varchar(255)"
|
||||
// },
|
||||
// {
|
||||
// "key": "jobId",
|
||||
// "type": "number(3)",
|
||||
// "relation": [{
|
||||
// "key": "id",
|
||||
// "nodeId": "job"
|
||||
// }]
|
||||
// },
|
||||
// {
|
||||
// "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"
|
||||
'nodes': [{
|
||||
'id': 'a72f9f56-d3b6-4f7b-a42f-bf9cc45e7c3c',
|
||||
'x': 144.47865794573642,
|
||||
'y': -12.739970930232559,
|
||||
'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': '' }
|
||||
},
|
||||
{
|
||||
"source": "info",
|
||||
"target": "dept",
|
||||
"sourceKey": "deptId",
|
||||
"targetKey": "id"
|
||||
'selectedIndex': null,
|
||||
'label': '',
|
||||
'appConfig': { 'ip': '', 'port': '', 'sysName': '' },
|
||||
'depth': 0
|
||||
}, {
|
||||
'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': '' }
|
||||
},
|
||||
{
|
||||
"source": "dept",
|
||||
"target": "dept",
|
||||
"sourceKey": "parent",
|
||||
"targetKey": "id"
|
||||
}
|
||||
]
|
||||
'selectedIndex': null,
|
||||
'label': '',
|
||||
'appConfig': { 'ip': '', 'port': '', 'sysName': '' },
|
||||
'depth': 0
|
||||
}], '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: [
|
||||
// { guid: "blue", label: "蓝色", imgSrc: require("../../assets/images/blue.svg") },
|
||||
|
|
@ -163,50 +264,55 @@ export default {
|
|||
],
|
||||
// 节点配置
|
||||
nodeAppConfig: {
|
||||
ip: "节点IP",
|
||||
port: "节点端口",
|
||||
sysName: "设备名称"
|
||||
// ip: '节点IP',
|
||||
// port: '节点端口',
|
||||
// sysName: '设备名称'
|
||||
},
|
||||
edgeAppConfig: {
|
||||
associated: '查询方式',
|
||||
tableComment: '主表字段',
|
||||
relComment: '关联字段'
|
||||
},
|
||||
autoRefreshTimer: null
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let graphData = deepClone(this.graphData);
|
||||
this.$refs.topology.initTopo(graphData);
|
||||
this.randomChange();
|
||||
let graphData = deepClone(this.graphData)
|
||||
this.$refs.topology.initTopo(graphData)
|
||||
this.randomChange()
|
||||
},
|
||||
methods: {
|
||||
doAutoRefresh(interval) {
|
||||
if (interval === -1) {
|
||||
clearInterval(this.autoRefreshTimer);
|
||||
clearInterval(this.autoRefreshTimer)
|
||||
} else {
|
||||
clearInterval(this.autoRefreshTimer);
|
||||
clearInterval(this.autoRefreshTimer)
|
||||
this.autoRefreshTimer = setInterval(() => {
|
||||
this.randomChange();
|
||||
}, interval);
|
||||
this.$once("hook:beforeDestroy", () => {
|
||||
clearInterval(this.autoRefreshTimer);
|
||||
});
|
||||
this.randomChange()
|
||||
}, interval)
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
clearInterval(this.autoRefreshTimer)
|
||||
})
|
||||
}
|
||||
},
|
||||
doChangeMode(graphMode) {
|
||||
clearInterval(this.autoRefreshTimer);
|
||||
let graphData = deepClone(this.graphData);
|
||||
this.$refs.topology.changeGraphMode(graphData, graphMode);
|
||||
clearInterval(this.autoRefreshTimer)
|
||||
let graphData = deepClone(this.graphData)
|
||||
this.$refs.topology.changeGraphMode(graphData, graphMode)
|
||||
},
|
||||
doManualRefresh() {
|
||||
this.randomChange();
|
||||
this.randomChange()
|
||||
},
|
||||
doSaveData(graphData) {
|
||||
console.log(JSON.stringify(graphData));
|
||||
console.log(JSON.stringify(graphData))
|
||||
},
|
||||
randomChange() {
|
||||
let graphData = deepClone(this.$refs.topology.getGraphData());
|
||||
let { nodes } = graphData;
|
||||
this.$refs.topology.changeGraphData(graphData);
|
||||
let graphData = deepClone(this.$refs.topology.getGraphData())
|
||||
let { nodes } = graphData
|
||||
this.$refs.topology.changeGraphData(graphData)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
Loading…
Reference in New Issue