免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
D3.js畫思維導(dǎo)圖(轉(zhuǎn))

思維導(dǎo)圖的節(jié)點具有層級關(guān)系和隸屬關(guān)系,很像枝葉從樹干伸展開來的形狀。在前面講解布局的時候,提到有五個布局是由層級布局擴展來的,其中的樹狀圖(tree layout)和集群圖(cluster layout)布局制作出來的圖具有“樹形”。因此,可以憑借這兩種布局來制作思維導(dǎo)圖。

1. 構(gòu)造思路

樹狀圖布局,將一個具有層級關(guān)系的對象root轉(zhuǎn)換成節(jié)點數(shù)組nodes時,情況如下。有一個root對象:

{      name: "node1",      children:   [              { name: "node2" },              { name: "node3" }      ]  }  

經(jīng)樹狀圖布局轉(zhuǎn)換后,得到的節(jié)點數(shù)組nodes如下:

[  {          name: "node1",          children:           [              { name: "node2" },              { name: "node3" }          ]      },      { name: "node2" },      { name: "node3" }  ]  

下圖是上述節(jié)點數(shù)組的示意圖。由于 node1 具有子節(jié)點,可作為開關(guān)使用,點擊 node1 才會展現(xiàn) node2 和 node3。

問題是:怎樣制作一個“開關(guān)”,使得點擊樹狀圖中的某個節(jié)點時,樹狀圖更新并顯示出被點擊節(jié)點的子節(jié)點。

我們知道,樹狀圖的層級關(guān)系是由每一個對象的children屬性決定的(當(dāng)然,也可以通過tree.children()修改這一點),也就是說,如果某一個節(jié)點的children值為空,則再次用布局計算時,其子節(jié)點就不會進入節(jié)點數(shù)組nodes了。例如,將root改為:

{      name: "node1",      children: null  }  

則得到的節(jié)點數(shù)組nodes里將沒有node2和node3節(jié)點。也就是說,“開關(guān)”只要將被點擊節(jié)點的children設(shè)置為null即可。但是,由于將來可能還要用到children節(jié)點,可設(shè)一臨時變量_children保存此值,例如:

{      name: "node1",      children: null         _children:       /* 臨時變量 */         [              { name: "node2" },              { name: "node3" }      ]    }  

樹狀圖布局不會認為_children是保存子節(jié)點的變量,只把它看做是一般的變量而保存下來,因此節(jié)點數(shù)組nodes里只有一個節(jié)點。根據(jù)上面的思路,寫一個開關(guān)切換函數(shù)如下。

//切換開關(guān),d 為被點擊的節(jié)點  function toggle(d){    if(d.children){  //如果有子節(jié)點          d._children = d.children; //將該子節(jié)點保存到 _children          d.children = null;  //將子節(jié)點設(shè)置為null        }else{  //如果沒有子節(jié)點          d.children = d._children; //從 _children 取回原來的子節(jié)點           d._children = null; //將 _children 設(shè)置為 null      }  }  

每次開關(guān)狀態(tài)切換時,都要重新調(diào)用布局重新計算節(jié)點的位置,也就是說,要有一個重繪函數(shù)能夠處理數(shù)據(jù)發(fā)生更新的情況。這就又要用到【選擇集與數(shù)據(jù) - 第 5 章】的處理模板,重繪函數(shù)的部分代碼如下,尤其要注意開關(guān)函數(shù)是如何被使用的。

//重繪函數(shù)   function redraw(source){        //重新計算節(jié)點和連線      var nodes = tree.nodes(root);      var links = tree.links(nodes);    //獲取節(jié)點的update部分      var nodeUpdate = svg.selectAll(".node")                          .data(nodes, function(d){ return d.name; });        //獲取節(jié)點的enter部分      var nodeEnter = nodeUpdate.enter();    //在給enter部分添加新的節(jié)點時,添加監(jiān)聽器,應(yīng)用開關(guān)切換函數(shù)  nodeEnter.append("g")             .on("click", function(d) {   toggle(d);   redraw(d);   });    /***************         省略 ***************/  }  

每一個被新添加的節(jié)點,都會響應(yīng)click事件。當(dāng)某個節(jié)點被點擊時,如果它具有子節(jié)點,則在開關(guān)切換函數(shù)的作用下,root對象被修改了,然后調(diào)用重繪函數(shù)后,新的樹狀圖將被繪制。如此一來,樹狀圖具有開關(guān)功能,也就可以當(dāng)做思維導(dǎo)圖使用了。

2. 制作思維導(dǎo)圖

首先,要有一個具有層級關(guān)系的 JSON 文件,本文使用:learn.json

{"name":"如何學(xué)習(xí)D3","children":[    {       "name":"預(yù)備知識" ,         "children":        [                {"name":"HTML & CSS" },                {"name":"JavaScript" },                {"name":"DOM" },                {"name":"SVG" }        ]       },          {         "name":"安裝" ,         "children":        [            {                "name":"記事本軟件",                "children":                [                    {"name":"Notepad++"},                    {"name":"EditPlus"},                    {"name":"Sublime Text"}                ]            },            {                "name":"服務(wù)器軟件",                "children":                [                    {"name":"Apache Http Server"},                    {"name":"Tomcat"}                ]            },            {"name":"下載D3.js"}        ]     },        {         "name":"入門",        "children":        [            {                "name":"選擇集",                "children":                [                    {"name":"select"},                    {"name":"selectAll"}                ]            },            {                "name":"綁定數(shù)據(jù)",                "children":                [                    {"name":"datum"},                    {"name":"data"}                ]            },            {"name":"添加刪除元素"},            {                "name":"簡單圖形",                "children":                [                    {"name":"柱形圖"},                    {"name":"折線圖"},                    {"name":"散點圖"}                ]            },            {"name":"比例尺"},            {"name":"生成器"},            {"name":"過渡"}        ]     },        {         "name":"進階" ,         "children":        [            {                "name":"布局的應(yīng)用",                "children":                [                    {"name":"餅狀圖"},                    {"name":"樹狀圖"},                    {"name":"矩陣樹圖"}                ]            },            {"name":"地圖"}        ]    }]}

其次,依次創(chuàng)建樹狀圖布局、對角線生成器等,用于繪制樹狀圖。

然后,實現(xiàn)最關(guān)鍵的重繪函數(shù),函數(shù)聲明如下:

function redraw(source)

只有一個參數(shù)source,這是被點擊的節(jié)點,如果該節(jié)點原來為閉合狀態(tài),點擊后其子節(jié)點將顯現(xiàn),如果原來為打開狀態(tài),點擊后其子節(jié)點將隱藏。函數(shù)體的實現(xiàn),分為四個步驟:

2.1 調(diào)用布局,計算節(jié)點和連線數(shù)組

樹狀圖布局的tree.nodes()返回節(jié)點數(shù)組,tree.links()返回連線數(shù)組。其中,對節(jié)點的y坐標(biāo)重新計算,使其只與節(jié)點的深度有關(guān),由于后期繪制節(jié)點和連線時要將x和y坐標(biāo)對調(diào),因此這里重計算的實際上是水平方向的坐標(biāo)。

//應(yīng)用布局,計算節(jié)點和連線  var nodes = tree.nodes(root);  var links = tree.links(nodes);    //重新計算節(jié)點的y坐標(biāo)  nodes.forEach(function(d) { d.y = d.depth * 180; });

之所以重新計算y坐標(biāo),是為了當(dāng)數(shù)據(jù)更新(用于點擊節(jié)點)時,保證樹狀圖的結(jié)構(gòu)不要發(fā)生太大的變化,如此看起來比較自然。

2.2 分別處理節(jié)點的update、enter、exit三部分

在svg里選擇當(dāng)前所有的節(jié)點,使其與節(jié)點數(shù)組nodes綁定,綁定時要設(shè)定一個鍵函數(shù)。鍵函數(shù)里直接返回d.name,當(dāng)節(jié)點數(shù)組發(fā)生更新時,新節(jié)點要與舊節(jié)點在名稱上相對應(yīng)。

//獲取節(jié)點的update部分  var nodeUpdate = svg.selectAll(".node")                 .data(nodes, function(d){ return d.name; });    //獲取節(jié)點的enter部分  var nodeEnter = nodeUpdate.enter();    //獲取節(jié)點的exit部分  var nodeExit = nodeUpdate.exit(); 

先處理enter部分,即添加節(jié)點。節(jié)點的構(gòu)成為:分組元素里有一個圓表示節(jié)點,還有一個文字元素表示節(jié)點的名稱。元素結(jié)構(gòu)如下:

本例中,每一個新添加的節(jié)點都將緩慢地過渡到自己本身的位置,如此更具有友好性。因此,新節(jié)點的初始位置都設(shè)定在source節(jié)點處,確切的說是重回之前source節(jié)點的位置,該坐標(biāo)是保存在source.x0和source.y0里的。另外,對于每一個新節(jié)點,設(shè)置的半徑為0,設(shè)置為完全透明,接下來在處理update部分的時候會將這些新節(jié)點過渡到正常狀態(tài)的。下圖展示了處理enter部分和update部分時如何節(jié)點的位置時如何確定和過渡的。

處理enter部分的代碼如下。

//1. 節(jié)點的 Enter 部分的處理辦法  var enterNodes = nodeEnter.append("g")         .attr("class","node")         .attr("transform", function(d) {   return "translate(" + source.y0 + "," + source.x0 + ")";   })         .on("click", function(d) {   toggle(d);   redraw(d);   });    //省略添加圓和文字部分  

然后處理update部分,將所有節(jié)點(包括在enter部分新添加的節(jié)點)都緩緩過渡到新的位置。由于新的節(jié)點數(shù)組是與節(jié)點選擇集綁定在一起的,因此d.x和d.y里保存的就是新的坐標(biāo)值。

//2. 節(jié)點的 Update 部分的處理辦法  var updateNodes = nodeUpdate.transition()                 .duration(500)                 .attr("transform", function(d) {   return "translate(" + d.y + "," + d.x + ")";   }); 

最后處理exit部分,需要刪除的節(jié)點的位置緩緩過渡到其父節(jié)點處。

//3. 節(jié)點的 Exit 部分的處理辦法  var exitNodes = nodeExit.transition()   .duration(500)  .attr("transform", function(d) {   return "translate(" + source.y + "," + source.x + ")";   })   .remove();  

2.3 分別處理連線的update、enter、exit三部分

在svg中選擇所有的連線,綁定連線數(shù)組links,由此可獲得連線的update、enter、exit部分。

//獲取連線的update部分  var linkUpdate = svg.selectAll(".link")           .data(links, function(d){ return d.target.name; });    //獲取連線的enter部分  var linkEnter = linkUpdate.enter();    //獲取連線的exit部分  var linkExit = linkUpdate.exit(); 

對于連線的enter部分,是插入路徑元素path,路徑由對角線生成器獲取,對角線的起點和終點坐標(biāo)都是(source.x0, source.y0)。

對于連線的update部分,將所有的連線的位置(對角線的起點和終點)更新到新的位置,即目前綁定的數(shù)組links里保存的位置。

對于連線的exit部分,令其緩緩過渡到當(dāng)前的source點,再移除。

//1. 連線的 Enter 部分的處理辦法  linkEnter.insert("path",".node")            .attr("class", "link")            .attr("d", function(d) {                var o = {x: source.x0, y: source.y0};                return diagonal({source: o, target: o});            })            .transition()            .duration(500)            .attr("d", diagonal);     //2. 連線的 Update 部分的處理辦法   linkUpdate.transition()          .duration(500)          .attr("d", diagonal);     //3. 連線的 Exit 部分的處理辦法   linkExit.transition()            .duration(500)            .attr("d", function(d) {              var o = {x: source.x, y: source.y};              return diagonal({source: o, target: o});            })            .remove();  

2.4 保存當(dāng)前的節(jié)點坐標(biāo)

當(dāng)用戶點擊節(jié)點后,數(shù)據(jù)發(fā)生更新,即每個節(jié)點的坐標(biāo)要發(fā)生更新。但是,在對節(jié)點和連線進行過渡操作的時候,需要使用到更新前的數(shù)據(jù)(source.x0和source.y0)。因此,每一次調(diào)用重繪函數(shù),都要將當(dāng)前節(jié)點的位置保存下來。

nodes.forEach(function(d) {        d.x0 = d.x;        d.y0 = d.y;  }); 

x和y坐標(biāo)分別保存在x0和y0中,在調(diào)用redraw(source)時,被點擊的節(jié)點被作為參數(shù)傳到了重繪函數(shù)里,因此source.x0和source.y0里保存的是被點擊之前節(jié)點的坐標(biāo)。

3. 結(jié)果

結(jié)果如下圖所示,點擊節(jié)點可以展開子節(jié)點。

源代碼請單擊以下鏈接,郵件查看源代碼:

http://www.ourd3js.com/demo/G-10.0/mind.html

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
jQuery EasyUI 樹形菜單 – 樹形菜單加載父/子節(jié)點 | w3cschool菜鳥教程
可視化工具D3.js教程 入門 (第十三章)—— 樹狀圖
好看的?;鶊D是如何煉成的!
d3js force layout 節(jié)點描述性文字居中顯示
JQuery EasyUI TreeGrid控件的使用
科學(xué)網(wǎng)—復(fù)雜網(wǎng)絡(luò)分析庫NetworkX學(xué)習(xí)筆記(3):網(wǎng)絡(luò)演化模型
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服