文档章节

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

kindcao
 kindcao
发布于 2017/09/06 16:51
字数 757
阅读 194
收藏 2

效果图:

输入图片说明

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

© 著作权归作者所有

共有 人打赏支持
kindcao
粉丝 5
博文 17
码字总数 6657
作品 0
深圳
高级程序员
私信 提问
使用Javascript来实现的超炫组织结构图(Organization Chart)

最近有个内部项目需要使用组织结构图(organization chart), 寻找了一些开源的项目及其类库,发现竟然没有现成的JS类库可以使用,找到一些简单的JS实现,不过界面及其操作及其简单,不过功夫...

gbin1
2011/06/29
0
3
帮助你生成组织结构图的jQuery插件 - jOrgChart

日期:2013-3-17 来源:GBin1.com 在线演示 大家可能看到过使用javascript类库JavaScript InfoVis Toolkit实现的特效组织结构图,这里我们使用jQuery插件-jOrgchart也同样可以实现一个组织结...

gbin1
2013/03/19
2.7K
3
利用内存多叉树实现Ext JS中的无限级树形菜单(一种构建多级有序树形结构JSON的方法)

利用内存多叉树实现Ext JS中的无限级树形菜单(一种构建多级有序树形结构JSON的方法) 一、问题研究的背景和意义 目前在Web应用程序开发领域,Ext JS框架已经逐渐被广泛使用,它是富客户端开...

星星知我心
2012/01/30
3.1K
4
利用多叉树实现Ext JS中的无限级树形菜单(一种构建多级有序树形结构JSON的方法)

一、问题研究的背景和意义 目前在Web应用程序开发领域,Ext JS框架已经逐渐被广泛使用,它是富客户端开发中出类拔萃的框架之一。在Ext的UI控件中,树形控件无疑是最为常用的控件之一,它用来...

Alex_曰生
2014/12/01
0
2
10 个非常有用的 SVG 动画的 JavaScript 库

SVG 通常可以用作跨分辨率视频。这意味着在一块高分屏幕上不会降低图片的锐度。此外,你甚至可以让SVG动起来,通过使用一些javascript类库。下面,我们分享一些javascript类库,这些类库会帮...

oschina
2015/02/12
12.8K
12

没有更多内容

加载失败,请刷新页面

加载更多

如何很绅士的使用线程池

前言 平时接触过多线程开发的童鞋应该都或多或少了解过线程池,之前发布的《阿里巴巴 Java 手册》里也有一条: 可见线程池的重要性。 简单来说使用线程池有以下几个目的: 线程是稀缺资源,不...

瑞查德-Jack
16分钟前
2
0
Java开发必会的Linux命令

1.查找文件find / -name filename.txt 根据名称查找/目录下的filename.txt文件。find . -name "*.xml" 递归查找所有的xml文件find . -name "*.xml" |xargs grep "hello world" 递归...

奥特曼之王
18分钟前
3
0
【 58沈剑 架构师之路】各种SQL到底加了什么锁?

有朋友留言:你TM讲了这么多,锁分了这么多类型,又和事务隔离级别相关,又和索引相关,究竟能不能直接告诉我,一个SQL到底加了什么锁!? 我竟无言以对。 好吧,做过简单梳理之后,今天尝试...

张锦飞
20分钟前
2
0
打包 压缩 命令tar zip

打包 压缩 命令tar zip tar语法 #压缩 tar -czvf ***.tar.gz tar -cjvf ***.tar.bz2 #解压缩 tar -xzvf ***.tar.gz tar -xjvf ***.tar.bz2  tar [主选项+辅选项] 文件或目录 主选项是必须要...

linjin200
25分钟前
1
0
使用form表单同时实现上传文件和提交文本数据

使用form表单同时实现上传文件和提交文本数据,此示例中在后台将文件上传到阿里的oss存储服务器中 申请oss相关账号: endpoint = "http://oss-cn-qingdao.aliyuncs.com"; accessKeyId = "key"...

貔貅叔
31分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部