效果图:
raphael.html 源码
<html>
<head>
</head>
<body>
<center>
<h1>Raphael JS - 组织结构图/层次结构图/多叉树图</h1>
</center>
</body>
<script src="https://cdn.bootcss.com/raphael/2.2.7/raphael.js"></script>
<script src="./raphael-orgchart.js"></script>
<script>
var data = [];
data.push({
"id" : "0",
"name" : "root",
"parentId" : -1,
"txt1" : "txt1-root"
});
data.push({
"id" : "1",
"name" : "name1",
"parentId" : 0,
"txt1" : "txt1-name1"
});
data.push({
"id" : "2",
"name" : "name2",
"parentId" : 0,
"txt1" : "txt1-name2"
});
data.push({
"id" : "3",
"name" : "name3",
"parentId" : 0,
"txt1" : "txt1-name3"
});
data.push({
"id" : "4",
"name" : "name4",
"parentId" : 1,
"txt1" : "txt1-name4"
});
data.push({
"id" : "5",
"name" : "name5",
"parentId" : 1,
"txt1" : "txt1-name5"
});
data.push({
"id" : "6",
"name" : "name6",
"parentId" : 1,
"txt1" : "txt1-name6"
});
data.push({
"id" : "7",
"name" : "name7",
"parentId" : 3,
"txt1" : "txt1-name7"
});
data.push({
"id" : "8",
"name" : "name8",
"parentId" : 3,
"txt1" : "txt1-name8"
});
data.push({
"id" : "9",
"name" : "name9",
"parentId" : 5,
"txt1" : "txt1-name9"
});
data.push({
"id" : "10",
"name" : "name10",
"parentId" : 5,
"txt1" : "txt1-name10"
});
data.push({
"id" : "11",
"name" : "name11",
"parentId" : 6,
"txt1" : "txt1-name11"
});
data.push({
"id" : "12",
"name" : "name12",
"parentId" : 6,
"txt1" : "txt1-name12"
});
data.push({
"id" : "13",
"name" : "name13",
"parentId" : 6,
"txt1" : "txt1-name13"
});
data.push({
"id" : "14",
"name" : "name14",
"parentId" : 7,
"txt1" : "txt1-name14"
});
data.push({
"id" : "15",
"name" : "name15",
"parentId" : 7,
"txt1" : "txt1-name15"
});
data.push({
"id" : "16",
"name" : "name16",
"parentId" : 7,
"txt1" : "txt1-name16"
});
var chart = new orgchart(5, 30, data);
chart.drawChart();
</script>
</html>
raphael-orgchart.js 源码
/**
* Raphael JS - 组织结构图/层次结构图/多叉树图
*/
orgchart = function(Px, Py, D) {
if (!Array.isArray(D)) {
console.log("Need array args!");
return;
}
var data = D;
// 参考原点坐标
var X = Px;
var Y = Py;
// 最大层数/行数
var maxRowNum = 0;
// 最大列数
var maxColNum = 0;
// 单元格宽度
var cellW = 100;
// 单元格高度
var cellH = 50;
// 水平间距/列距
var hSpace = 50;
// 垂直间距/行距
var vSpace = 50;
// 画布对象
var paper;
// 画布宽度
var paperW = 0;
// 画布高度
var paperH = 0;
this.drawChart = function init() {
calc();
draw();
}
//
function calc() {
// 统计不重复的父节点总个数
var _rowSet = new Set();
for (var i = 0; i < data.length; i++) {
data[i]["xy"] = {
"x" : X,
"y" : Y
};
//
_rowSet.add(data[i].parentId);
}
//
maxRowNum = _rowSet.size;
// 节点总数-(父节点总数-1); 1--根节点没有父节点,排除
maxColNum = data.length - (_rowSet.size - 1);
paperW = maxColNum * (cellW + hSpace);
paperH = maxRowNum * (cellH + vSpace);
paper = new Raphael(X, Y, paperW, paperH);
//
var rootObj = findRoot();
if (rootObj != null) {
calcXY(rootObj, 0);
calcParentXY(rootObj);
}
// console.log("paperW= " + paperW + " paperH= " + paperH + " maxRowNum=
// " + maxRowNum + " maxColNum= " + maxColNum)
}
function calcXY(obj, level) {
level++;
var childrenArr = getChildren(obj);
for (var i = 0; i < childrenArr.length; i++) {
//
if (i == 0) {
childrenArr[i].xy.x = obj.xy.x;
} else {
var offsetX = 0;
var childrenArr2 = getChildren(childrenArr[i - 1]);
if (childrenArr2.length > 0) {
offsetX = childrenArr2[childrenArr2.length - 1].xy.x;
} else {
offsetX = childrenArr[i - 1].xy.x;
}
childrenArr[i].xy.x = offsetX + (cellW + hSpace);
}
childrenArr[i].xy.y += (cellH + vSpace) * level;
obj.xy.x = childrenArr[i].xy.x
//
calcXY(childrenArr[i], level);
}
// console.log(" | " + level + " calcXY" + obj.name + " " + obj.xy.x + "
// " + obj.xy.y)
}
function calcParentXY(obj) {
var childrenArr = getChildren(obj);
for (var i = 0; i < childrenArr.length; i++) {
calcParentXY(childrenArr[i]);
}
if (childrenArr.length > 0) {
if (childrenArr.length % 2 == 0) {
obj.xy.x = (childrenArr[0].xy.x + childrenArr[childrenArr.length - 1].xy.x) / 2;
} else {
obj.xy.x = childrenArr[Math.floor(childrenArr.length / 2)].xy.x;
}
}
}
function findRoot() {
for (var i = 0; i < data.length; i++) {
if (data[i].parentId == -1) {
return data[i];
}
}
return null;
}
function getChildren(obj) {
var childrenArr = [];
for (var i = 0; i < data.length; i++) {
if (data[i].parentId == obj.id) {
childrenArr.push(data[i]);
}
}
return childrenArr;
}
function draw() {
for (var i = 0; i < data.length; i++) {
drawRect(data[i]);
//
var childrenArr = getChildren(data[i]);
for (var j = 0; j < childrenArr.length; j++) {
drawLine(data[i], childrenArr[j], j == 0 ? true : false)
}
}
}
function drawLine(parentObj, obj, isFirst) {
//
var Pp_X = parentObj.xy.x + cellW / 2;
var Pp_Y1 = parentObj.xy.y + cellH;
var P_Y = parentObj.xy.y + cellH + vSpace / 2;
//
var Pc_X = obj.xy.x + cellW / 2;
var Pc_Y1 = obj.xy.y;
//
var linePathStr = " M" + Pc_X + " " + P_Y + "L" + Pp_X + " " + P_Y
+ " M" + Pc_X + " " + P_Y + "L" + Pc_X + " " + Pc_Y1;
if (isFirst) {
linePathStr = "M" + Pp_X + " " + Pp_Y1 + "L" + Pp_X + " " + P_Y
+ linePathStr;
}
//
var line = paper.path(linePathStr);
line.attr({
stroke : "#000"
});
//
var txt = paper.text(Pc_X, (obj.xy.y + P_Y) / 2, obj.txt1);
txt.attr({
fill : "#4169E1",
"font-size" : 10
});
}
function drawRect(obj) {
//
var rect = paper.rect(obj.xy.x, obj.xy.y, cellW, cellH, 10);
rect.mousemove(function() {
this.attr("fill", "#ADFF2F");
});
rect.mouseout(function() {
this.attr("fill", "#fff");
});
rect.attr({
title : obj.name
});
//
var txt = paper.text(obj.xy.x + cellW / 2, obj.xy.y + cellH / 2,
obj.name);
}
}