GoJS 是一个用于实现交互式图表的 JavaScript 库,详情可查看官网
根据官网samples实现以下demo
1.安装gojs插件
npm install gojs --save
或者yarn add gojs
2.在vue组件中引入
import go from "gojs";
const $ = go.GraphObject.make;
const palettes={
palette0: [
{ palette: "0", type: "start", text: "开始", nyColor: null, from: true },
{ palette: "0", type: "stop", text: "结束", nyColor: null, to: true },
{
palette: "0",
type: "type1",
text: "demo1",
label: "双击设置",
nyColor: null,
from: true,
to: true,
},
{
palette: "0",
type: "type2",
text: "demo2",
label: "双击设置",
nyColor: null,
from: true,
to: true,
},
],
palette1: [
{
palette: "1",
type: "type3",
text: "demo3",
label: "双击设置",
nyColor: null,
from: true,
to: true,
},
{
palette: "1",
type: "type4",
text: "demo4",
label: "双击设置",
nyColor: null,
from: true,
to: true,
},
{
palette: "1",
type: "type5",
text: "demo5",
label: "双击设置",
nyColor: null,
from: true,
to: true,
},
],
}
let diagram = null;
3.创建div标签元素
<div class="content">
<div class="left">
<div id="palette0" class="palette"></div>
<div id="palette1" class="palette"></div>
</div>
<div class="right">
<div id="diagram" :style="{ height: 'calc(100vh - 305px)' }"></div>
</div>
</div>
样式部分
.content{
display:flex;
.left{
width:300px;
.palette {
width: 100%;
height: 150px;
}
}
.right{
flex:1
}
}
4.行为部分(script)
data() {
return {
nodesData: {},
isReadOnly: false,
};
},
mounted() {
that = this;
diagram = this.createDiagram();
// diagram.model = go.Model.fromJson({});
diagram.commandHandler.canDeleteSelection = function (e) {
//用例获取选中的节点或线
return diagram.selection.all(function (nodeOrLink) {
// console.log(nodeOrLink.data);
//判断是否存在不允许删除的节点或线
if (nodeOrLink.data.text == "结束" || nodeOrLink.data.text == "开始") {
return false;
} else {
return true;
}
});
};
diagram.model.linkFromPortIdProperty = "fromPort";
diagram.model.linkToPortIdProperty = "toPort";
diagram.model.nodeDataArray = [
{
palette: "0",
key: -1,
type: "start",
text: "开始",
from: true,
img: require("@/assets/icons/icons8-start.png"),
},
{
palette: "0",
key: -3,
type: "stop",
text: "结束",
to: true,
img: require("@/assets/icons/icons8-stop.png"),
},
];
this.createPalette("palette0", palettes.palette0);
this.createPalette("palette1", palettes.palette1);
//this.init();用于回显画布内容
},
beforeDestroy() {
diagram.model = go.Model.fromJson({});
},
methods:{
init(){
const configs = JSON.parse({});
configs["nodes"].forEach((node) => {
that.nodesData[node["current"]] = node["config"];
});
configs["diagram"]["nodeDataArray"].forEach((nodeData) => {
nodeData["img"] = require("@/assets/icons/icons8-task-160.png");
});
configs["diagram"]["linkFromPortIdProperty"] = "fromPort";
configs["diagram"]["linkToPortIdProperty"] = "toPort";
diagram.model = go.Model.fromJson(configs["diagram"]);
},
createDiagram() {
return $(go.Diagram, "diagram", {
grid: $(
go.Panel,
"Grid",
$(go.Shape, "LineH", { stroke: "lightgray", strokeWidth: 0.5 }),
$(go.Shape, "LineH", {
stroke: "gray",
strokeWidth: 0.5,
interval: 10,
}),
$(go.Shape, "LineV", { stroke: "lightgray", strokeWidth: 0.5 }),
$(go.Shape, "LineV", {
stroke: "gray",
strokeWidth: 0.5,
interval: 10,
})
),
validCycle: go.Diagram.CycleNotDirected,
"undoManager.isEnabled": true,
nodeTemplate: this.getNodeTemplate(),
linkTemplate: $(
go.Link,
{ selectable: true },
{
routing: go.Link.AvoidsNodes,
corner: 5,
toShortLength: 4,
},
new go.Binding("points").makeTwoWay(),
$(go.Shape, { isPanelMain: true, strokeWidth: 2 }),
$(go.Shape, { toArrow: "Standard", stroke: null })
),
ExternalObjectsDropped: (e) => {
e.subject.each((part) => {
let type = part.data.type;
if (type === "start") {
if (diagram.model.findNodeDataForKey(-1)) {
that.$message.error("节点已存在");
diagram.remove(part);
}
} else if (type === "stop") {
if (diagram.model.findNodeDataForKey(-3)) {
that.$message.error("节点已存在");
diagram.remove(part);
}
}
});
},
});
},
createPalette(id, models) {
models.forEach((model) => {
model["img"] = require("@/assets/icons/icons8-task-160.png");
});
$(go.Palette, id, {
nodeTemplate: $(
go.Node,
go.Panel.Horizontal,
{ desiredSize: new go.Size(100, 20), margin: 0 },
$(
go.Picture,
{ maxSize: new go.Size(16, 16) },
new go.Binding("source", "img")
),
$(
go.TextBlock,
{ maxSize: new go.Size(100, NaN) },
new go.Binding("text", "text")
),
{
selectionAdornmentTemplate: $(
go.Adornment,
"Auto",
$(go.Shape, { fill: null, strokeWidth: 0 }),
$(go.Placeholder)
),
}
),
model: new go.GraphLinksModel(models),
});
},
getNodeTemplate() {
return $(
go.Node,
"Spot",
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(
go.Point.stringify
),
$(
go.Panel,
"Auto",
$(
go.Shape,
"RoundedRectangle",
{
portId: null,
fromLinkableDuplicates: false,
toLinkableDuplicates: false,
fromLinkableSelfNode: false,
toLinkableSelfNode: false,
cursor: "pointer",
fill: "white",
stroke: "#DCDFE6",
strokeWidth: 1,
},
new go.Binding("fromLinkable", "from"),
new go.Binding("toLinkable", "to")
),
$(
go.Panel,
"Horizontal",
$(
go.Picture,
{ maxSize: new go.Size(40, 40) },
new go.Binding("source", "img")
),
$(
go.Panel,
"Vertical",
{ defaultAlignment: go.Spot.Left, margin: 5 },
$(
go.TextBlock,
{ font: "bold 12px sans-serif" },
new go.Binding("text", "text")
),
$(
go.TextBlock,
{
maxSize: new go.Size(100, NaN),
wrap: "WrapFit",
font: "normal 11px sans-serif",
stroke: "#909399",
},
new go.Binding("text", "label")
)
)
)
),
this.makePort("T", go.Spot.Top, false, true),
this.makePort("B", go.Spot.Bottom, true, false),
this.makePort("BL", go.Spot.BottomLeft, true, false),
this.makePort("BR", go.Spot.BottomRight, true, false),
{
selectionAdornmentTemplate: $(
go.Adornment,
"Auto",
$(go.Shape, "RoundedRectangle", {
fill: null,
stroke: "#303133",
strokeWidth: 1,
}),
$(go.Placeholder)
), // 设置选中效果
linkValidation: that.linkValidation,
mouseEnter: (e, node) => {
node.ports.each((port) => {
if (port.portId === "T") {
port.fill = node.data.to ? "#16BEFF" : null;
} else if (port.portId === "B" && node.data.type != "decision") {
port.fill = node.data.from ? "#16BEFF" : null;
} else if (
port.portId === "BL" &&
node.data.type === "decision"
) {
port.fill = node.data.from ? "#16BEFF" : null;
} else if (
port.portId === "BR" &&
node.data.type === "decision"
) {
port.fill = node.data.from ? "#16BEFF" : null;
}
});
},
mouseLeave: (e, node) => {
node.ports.each((port) => {
if (
port.portId === "T" ||
port.portId === "B" ||
port.portId === "BL" ||
port.portId === "BR"
) {
port.fill = null;
}
});
},
doubleClick: (e, node) => {
const type = node.data.type;
let key = type + node.data.key;
console.log(type,key)
},
}
);
},
makePort(name, spot, output, input) {
return $(
go.Panel,
"Horizontal",
{ alignment: spot, alignmentFocus: spot },
$(
go.TextBlock,
// { font: "500 12px sans-serif", text: name == "BL" ? Y : null },
{ font: "500 12px sans-serif", text: name == "BL" ? null : null },
new go.Binding("stroke", "nyColor")
),
$(go.Shape, "Circle", {
fill: null,
stroke: null,
desiredSize: new go.Size(7, 7),
portId: name,
fromSpot: spot,
toSpot: spot,
fromLinkable: output,
toLinkable: input,
cursor: "pointer",
fromMaxLinks: name == "BR" || name == "BL" ? 1 : 5,
}),
$(
go.TextBlock,
// { font: "500 12px sans-serif", text: name == "BR" ? N : null },
{ font: "500 12px sans-serif", text: name == "BR" ? null : null },
new go.Binding("stroke", "nyColor")
)
);
},
// 校验节点间是否可连接通过返回true或者false允许和静止连接
linkValidation(fromNode, fromPort, toNode, toPort) {
const fromPalette = fromNode.data.palette;
const fromType = fromNode.data.type;
const toPalette = toNode.data.palette;
const toType = toNode.data.type;
let isRight = false; // 连线是否正确
let linkedOtherCount = 0; // 已经连接了几个节点
let beLinkedCount = 0; // 已经被几个节点连接
fromNode.findNodesOutOf().each(() => {
linkedOtherCount++;
});
toNode.findNodesInto().each(() => {
beLinkedCount++;
});
console.log(
"from",
fromType,
"to",
toType,
"连几个",
linkedOtherCount,
"被几个",
beLinkedCount,
"parent",
fromPalette,
"parent",
toPalette,
"fromPort",
fromPort,
"toPort",
toPort
);
return true;
}
}
获取diagram生成的json数据
diagram.model.modelData.position =
go.Point.stringify(diagram.position); let model =
JSON.parse(diagram.model.toJson()); console.log(“diagram”, model);