js插件 | 插件特色 | 文档 |
---|---|---|
antv-x6 | 优先推荐使用,开源代码免费,文档为中文 | 中文文档(https://antv-x6.gitee.io/zh/d... demo |
gojs | 有代码,可以个人使用,商业使用需要授权,兼容性比较好 | 英文文档https://gojs.net.cn/samples/m... |
mxGraph | 开源免费代码,但是算法不怎么友好,复杂的流程不推荐使用 | 英文文档http://jgraph.github.io/mxgraph/docs/manual.html |
antv-x6
1、引用js插件
<script src="./source/js/antv_x6/x6.js"></script>
<script src="./source/js/antv_x6/layout.min.js"></script>
2、创建div及节点样式
<div id="container"></div>
<style>
.antv_x6_node_Orange {
width: 100%;
height: 100%;
display: flex;
border: 1px solid #b5b1b1;
place-content: center;
align-items: center;
/* background: #61D2F7; */
background: -webkit-linear-gradient(top,#61D2F7,#f8f8f8);
flex-direction: column;
border-radius: 4px;
color: rgb(34, 34, 34);
cursor: pointer;
box-shadow: rgb(0 112 204 / 6%) 0px 2px 3px 0px;
}
.antv_x6_node_Orange > img {
margin-bottom: 10px;
}
.antv_x6_node_Orange > span {
font-size: 12px;
text-align: center;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
display: -webkit-box;
}
</style>
3、数据格式
let data = {
"nodes": [{ "id": "100014", "type": "1", "value": "1111" },
{ "id": "100015", "type": "1", "value": "2" },
{ "id": "100016", "type": "1", "value": "3" },
{ "id": "100017", "type": "1", "value": "4" },
{ "id": "100018", "type": "1", "value": "5" },
{ "id": "100019", "type": "1", "value": "6" },
{ "id": "100020", "type": "1", "value": "7" },
{ "id": "100021", "type": "1", "value": "8" },
{ "id": "100022", "type": "1", "value": "9" },
{ "id": "100023", "type": "1", "value": "10" },
{ "id": "100024", "type": "1", "value": "11" },
{ "id": "100025", "type": "1", "value": "12" },
{ "id": "100026", "type": "1", "value": "13" },
{ "id": "100027", "type": "1", "value": "14" },
{ "id": "100028", "type": "1", "value": "15" },
{ "id": "100029", "type": "1", "value": "16" },
{ "id": "100030", "type": "1", "value": "17" },
{ "id": "100031", "type": "1", "value": "18" },
{ "id": "100032", "type": "1", "value": "19" },
{ "id": "100033", "type": "1", "value": "20" },
{ "id": "100034", "type": "1", "value": "21" },
{ "id": "100035", "type": "1", "value": "22" },
{ "id": "100036", "type": "1", "value": "23" },
{ "id": "100037", "type": "1", "value": "24" }
],
"edges": [
{
"source": "100014", "target": "100015"
},
{ "source": "100015", "target": "100016" },
{ "source": "100016", "target": "100017" },
{ "source": "100017", "target": "100018" },
{ "source": "100018", "target": "100019" },
{ "source": "100017", "target": "100020" },
{ "source": "100017", "target": "100021" },
{ "source": "100017", "target": "100022" },
{ "source": "100017", "target": "100023" },
{ "source": "100017", "target": "100024" },
{ "source": "100024", "target": "100025" },
{ "source": "100024", "target": "100026" },
{ "source": "100024", "target": "100027" },
{ "source": "100024", "target": "100028" },
{ "source": "100024", "target": "100029" },
{ "source": "100025", "target": "100030" },
{ "source": "100026", "target": "100030" },
{ "source": "100027", "target": "100030" },
{ "source": "100028", "target": "100030" },
{ "source": "100029", "target": "100030" },
{ "source": "100019", "target": "100031" },
{ "source": "100020", "target": "100031" },
{ "source": "100021", "target": "100031" },
{ "source": "100022", "target": "100031" },
{ "source": "100023", "target": "100031" },
{ "source": "100030", "target": "100031" },
{ "source": "100031", "target": "100032" },
{ "source": "100032", "target": "100033" },
{ "source": "100033", "target": "100034" },
{ "source": "100034", "target": "100035" },
{ "source": "100035", "target": "100036" },
{ "source": "100036", "target": "100037" }
]
}
4、js方法
//初始化画布
function initGraph (mapContainer, mapWidth, mapHeight) {
const graph = new X6.Graph(getGraphData(mapContainer, mapWidth, mapHeight));
return graph
}
//初始化获取画布配置,参数(地图容器,宽度,高度)
function getGraphData(mapContainer, mapWidth, mapHeight) {
//浏览器宽度
const windowWidth =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth;
//浏览器高度
var windowHeight =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight ||
500;
windowHeight = windowHeight < 500 ? 500 :windowHeight
// 画布容器对象
const container = document.getElementById(mapContainer);
console.log(mapContainer, mapWidth, mapHeight);
const graphData = {
container: container,
width: mapWidth || windowWidth, //画布宽度
height: mapHeight || windowHeight - 20, //画布高度
background: {
color: "#fffbe6", // 设置画布背景颜色
},
grid: {
size: 10, // 网格大小 10px
visible: true, // 渲染网格背景
},
scroller: {
enabled: true,//画布是否有滚动条
pannable: true,
className: "my-scroller",
},
mousewheel: {
enabled: true,
modifiers: ["ctrl", "meta"],
},
connecting: {
router: {
name: "manhattan",//连接线为直线
// name: "metro",//弯线
},
},
};
return graphData;
}
// 布局对象
const { DagreLayout } = window.layout;
// 算法布局
const dagreLayout = new DagreLayout({
type: "dagre",
rankdir: "LR",//布局的方向
align: "DL",//节点对齐方式
ranksep: 20,//层间距
nodesep: 10,//节点距离
controlPoints: true,
});
// 连线样式
const edgeType = {};
function formatEdge(edgesData) {
for (var i in edgesData) {
var edge = edgesData[i];
let attrs = {
line: {
stroke: "#b5b1b1",//连线的颜色
strokeWidth: 1.5,//连线宽度
},
};
edge.attrs = attrs;
Object.assign(edge, edgeType);
}
console.log(edgesData);
return edgesData;
}
function layoutGraph (data) {
var newModel = dagreLayout.layout(data)
return newModel
}
//创建节点
function createNodeDom (doc, value, type) {
// doc对象直接引用页面传至,减少重复获取doc对象
var wrap = null
if (!doc) doc = document
// 创建div
wrap = doc.createElement('DIV')
wrap.className = 'antv_x6_node_Orange'
// 创建span 展示数据
span = doc.createElement('SPAN')
span.innerText = value
span.title = value
// 将span 与 img 添加到wrap中
wrap.appendChild(span)
return wrap
}
//数据格式化
function x6DataFormat (data, doc) {
var nodes = data.nodes
var edges = data.edges
var x6Nodes = []
var x6Data = {}
for (var i in nodes) {
var nodeData = nodes[i]
var value = nodeData.value
var type = nodeData.type
var nodeHtmlData = {}
if (!doc) doc = document
var wrapDom = createNodeDom(doc, value, type)
nodeHtmlData.id = nodeData.id
nodeHtmlData.shape = 'html'
nodeHtmlData.width = 64
nodeHtmlData.height = 30,
nodeHtmlData.html = wrapDom
x6Nodes.push(nodeHtmlData)
}
var newedges = formatEdge(edges)//连线
x6Data.nodes = x6Nodes
x6Data.edges = newedges
return x6Data
}
5、js调用
// 初始化画布
const graph = initGraph("container");
// 获取后台数据并格式化
var x6Data = x6DataFormat(data, document);
const newModel = layoutGraph(x6Data);
// const newModel = x6Data;
graph.fromJSON(newModel);
// 将画布内容中心与视口中心对齐
graph.centerContent();
//节点点击事件
graph.on("node:click", function ( event ) {
console.log(event)
});
6、效果图
mxGraph
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript">
mxBasePath = '../src';
</script>
<style>
#graphContainer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: auto;
}
</style>
<!--引入支持库文件 -->
<script type="text/javascript" src="../src/js/mxClient.js"></script>
</head>
<body>
<div id="graphContainer"></div>
</body>
<script>
if (!mxClient.isBrowserSupported()) {
// 判断是否支持mxgraph
mxUtils.error("Browser is not supported!", 200, false);
} else {
// 在容器中创建图表
let container = document.getElementById("graphContainer");
var model = new mxGraphModel();
var graph = new mxGraph(container, model);
//设置元素可被连接线连接
graph.setConnectable(false);
//设置元素可编辑,不然无法自动布局
graph.setCellsLocked(false);
//设置两个节点是否可以建立多个连接
graph.setMultigraph(false);
//cell创建支持传入html
graph.setHtmlLabels(true);
//是否允许线单独存在
graph.setAllowDanglingEdges(false);
//设置cell可选中
graph.setCellsSelectable(false);
//设置面板可以扩大
graph.setPanning(false);
graph.setDisconnectOnMove(false) //边被拖时,始终保持连接
mxGraphHandler.prototype.guidesEnabled = false // 启用对齐线帮助定位
// // 设置自动调整大小
// graph.setAutoSizeCells(true);
// graph.setPanning(true);
// graph.panningHandler.useLeftButtonForPanning = true;
// // 允许连线的目标和源是同一元素
// graph.setAllowLoops(true);
//自定义连线
mxEdgeStyle.MyStyle = function (state, source, target, points, result) {
if (source != null && target != null) {
console.log(state, source, target, points, result)
// var pt = new mxPoint(target.getCenterX(), source.getCenterY());
var pt = new mxPoint(target.x, source.getCenterY());
// if (mxUtils.contains(source, pt.x, pt.y)) {
// pt.y = source.y + source.height;
// }
result.push(pt);
}
}
mxStyleRegistry.putValue('myEdgeStyle', mxEdgeStyle.MyStyle);
// 修改节点默认样式
var style = graph.getStylesheet().getDefaultVertexStyle();
style[mxConstants.STYLE_FILLCOLOR] = "#61D2F7";//节点背景颜色
style[mxConstants.STYLE_STROKECOLOR] = "#797979";//节点边框颜色
style[mxConstants.STYLE_GRADIENTCOLOR] = '#ffffff';//节点背景渐变色
style[mxConstants.STYLE_STROKEWIDTH] = 1.5;//节点边框宽度
style[mxConstants.STYLE_FONTCOLOR] = "#000";//节点字体颜色
style[mxConstants.STYLE_FONTSIZE] = 15;//节点字体大小
style[mxConstants.STYLE_SPACING] = 10;//节点自适应内边距
// style[mxConstants.STYLE_SPACING_BOTTOM] = 30;
style = graph.getStylesheet().getDefaultEdgeStyle();
style[mxConstants.STYLE_ROUNDED] = true;//边线是否圆角
style[mxConstants.STYLE_STROKECOLOR] = "#797979";//边线颜色
// style[mxConstants.STYLE_ORTHOGONAL] = "orthogonal";
style[mxConstants.STYLE_STROKEWIDTH] = 1.5;//边线宽度
style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector
// style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ToptBottom
// style[mxConstants.STYLE_EDGE] = mxEdgeStyle.LeftToRight;
// style[mxConstants.STYLE_EDGE] = mxEdgeStyle.OrthConnector;
// style[mxConstants.STYLE_EDGE] = mxEdgeStyle.SegmentConnector;
// style[mxConstants.STYLE_EDGE] = mxEdgeStyle.MyStyle;
// style[mxConstants.STYLE_EDGE]= mxEdgeStyle.EntityRelation
style[mxConstants.STYLE_ORTHOGONAL_LOOP] = 1;
style[mxConstants.STYLE_JETTY_SIZE] = "auto";
var parent = graph.getDefaultParent();
graph.getModel().beginUpdate();
try {
//数据格式转化
var result = {
"nodes": [
{
"id": "10001",
"value": "1",
"type": "2"
},
{
"id": "2",
"value": "2",
"type": "1"
},
{
"id": "3",
"value": "3",
"type": "1"
},
{
"id": "4",
"value": "4"
},
{
"id": "5",
"value": "5",
"type": "1"
},
{
"id": "6",
"value": "6"
},
{
"id": "7",
"value": "7"
},
{
"id": "8",
"value": "8"
},
{
"id": "9",
"value": "9"
},
{
"id": "10",
"value": "10"
},
{
"id": "11",
"value": "11"
},
{
"id": "12",
"value": "12"
},
{
"id": "13",
"value": "13"
},
{
"id": "14",
"value": "14"
},
{
"id": "15",
"value": "15"
},
{
"id": "16",
"value": "16"
},
{
"id": "17",
"value": "17"
},
{
"id": "18",
"value": "18测试"
},
{
"id": "19",
"value": "18测试"
},
{
"id": "20",
"value": "18测试"
}
],
"edges": [
{
"source": "10001",
"target": "2"
},
{
"source": "2",
"target": "3"
},
{
"source": "3",
"target": "4"
},
{
"source": "4",
"target": "5"
},
{
"source": "5",
"target": "6"
},
{
"source": "4",
"target": "7"
},
{
"source": "4",
"target": "8"
},
{
"source": "4",
"target": "9"
},
{
"source": "4",
"target": "10"
},
{
"source": "4",
"target": "11"
},
{
"source": "11",
"target": "13"
},
{
"source": "11",
"target": "12"
},
{
"source": "11",
"target": "14"
},
{
"source": "11",
"target": "15"
},
{
"source": "11",
"target": "16"
},
{
"source": "12",
"target": "17"
},
{
"source": "13",
"target": "17"
},
{
"source": "14",
"target": "17"
},
{
"source": "15",
"target": "17"
},
{
"source": "16",
"target": "17"
},
{
"source": "6",
"target": "18"
},
{
"source": "7",
"target": "18"
},
{
"source": "8",
"target": "18"
},
{
"source": "9",
"target": "18"
},
{
"source": "10",
"target": "18"
},
{
"source": "17",
"target": "18"
},
{
"source": "5",
"target": "19"
}
]
}
var childList = []
for (let i = 0; i < result.nodes.length; i++) {
var childId = result.nodes[i].id;
child = graph.insertVertex(
parent,
result.nodes[i].id,//节点id,id不能为1
result.nodes[i].value,//节点内容
0,//水平居中
30,//距离顶部高度
130,//节点宽度
30,//节点高度
)
childList.push(child)
}
// console.log(childList)
for (let i = 0; i < result.edges.length; i++) {
var source = getNodeData(childList, result.edges[i].source);
var target = getNodeData(childList, result.edges[i].target);
graph.insertEdge(parent, null, '', source, target);
}
} finally {
// Updates the display
graph.getModel().endUpdate();
}
// 自动布局
// let layout = new mxFastOrganicLayout(graph);//组织结构,排除
// let layout = new mxCompactTreeLayout(graph);//树型结构
// mxCompactTreeLayout.prototype.resetEdges = false
// mxCompactTreeLayout.prototype.levelDistance = 10
// mxCompactTreeLayout.prototype.horizontal = false
// mxCompactTreeLayout.prototype.invert = true
// mxCompactTreeLayout.prototype.resizeParent = false
// mxCompactTreeLayout.prototype.maintainParentLocation = true
// mxCompactTreeLayout.prototype.groupPaddingTop = 10
// mxCompactTreeLayout.prototype.groupPaddingRight = 100
// mxCompactTreeLayout.prototype.nodeDistance = 20
var layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_WEST, true);
mxHierarchicalLayout.prototype.intraCellSpacing = 30
mxHierarchicalLayout.prototype.fineTuning = false
mxHierarchicalLayout.prototype.traverseAncestors = false
mxHierarchicalLayout.prototype.resizeParent = true
// 无关系实体之间的间距
mxHierarchicalLayout.prototype.interHierarchySpacing = 20
// 层级之间的距离
mxHierarchicalLayout.prototype.interRankCellSpacing = 50
// mxHierarchicalLayout.prototype.crossingStage = true
mxHierarchicalLayout.prototype.parallelEdgeSpacing = 0
// layout.orientation=mxConstants.DIRECTION_NORTH;
// var layout = new mxSwimlaneLayout(graph);
// var layout = new mxCircleLayout(graph);//圆形结构,排除
// var layout = new mxEdgeLabelLayout(graph);//排除
// var layout = new mxParallelEdgeLayout(graph);//排除
// var layout = new mxPartitionLayout(graph, true, 10, 20);//排除
// var layout = new mxRadialTreeLayout(graph, false, 30, 200);//排除
// var layout = new mxStackLayout(graph, true, 100, 200);//排除
layout.disableEdgeStyle = false;
// console.log(layout)
layout.execute(graph.getDefaultParent());
// 居中
var bounds = graph.getGraphBounds();
var margin = margin || 10;
graph.container.style.overflow = "hidden";
graph.view.setTranslate(
-bounds.x - (bounds.width - graph.container.clientWidth) / 2,
-bounds.y - (bounds.height - graph.container.clientHeight) / 2
);
while ((bounds.width + margin * 2) > graph.container.clientWidth
|| (bounds.height + margin * 2) > graph.container.clientHeight) {
graph.zoomOut();
bounds = graph.getGraphBounds();
}
graph.container.style.overflow = "auto";
}
// 获取节点格式
function getNodeData(childList, value) {
let getNode;
for (let j = 0; j < childList.length; j++) {
if (childList[j].id == value) {
getNode = childList[j]
}
}
// console.log(value, getNode)
return getNode
}
</script>
</html>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。