1. 程式人生 > >利用Javascript框架——D3.js製作力導向關係圖普

利用Javascript框架——D3.js製作力導向關係圖普

因公司業務需求,整理製作了一個實用且酷炫力導向關係圖。下面是我自己的一個demo。先Po一下成品圖(自己做的資料偏少):

圖1:
這裡寫圖片描述

1)、引入D3框架,這裡引入的版本是v3.0

圖2:
這裡寫圖片描述

2)、資料整理(資料結構如下圖)

圖3:

這裡寫圖片描述

圖3:

這裡寫圖片描述

資料解析:資料準備是很重要的一部分。Jstr由兩個部分組成:‘nodes’、‘links’,主要資料為‘nodes’,‘links’表示資料之間的聯絡。‘nodes’部分每條資料由‘name’、‘group’、‘index’組成,可大致理解為按‘group’分組(圖一中橘黃色的圓圈為一組、紫色的為一組、藍色的為一組),‘index’表示此資料的唯一標識。‘links’部分每條資料由‘source’、‘target’組成,‘source’表示源頭,‘target’表示指向的目標。如圖1中‘中國’指向‘四川’這條線,中國為源頭,所以source’為‘nodes’中‘中國’的index即0,target為‘四川’的的index,即3。

3)下面附上程式碼並做詳細講解

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>D3製作力導向關係圖</title>
</head>
<body>
<div class="container" id="main_2"></div>
<script type='text/javascript' src
='js/jquery-3.1.1.min.js'>
</script> <script src="js/d3.v3.min.js"></script> <script type="text/javascript"> var index = 0; var width = 1140, height = 1000; var color = ["#FF8000", "#9393FF", "#0080FF"]; var force = d3.layout.force()/*layout將json格式轉化為力學圖可用的格式*/ .linkDistance(80
)/*指定結點連線線的距離,預設為20*/ .charge(-600)/*頂點的電荷數。該引數決定是排斥還是吸引,數值越小越互相排斥*/ .size([width, height]);/*作用域*/ var svg; $(document).ready(function () { var jstr = { "nodes": [ {"name": "中國", "group": 1, "index": 0}, {"name": "內蒙古", "group": 2, "index": 1}, {"name": "貓咪", "group": 3, "index": 2}, {"name": "四川", "group": 2, "index": 3}, {"name": "棕熊", "group": 2, "index": 4}, {"name": "臭豆腐", "group": 3, "index": 5}, {"name": "小豬豬", "group": 2, "index": 6}, {"name": "湖南", "group": 2, "index": 7}, {"name": "大熊貓", "group": 3, "index": 8}, {"name": "北京", "group": 2, "index": 9}, {"name": "霧霾", "group": 3, "index": 10} ], "links": [{"source": 0, "target": 1}, {"source": 1, "target": 2}, {"source": 0, "target": 3}, {"source": 3, "target": 8}, {"source": 0, "target": 4}, {"source": 0, "target": 6}, {"source": 0, "target": 7}, {"source": 7, "target": 5}, {"source": 0, "target": 9}, {"source": 9, "target": 10}, {"source": 4, "target": 5} ] }; $("#main_2").html(conduct(jstr));/*在$(“#main_2”)作用域內畫圖*/ }); function conduct(graph, link) { var dd = $('<div class="d3strench" id="d3strench"></div>'); $("#main_2").append(dd); /*D3採用SVG來更加生動展現資料,此處設定svg的基本樣式*/ svg = d3.select(".d3strench").append("svg") .attr("width", 1140) .attr("height", height) .attr('border', 'red') .style({ 'margin': '0 auto', 'display': 'block' }); var nodes = graph.nodes.slice(), /*nodes() 裡傳入頂點的陣列*/ links = [], bilinks = []; /*將資料組裝成source-->target的形式*/ graph.links.forEach(function (link) { var s = nodes[link.source], t = nodes[link.target], i = {}; // 中間節點 nodes.push(i); links.push({source: s, target: i}, {source: i, target: t}); bilinks.push([s, i, t]); }); //nodes(圖5)

圖5:

這裡寫圖片描述

//links(圖6)

圖6:

這裡寫圖片描述

//blinks(圖7)

圖7:

這裡寫圖片描述

 force.nodes(nodes)
                .links(links)
                .start();
/*svg的path標籤被稱為”可以組成任何形狀的形狀”,所以此處用path標籤來繪製線條*/
        var link = svg.selectAll(".link")//線條
                .data(bilinks)
                .enter().append("path")
                .attr("class", "link")
                .attr("stroke", function (d) {
                    return color[d[0].group - 1];
                })
                .attr("stroke-width", 1)
/*接下來是資料的渲染*/

圖8:

這裡寫圖片描述

圖9(一個g標籤包裹的內容將被渲染成一個圓圈組):

這裡寫圖片描述

 var node = svg.selectAll(".node")
                .data(graph.nodes)
                .enter().append("g")
                .attr("class", "node")
                .attr("group", function (d) {
                    return d.group;
                })
                .call(force.drag);
        node.append("circle")
                .attr("r", 8)
                .style("fill", function (d) {
                    return color[d.group - 1];
                })
                .style("stroke", function (d) {
                    return color[d.group - 1];
                })
                .style("stroke-width", "8") //圓外面的輪廓線
                .style("stroke-opacity", "0.6"); //圓外面的輪廓線的透明度
        node.filter(function (d) {
            return d.group !== 0;
        })
                .append("text")
                .attr("font-family", "微軟雅黑")
                .attr("text-anchor", "middle")
                .attr("dy", function () {   //dy表示文字的偏移量
                    return "0em";
                })
                .attr('x', function (d) {
                    d3.select(this).append('tspan')//新增文字
                            .text(function () {
                                return d.name;
                            });
                    d3.selectAll(".node[group='3'] text")//設定圓圈的樣式以及半徑
                            .selectAll("tspan")
                            .attr("fill", "#000");
                    d3.selectAll(".node[group='1'] circle")
                            .attr('r', 40)
                            .style('cursor', 'pointer');
                    d3.selectAll(".node[group='2'] circle")
                            .attr('r', 25);
                    d3.selectAll(".node[group='3'] circle")
                            .attr('r', 30);
                });
        node.append("title")//為每個節點設定title(類似於html標籤的title屬性)
                .text(function (d) {
                    return d.name;
                });
        /*拖拽事件*/
        force.on("tick", function () {
            link.attr("d", function (d) {//設定線條的偏移以及路徑
                var dx = d[2].x - d[0].x,
                        dy = d[2].y - d[0].y,
                        dr = Math.sqrt(dx * dx + dy * dy);
                /*下面表示位置的菜蔬中, M(表示畫筆落下的位置), A(畫橢圓)是大寫的,表示絕對位置。當使用相對位置時,要小寫*/
                return "M" + d[0].x + "," + d[0].y + "A" + dr + "," + dr + " 0 0,0 " + d[2].x + "," + d[2].y;
            }).attr("fill", "transparent");
            node.attr("transform", function (d) {//circle節點的偏移量
                return "translate(" + d.x + "," + d.y + ")";
            });
        });
        force.stop();
        force.start();
    }
</script>
</body>
</html>

D3.js作為資料可視的一個庫,可將資料生動化,但相對於echart等來說,難度稍大稍複雜。上面的案例也是在網上搜羅了很多知識點才繪製出來的,如果有什麼不同的看法,或者有什麼不對的地方,請大家指出評論!