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>
二.根据不同数据源,定制开发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"},
- ]
- 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])
- }
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;
- },
- <span style="color:#ff0000;">rescusive:function (number){//这里是构建数据源的重点</span>
- 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)
- }
- <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>
4)完整代码及echart.js下载见可视化树图完整代码
三 .总结
基础知识很重要,之前对于递归虽然有所了解,但是理解不深。通过这次实践加深了对递归的理解和应用。关于echarts可视化这块,重点学习如何插入数据源和修改样式。