Raphael JS - 组织结构图/层次结构图/多叉树图

效果图:

输入图片说明

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);
	}
}

转载于:https://my.oschina.net/kind790/blog/1530121

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值