利用highcharts繪製樹形結構圖

highcharts不只能夠繪製官網上面指定的報表,同時,還能夠利用其封裝好的繪圖庫來繪製自定義圖形。css

有朋友在工做中恰好有這樣的需求,當時看了兩個相似的js繪圖庫:node

highcharts重在報表,可是同時提供了封裝好的繪圖庫,屏蔽了瀏覽器間差別(IE8及如下不支持SVG,使用VML繪圖)web

Raphaël僅僅提供了各式各樣的繪圖的API,也很是的好用。瀏覽器

僅僅實現當前功能的話,Raphaël應該是首選,可是,咱們作web應用的時候,項目中不免用到其餘的報表樣式,因此權衡之下,仍是選擇highcharts比較划算。數據結構

先把效果圖貼上,比較好描述問題:ide

1. 首先,咱們定義一組這樣的樹形結構,你們學過數據結構的,應該很容易使用相似鏈表的結構進行描述。函數

2. 關於怎麼添加節點之類的就很少說了,主要說一下,畫圖須要知道繪製圖形的位置,而這個位置須要根據節點來進行計算。this

3. 計算位置的時候,採用遞歸的方式來進行計算,當前節點的位置始終位於,其子節點的的中間偏上的位置,因此須要一個獲取子節點左邊位置和一個獲取右邊位置的函數,此函數會遞歸調用。和子節點之間的高度則由一個常數來進行定義。spa

4. 繪製圖形,經過第三步能夠計算出每一個節點對應的位置,那麼就能夠進行繪圖了,首先是節點圖形,這個相對簡單。其次是父子節點之間的連線。每條線均使用3次貝澤爾曲線來繪製。須要提供3個點,共6個參數。恰好這6個參數能夠由父節點的位置和子節點的位置經過組合獲得。.net

具體代碼以下所示:(也能夠經過http://jsfiddle.net/lloydzhou/JY59J/5/ 在線查看)

定義節點類
 1 var Node = {
 2     height: 20,
 3     width: 60,
 4     padding: 30,
 5     paddingTop: 50,
 6     paddingText: 5,
 7     paddingLeft: 20,
 8     arrowLength: 4,
 9     arrowWidth: 3,
10     create: function(textVal){
11         return {
12             text: textVal,
13             childNodes: [],
14             parentNode: null,
15             index: null,
16             x: null,
17             y: null,
18             add: function(node) {
19                 this.childNodes[node.index = this.childNodes.length] = node;
20                 return node.parentNode = this;
21             },
22             leftNode: function() {
23                 return this.parentNode ? (this.index > 0 ? this.parentNode.childNodes[this.index - 1] : this.parentNode.leftNode()) : null;
24             },
25             top: function() {
26                 if (this.y) return this.y;
27                 else return this.y = (this.parentNode ? this.parentNode.top() + Node.height + Node.padding : Node.paddingTop);
28             },
29             left: function() {
30                 if (this.x) {
31                     return this.x;
32                 }else{
33                     return this.x = this.leftNode() ? this.leftNode().left() + Node.padding + this.leftNode().childWidth() : Node.paddingLeft;
34                 }
35             },
36             childHeight: function() {
37                 var h = 0;if (this.childNodes.length > 0) {for(var i=0;i<this.childNodes.length;i++) h = Math.max(h,this.childNodes[i].childHeight() + Node.padding);}
38                 return (h === 0) ? Node.height : h ;
39             },
40             childWidth: function() {
41                 var w = 0;if (this.childNodes.length > 0) {for(var i=0;i<this.childNodes.length;i++) w = w + this.childNodes[i].childWidth() + Node.padding;}
42                 return (w === 0) ? Node.width : w - Node.padding;
43             },
44             toString: function() {
45                 return this.text + '[' + this.left() + ',' + this.top() + ']' + (this.childNodes.length > 0 ? ':{' + this.childNodes + '}' : '');
46             },
47             arrowX: function () {
48                 return this.left() + this.childWidth() / 2 - (this.parentNode.left() + this.parentNode.childWidth() / 2 - Node.width / 2) - Node.width / 2;
49             },
50             arrowY: function () {
51                 return Node.padding - 2 * Node.paddingText;
52             },
53             arrow: function(renderer, colors) {
54                 var a = Node.arrowLength, b = Node.arrowWidth, x2 = this.arrowX(), y2 = this.arrowY(),
55                     x = this.parentNode.left() + this.parentNode.childWidth() / 2 - Node.width / 2+Node.width/2 + Node.paddingText,
56                     y = this.parentNode.top() + Node.height + 2 * Node.paddingText
57                 renderer.path(['M', 0, 0, 'C', 0, y2/1.8, x2, 0, x2, y2]).attr({'stroke-width': 2, stroke: colors[1]}).translate(x,y).add()
58             },
59             drow: function(renderer, colors) {
60                 var x = this.left() + this.childWidth() / 2 - Node.width / 2, y = this.top();
61                 renderer.label(this.text, x, y).attr({fill: colors[0], stroke: 'white','stroke-width': 3,padding: Node.paddingText, r: 2 * Node.paddingText, width: Node.width, height: Node.height}).css({color: 'white', textAlign:'center',fontWeight: 'bold',fontSize: '10px'}).add().shadow(true);
62                 if (this.childNodes.length > 0) {
63                     for(var i=0;i<this.childNodes.length;i++) {
64                         this.childNodes[i].drow(renderer, colors);
65                         this.childNodes[i].arrow(renderer, colors);
66                     }
67                 }
68             }
69         };
70     }
71 }

1 var n = Node.create
2 
3 var datas = n(1)
4     .add(n(2))
5     .add(n(3).add(n(7)).add(n(8)))
6     .add(n(4))
7     .add(n(5).add(n(6)).add(n(9)))
生成節點
1     var chart = new Highcharts.Chart({
2         chart: {
3             renderTo: 'container',
4             events: {load: function () { 
5                 datas.drow(this.renderer, Highcharts.getOptions().colors);
6             }}
7         },
8         title: {text: 'demo'}
9     });
繪製圖形
相關文章
相關標籤/搜索