基于G6 3.8.1版本进行构造
主题使用方法:github.com/xitu/juejin…
theme: juejin highlight: github
基本需求: 1.根据后台提供数据生成带有分支的流程图
2.节点自定义 根据具体需求重定义节点样式
基本全部代码:
流程图自定义元素 切换分支<script>
</script>
<!-- <script src="./g6.js"></script> -->
<script src="https://gw.alipayobjects.com/os/lib/antv/g6/3.8.1/dist/g6.min.js"></script>
<!-- <script src="https://gw.alipayobjects.com/os/antv/assets/lib/jquery-3.2.1.min.js"></script> -->
<!--
<script src="https://gw.alipayobjects.com/os/lib/dagre/0.8.4/dist/dagre.min.js"></script> -->
<!-- 3.8.X版本支持插入html节点并且可以成功连线,3.1.x 不支持连线 其他版本未尝试 -->
<script>
//测试数据
var nodeArr = []
var jd = [
{
"nodeId": "start",
"nodeName": "开始",
"relatedIds": [
"bece31ff-15da-11eb-91c7-14f6d8da8bae"
]
},
{
"nodeId": "bece31ff-15da-11eb-91c7-14f6d8da8bae",
"revision": 1,
"nodeName": "申请",
"groupId": "4",
"groupName": "申请人",
"taskKey": "sq",
"relatedIds": ["bmjlsp"]
},
{
"nodeId": "bmjlsp",
"nodeName": "部门经理审批",
"seq": 2,
"relatedIds": [
"end",
"fgfzsp"
]
},
{
"nodeId": "fgfzsp",
"nodeName": "分管副总审批",
"seq": 3,
"relatedIds": [
"jtsctzbjl",
"end"
]
},
{
"nodeId": "jtsctzbjl",
"nodeName": "集团市场拓展部经理",
"seq": 4,
"relatedIds": [
"jtfgfzsp"
]
},
{
"nodeId": "jtfgfzsp",
"nodeName": "集团分管副总审批",
"seq": 5,
"relatedIds": [
"end"
]
},
{
"nodeId": "end",
"nodeName": "结束",
"seq": 2147483647,
"relatedIds": []
}
]
//添加节点
jd.forEach(item => {
if (item.nodeName == "结束") {
nodeArr.push({
id: item.nodeId,
"shape": "circle",
"size": 50,
"label": "结束",
"spjy": 123, //审批建议
})
}else if(item.nodeName == "开始"){
nodeArr.push( //开始节点 固定添加开始节点
{
"id": item.nodeId,
"label": "开始",
"shape": "circle",
"size": 50,
"source": item.nodeId,
"next": item.relatedIds
},
)
} else{
nodeArr.push({
id: item.nodeId,
"borderStatus": computeColor(item.revision, item.outcome), //边框颜色值
"backColor": compoteBackColor(item.revision), //左上角背景色
"nowStatus": item.nodeName, //当前所在流程节点
"name": item.assigneeName,
"time": item.completedTime,
"size": [200, 120],
"spjy": item.approvalComments, //审批建议
"source": item.nodeId,
"next": item.relatedIds, //指向的下一节点数组
})
}
})
//数据源结构
var data = {
nodes: [],
edges: []
};
data.nodes = nodeArr;
console.log(data)
//渲染流程图
constructEdage(data);
var gh = renderFn(data);
//构造边连接
function constructEdage(data) {
var edges = []
data.nodes.forEach(item => {
if (item.next) {
item.next.forEach(d => {
edges.push({
source: item.id,
target: String(d),
})
})
}
})
data.edges = edges;
}
//判断边框颜色值
function computeColor(r, c) {
if (r) {
if (r == 1) {
return '#FFC125'
};
if (r == 2) {
if (c == 1 || c == 2) {
return '#169bd5'
};
};
if (c == 3 || c == 4 || c == 5) {
return '#FF4500'
}
if (r == 3) {
if (c == 2 || c == 1) {
return '#169bd5'
}
}
} else {
return '#e0e0e0'
};
}
//通过节点出现的次数 计算层级 设置画布高度
function computeCount(e) {
var count = 0;
var maxCount = 0;
var countArr = [];
for (let i = 0; i < e.length; i++) { //遍历边对应的id 对"source"进行计数
for (let j = 0; j < e.length; j++) {
if (e[i].source == e[j].source) {
count++;
}
}
if (maxCount < count) {
maxCount = count;
}
if (count > 1 && countArr.indexOf(count) < 0) {
countArr.push(count);
}
count = 0;
}
var sum = 0;
countArr.forEach(item => {
sum += item;
})
console.log(countArr)
return sum || maxCount;
}
//计算上标识背景色
function compoteBackColor(r) {
if (r == 1 || !r) {
return '#d1d1d1'
};
};
function renderFn(data) {
//计算层级
var floorCount = computeCount(data.edges);
console.log(floorCount);
//画布宽度 在更改节点宽度时,需根据具体节点宽度对画布进行调整(节点宽度调整以后需要对节点之间的连线长度进行调整)
var canvansWidth = (data.nodes.length) * 240;
//保持画布宽度与容器宽度相同
document.getElementById("mountNode").style.width = canvansWidth + "px";
var canvansHeight = floorCount * 220;
//保持画布高度与容器高度相同
document.getElementById("mountNode").style.height = canvansHeight + "px";
// 创建 G6 图实例
const graph = new G6.Graph({
renderer: 'svg',
container: 'mountNode', // 指定图画布的容器 id
// 画布宽高
// fitView:true,
// fitViewPadding: [ 20, 40, 50, 20 ],
width: canvansWidth,
height: canvansHeight,
pixelRatio: 100,
maxZoom: 0.9,
animate: true,
layout: {
type: 'dagre', //层级自动布局
rankdir: 'LR', // 从左向右渲染
align: 'DL', // 可选
nodesep: 10, // 节点层距离(上下)
ranksep: 20, // 节点之间距离(左右)
controlPoints:true
},
defaultNode: {
shape: "dom-node"
},
defaultEdge: {
shape: 'polyline',
style: {
endArrow: true,
radius: 0,
offset: 20,
stroke: '#000',
lineWidth:1
},
}
});
//重定义节点样式自定义节点
G6.registerNode('dom-node', {
draw: (cfg, group) => {
const htmlShape = group.addShape('dom', {
attrs: {
width: cfg.size[0],
height: cfg.size[1],
x: -cfg.size[0] / 2,
y: -cfg.size[1] / 2,
html: `
<div id=${cfg.id} class='dom_node' style="background-color: #fff; border: 1px solid ${cfg.borderStatus}; border-radius: 5px; width: ${cfg.size[0] - 5}px; height: ${cfg.size[1] - 5}px; display: inline-block;">
<span class="smallStatus" style="background:${cfg.backColor}">${cfg.nowStatus}</span>
<p class="nodeItem first_item" ><span style="display: inline-block; float: left;">${cfg.nowStatus == "申请" ? "申请":"审批"}人:</span><span class="text_right">${cfg.name || ""}</span></p>
<p class="nodeItem"><span >审批时间:</span><span style="display: inline-block; padding-left:1px" class="text_right">${cfg.time || " "}</span></p>
<p class="nodeItem"><span style="display: inline-block; float: left;">审批意见:</span><span class="nodeText text_right">${cfg.spjy || " "}</span> </p>
</div>
`
},
}, "rect");
return htmlShape;
},
getAnchorPoints() {
return [
// [0, 0.5], // 左侧中间
// [1, 0.5], // 右侧中间
// [0.5, 1], // 上侧中间
// [0.5, 0], // 下侧中间
// [0, 0], // 右侧中间
// [0, 1], // 右侧中间
];
},
});
//加载数据
graph.data(data)
// 渲染图
graph.render();
//返回实例对象,需要再刷新视图时,调用销毁对象方法
return graph;
}
</script>
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.box {
width: 1800px;
height: 550px;
overflow-x: scroll;
border: 1px solid #eee;
white-space: nowrap;
position: absolute;
position: absolute;
top: 50%;
left: 50%;
right: 0;
bottom: 0;
transform: translate(-50%, -50%);
}
.nodeItem {
width: 195px;
text-align: left;
text-indent: 0.5em;
color: gray;
margin-bottom: 4px;
word-wrap: break-word;
word-break: break-all;
font-size: 10px;
overflow: hidden;
}
.dom_node {
display: inline-block;
vertical-align: middle;
text-align: left;
border: 1px solid lightgrey;
border-radius: 5px;
height: 130px;
position: relative;
overflow: hidden;
width: 210px;
font-size: 10px;
}
.first_item {
margin-top: 22px;
}
.smallStatus {
display: inline-block;
position: absolute;
top: 0;
left: 0;
background: #eee;
height: 20px;
padding: 0 5px 0 5px;
font-size: 12px;
border-radius: 3px 0 0 0;
background: #169bd5;
opacity: 0.9;
border: 1px #fff solider;
color: #fff
}
.nodeText {
display: inline-block;
width: 120px;
white-space: normal;
/* word-break: normal; */
display: inline-block;
word-wrap: break-word;
overflow: hidden;
padding: 0 0 5px 0;
height: 35px;
overflow-y: auto;
}
.text_right {
color: #000
}
.nodeText::-webkit-scrollbar {
width: 2px;
height: 1px;
}
.nodeText::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 5px #eee;
background: #535353;
}
.nodeText::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 5px #fff;
border-radius: 10px;
background: #EDEDED;
}