Echarts可视化开发之树型图(公司人事架构图)

引言:Echarts是百度开发的一款可视化的开源js框架,诸如此类的框架很多,今天我们就重点研究Echarts。使用Echarts非常简单,我们将需要展示的数据源以及可视化效果以参数的形式传入Echarts中即可。

一.Echarts使用

我们以官网的一个关于制作简单的树形图为例子,说明Echarts开发的整套流程。

1.开发流程

1).编写visual.hmtl文件,并引入echarts.js文件。

我们这里使用的是echarts 2.x版本,因为3.x版本中tree结构被移除了。详情见echarts配置及下载官方文档

2).定义一个容器

我们将可视化展示的图形放在一个定制好的容器中,这里所说的容器是div或者 可以容纳其他元素的便签。

3).配置数据源和参数

通过echarts提供的接口配置我们需要展示的数据源和效果

2.demo程序

1)效果展示如下:


2)核心代码如下:

<html>
<head>
  <meta charset="UTF-8">
<title>社交网络</title>
 <style>
</style>
   <script src="echarts-2.x.js"></script>
   </head>
  <body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
   <div style="padding:20px;width:100%;height:100%;"> 
               <div id="main" style="width: 1104px;height:464px;">
               </div>
 </div>
    <script type="text/javascript">
	//定义echarts容器
    var myChart = echarts.init(document.getElementById('main'), 'macarons');
    option = {
    title : {
        text: '手机品牌',
        subtext: '线、节点样式'
    },
    series : [
        {
            name:'树图',
            type:'tree',
            orient: 'horizontal',  // vertical horizontal
            rootLocation: {x: 100, y: '60%'}, // 根节点位置  {x: 'center',y: 10}
            nodePadding: 20,
            symbol: 'circle',
            symbolSize: 40,
            itemStyle: {
                normal: {
                    label: {
                        show: true,
                        position: 'inside',
                        textStyle: {
                            color: '#cc9999',
                            fontSize: 15,
                            fontWeight:  'bolder'
                        }
                    },
                    lineStyle: {
                        color: '#000',
                        width: 1,
                        type: 'broken' // 'curve'|'broken'|'solid'|'dotted'|'dashed'
                    }
                },
                emphasis: {
                    label: {
                        show: true
                    }
                }
            },
            data: [
                {
                    name: '手机',
                    value: 6,
                    symbolSize: [90, 70],
                    symbol: 'image://http://www.iconpng.com/png/ecommerce-business/iphone.png',
                    itemStyle: {
                        normal: {
                            label: {
                                show: false
                            }
                        }
                    },
                    children: [
                        {
                            name: '小米',
                            value: 4,
                            symbol: 'image://http://pic.58pic.com/58pic/12/36/51/66d58PICMUV.jpg',
                            itemStyle: {
                                normal: {
                                    label: {
                                        show: false
                                    }
                                }
                            },
                            symbolSize: [60, 60],
                            children: [
                                {
                                    name: '小米1',
                                    symbol: 'circle',
                                    symbolSize: 20,
                                    value: 4,
                                    itemStyle: {
                                        normal: {
                                            color: '#fa6900',
                                            label: {
                                                show: true,
                                                position: 'right'
                                            },
                                            
                                        },
                                        emphasis: {
                                            label: {
                                                show: false
                                            },
                                            borderWidth: 0
                                        }
                                    }
                                },
                                {
                                    name: '小米2',
                                    value: 4,
                                    symbol: 'circle',
                                    symbolSize: 20,
                                    itemStyle: {
                                        normal: {
                                            label: {
                                                show: true,
                                                position: 'right',
                                                formatter: "{b}"
                                            },
                                            color: '#fa6900',
                                            borderWidth: 2,
                                            borderColor: '#cc66ff'

                                        },
                                        emphasis: {
                                            borderWidth: 0
                                        }
                                    }
                                },
                                {
                                    name: '小米3',
                                    value: 2,
                                    symbol: 'circle',
                                    symbolSize: 20,
                                    itemStyle: {
                                        normal: {
                                            label: {
                                                position: 'right'
                                            },
                                            color: '#fa6900',
                                            brushType: 'stroke',
                                            borderWidth: 1,
                                            borderColor: '#999966',
                                        },
                                        emphasis: {
                                            borderWidth: 0
                                        }
                                    }
                                }
                            ]
                        },
                        {
                            name: '苹果',
                            symbol: 'image://http://www.viastreaming.com/images/apple_logo2.png',
                            symbolSize: [60, 60],
                            itemStyle: {
                                normal: {
                                    label: {
                                        show: false
                                    }
                                    
                                }
                            },
                            value: 4
                        },
                        {
                            name: '华为',
                            symbol: 'image://http://market.huawei.com/hwgg/logo_cn/download/logo.jpg',
                            symbolSize: [60, 60],
                            itemStyle: {
                                normal: {
                                    label: {
                                        show: false
                                    }
                                    
                                }
                            },
                            value: 2
                        },
                        {
                            name: '联想',
                            symbol: 'image://http://www.lenovo.com.cn/HomeUpload/Home001/6d94ee9a20140714.jpg',
                            symbolSize: [100, 40],
                            itemStyle: {
                                normal: {
                                    label: {
                                        show: false
                                    }
                                    
                                }
                            },
                            value: 2
                        }
                    ]
                }
            ]
        }
    ]
};             
 myChart.setOption(option);
  </script>      
  </body>
</html>

完整demo程序下载


二.根据不同数据源,定制开发tree图

我们从上面的demo程序中知道画树型图重点在于如何描述数据,上面配置参数里的data形式如下

data是一个数组形式,它是用来表示多个数据源,由于我们这里只需要使用一个数据源。所以我们只要提供类似{}结构的一个对象即可。即[{根对象}],我们这里只简单使用了name和children属性来说明问题。

[{name:"根",children:[           
{"name":"子根1",children:[...]},
{"{"name":"子根2",children:[...]}
{"name":"子根3",children:[....]},
]}]
我们从这里不难看出这里是一个递归结构的数据形式。所以重点是把我们定义的数据源能够转化成这样的一种形式。
我们对数据源进行分层,即建立父子关系。

数据源形式可以如下

     var zNodes=[
    {id:1,pId:0,name:"董事长"},
    {id:11,pId:1,name:"经理"},
    {id:12,pId:1,name:"副总"},
    {id:13,pId:1,name:"秘书"},
    {id:16,pId:11,name:"财务经理"},
    {id:27,pId:11,name:"人事经理"},
    {id:18,pId:12,name:"HR"},
]
1.建立每个节点到对应子节点列表的映射,即groups对象结构,里面存放着每个节点id和对应子节点的映射

groups={}
for(var i=0;i<zNodes.length;i++){
var pid=zNodes[i]['pId']
//如果该pid对应组不存在
if(!groups[pid])
groups[pid]=[]
//添加子节点
groups[pid].push(zNodes[i])
}
2.从根节点开始构建tree树需要的数据结构,这里是一个递归函数的应用,递归函数的三个重要的点在于结束条件,向下传递的表达式,向上返回的表达式。即结束条件和递归表达式。递归其实是将一个大问题分解成若干相似的小问题来解决。我思考这个问题时从以下2个点进行考虑:

1)结束条件以及此时返回的值。

如果某节点下不存在子节点则返回,不在继续递归下去。此时返回该节点的信息

2)抽象程序的流程。

其实针对这类树问题,我们可以将其变成树和子树的关系来考虑,其实就是构建根节点下的各个子树的数据,而子树的结构同样也是构建以该子树为跟的子树的结构。这里其实就是一个树的递归的定义过程。

描述如下:

//以根节点id为入口

function rescusive(number){
//根节点
var node={}
//存放子树
var data=[]
childrenList=groups[number]
//如果不存在子节点,这里其实就是结束条件
if(!childenList||childrenList.length==0){
node['name']=number;
node['children']=[]
return node;
}
for(var i=0;i<childrenList.length;i++){
//递归该节点下的子树来建构该子树
var children=rescusive(childrenList[i]["id"])
//将该子树加入根节点中
data.push(children)
}
node['name']=number
//根节点中的子树集合
node['children']=data
return node
}

3.构建tree数据

下面我们通过整合以上代码,通过面向对象编程的思想进行完成构建该对象

1)TreeGraph.js文件内容如下:

function treeMenu(a){
    //列表map形式
    this.tree=a||[];
    this.groups={};
	//存放id与对应的name映射
	this.nameMap={}
	//得到每个点对应的层次,为了后期进行布局
	this.levelMap={}
	//样式设计
	this.style={"symbolSize":[60,50,40,30,20],"value":[8,6,4,2,1]}
};
treeMenu.prototype={
    init:function(pid){
        this.group();
		this.MapNamebyId();
		this.setIdLevel(pid);
        return this.rescusive(pid);
    },
    group:function(){
        for(var i=0;i<this.tree.length;i++){
            //存在该grops则直接添加
            if(this.groups[this.tree[i].pId]){
                this.groups[this.tree[i].pId].push(this.tree[i]);
            }else{
                this.groups[this.tree[i].pId]=[];
                this.groups[this.tree[i].pId].push(this.tree[i]);
            }
        }
    },
	//得到每个点的层次
	setIdLevel:function(pid){
		var level=1;
		this.levelMap[pid]=level;
		var gs=this.groups[pid];
		//str=JSON.stringify(gs)
		//alert("json:"+str)
		var temp=[]
		while(gs){
			level++;
			if(gs==null||gs==undefined||gs.length==0)
				break;
			temp=[]
			for(var i=0;i<gs.length;i++){
				var myid=gs[i]["id"];
				this.levelMap[myid]=level;
				subgs=this.groups[myid];
				if(subgs instanceof Array &&subgs!=null){
				for(var j=0;j<subgs.length;j++){
				temp.push(subgs[j]);
				}
				}
			}
			gs=temp;
		}
		
	},
	//根据所在层次设计不同大小的样式
	getStyleById:function(id){
		var level=this.levelMap[id]
		if(level>=5)
			level=5;
		var symbolize=0
		var value=0
		symbolize=this.style['symbolSize'][level-1]
		value=this.style['value'][level-1]
		var styleValue={}
		styleValue['symbolSize']=symbolize
		styleValue['value']=value
		return styleValue
	},
    MapNamebyId:function(){
		for(var i=0;i<this.tree.length;i++){
			map=this.tree[i]
			this.nameMap[map["id"]]=map["name"]
		}
	},
	//设置节点属性
	setNode:function(node,name,symbolize,value,children){
		    node['name']=name;
			node['symbolSize']=symbolize;
			node['value']=value
			node['children']=children
			return node;
	},
	rescusive:function (number){//这里是构建数据源的重点
		var data=[]
		var node={}
		var styleValue={}
		//某个节点下的子节点
		var a=this.groups[number];
		var nodeName=this.nameMap[number];
		if(a==null||a==undefined){
			styleValue=this.getStyleById(number)
			//设置节点
			this.setNode(node,nodeName,styleValue['symbolSize'],styleValue['value'],[])
			return node;
		}
		for(var i=0;i<a.length;i++){
			children=this.rescusive(a[i].id);
			data.push(children);
		}
		styleValue=this.getStyleById(number)
		this.setNode(node,nodeName,styleValue['symbolSize'],styleValue['value'],data)
		return node;
	},
	//创建组织结构图
	createTreeVisual:function(myChart,title,data){
		var option = {
        title : {
        text: title
       },
        tooltip : {
        trigger: 'item',
        formatter: "{b}"
        },
      toolbox: {
        show : true,
        feature : {
            saveAsImage : {show: true}
         }
      },
      calculable : false,
       series : [
         {
            name:'树图',
            type:'tree',
            orient: 'horizontal',  // vertical horizontal
            rootLocation: {x: 100, y: '60%'}, // 根节点位置  {x: 'center',y: 10}
            nodePadding: 20,
            symbol: 'circle',
            data:data
        }]//series
	}	
     myChart.setOption(option);
	}
}
//得到数据
function getData(zNodes){
	var mytree=new treeMenu(zNodes)
	treeData=mytree.init(0)
	data=[]
	data.push(treeData)
	return data;
	//str=JSON.stringify(menu);
	//alert("responsing json:"+str)
}
function createTreeV(mychart,title,znodes){
	var mytree=new treeMenu(znodes)
	treeData=mytree.init(1)
	data=[]
	data.push(treeData)
	mytree.createTreeVisual(myChart,title,data)
}


2) html页面代码如下:

<html>
<head>
  <meta charset="UTF-8">
<title>社交网络</title>
</style>

   <script src="echarts-2.x.js"></script>
    <script src="TreeGraph.js"></script>
  
   </head>
  <body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
   <div style="padding:20px;width:100%;height:100%;"> 

        <!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
               <div id="main" style="width: 1104px;height:464px;">
                 
               </div>
           
      <div id='main_1' style="position: relative;height:15px;width: 100%;color:#A52A2A"></div>
          
 </div>
    <script type="text/javascript">
   //data
    //data=createDatabyHand()
	var zNodes=[
    {id:1,pId:0,name:"董事长"},
    {id:11,pId:1,name:"经理"},
    {id:12,pId:1,name:"副总"},
    {id:13,pId:1,name:"秘书"},
    {id:16,pId:11,name:"财务经理"},
    {id:27,pId:11,name:"人事经理"},
    {id:18,pId:12,name:"HR"},
    ]
	data=getData(zNodes)
    var myChart = echarts.init(document.getElementById('main'), 'macarons');
	createTreeV(myChart,"人事架构图",zNodes)
   
  </script>      
  </body>
</html>
3)页面效果如下:


4)完整代码及echart.js下载见可视化树图完整代码

三 .总结

基础知识很重要,之前对于递归虽然有所了解,但是理解不深。通过这次实践加深了对递归的理解和应用。关于echarts可视化这块,重点学习如何插入数据源和修改样式。


版权声明:本文为xqhadoop原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。