Web 前端开发

d3.js主要布局种类总结

2020-02-13  本文已影响0人  stayhungry_e89f

(本文在较早之前在本人知乎账号为“BOOM”的数据可视化专栏发表过:知乎链接,所以也可到本人知乎上的文章分享查看更多文章)

(本文章代码来自网络与《D3API详解》这本书,收集做学习交流之用)

说明:本文实用d3.js版本为v3。

1、捆绑布局

1.1、简介:

捆绑布局根据结点数据输入确定结点的父子关系,再根据边数据输入确定结点之间的边怎么画,当从一个结点映射出去的连接比较多时看上去像是形成一捆绳,所以叫捆图。适合展示如demo所示各大城市之间高铁连接关系这样的情况。

1.2、demo:

多个城市之间的高铁连接情况:

图1

1.3、代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>捆图</title>
    <style>
        body{
            background-color: #000000;
        }

        .node circle {
            stroke: black;
            stroke-width: 2px;
        }

        .node text{
            font-size: 12px;
            font-family: simsun;
        }

        .link {
            fill: none;
            stroke: white;
            stroke-opacity: .5;
            stroke-width: 8px;
        }

    </style>

</head>
<body>
<script src="../../d3.js"></script>
<script>

    var width  = 1370;  //SVG绘制区域的宽度
    var height = 670;   //SVG绘制区域的高度

    var svg = d3.select("body")         //选择<body>
            .append("svg")          //在<body>中添加<svg>
            .attr("width", width)   //设定<svg>的宽度属性
            .attr("height", height);//设定<svg>的高度属性

    //1\. 确定初始数据
    var vertex = {
        name: "",
        children:[
            {name: "北京"},{name: "上海"},{name: "杭州"},
            {name: "广州"},{name: "桂林"},{name: "昆明"},
            {name: "成都"},{name: "西安"},{name: "太原"}
        ]
    };

    var edges = [
        {source: "北京", target: "上海"},
        {source: "北京", target: "广州"},
        {source: "北京", target: "杭州"},
        {source: "北京", target: "西安"},
        {source: "北京", target: "成都"},
        {source: "北京", target: "太原"},
        {source: "北京", target: "桂林"},
        {source: "北京", target: "昆明"},
        {source: "北京", target: "成都"},
        {source: "上海", target: "杭州"},
        {source: "昆明", target: "成都"},
        {source: "西安", target: "太原"}
    ];

    var Zoom_data = 400;//这个值可以调节图的大小
    //2\. 转换数据
    var cluster = d3.layout.cluster()
            .size([360, width/2 - Zoom_data])
            .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });

    var bundle = d3.layout.bundle();

    //数据接口
    var nodes = cluster.nodes(vertex);
    var oLinks = map(nodes, edges);

    var links = bundle(oLinks);

    //将links中的source和target由名称替换成节点
    function map( nodes, links ){
        var hash = [];
        for(var i = 0; i < nodes.length; i++){
            hash[nodes[i].name] = nodes[i];
        }
        var resultLinks = [];
        for(var j = 0; j < links.length; j++){
            resultLinks.push({  source: hash[ links[j].source ],
                target: hash[ links[j].target ]
            });
        }
        return resultLinks;
    }

    //3\. 绘图
    var line = d3.svg.line.radial()
            .interpolate("bundle")
            .tension(.85)
            .radius(function(d) { return d.y; })
            .angle(function(d) { return d.x / 180 * Math.PI; });

    gBundle = svg.append("g")
            .attr("transform", "translate(" + (width/2) + "," + (height/2) + ")");

    var color = d3.scale.category20c();

    var link = gBundle.selectAll(".link")
            .data(links)
            .enter()
            .append("path")
            .attr("class", "link")
            .attr("d", line);   //使用线段生成器

    var node = gBundle.selectAll(".node")
            .data( nodes.filter(function(d) { return !d.children; }) )
            .enter()
            .append("g")
            .attr("class", "node")
            .attr("transform", function(d) {
                return "rotate(" + (d.x- 90) + ")translate(" + d.y + ")" + "rotate("+ (90 - d.x) +")";
            });

    node.append("circle")
            .attr("r", 20)
            .style("fill",function(d,i){ return color(i); });

    node.append("text")
            .attr("dy",".2em")
            .style("text-anchor", "middle")
            .text(function(d) { return d.name; });

</script>

</body>
</html>
图2

2、弦布局

2.1、简介:

弦图用来展示一组实体之间的关系,通过在不同的弧线之间画出二次贝塞尔曲线,将实体之间的关系表示在一张弦图中。下面展示了一个弦图,表示五个城市人口互相之间的来源关系,比如北京有2015人来自上海,上海有2060人来自广州。

2.2、demo:

图3

2.3、代码:

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <title>弦图</title>
    <style>
        body{
            background-color: #000000;
        }
    </style>
</head>

<body>
<script src="../../d3.js"></script>
<script>
    var city_name = ["北京","上海","广州","深圳","香港"];
    var population = [
        [1000,3015,4567,1234,3714],
        [3214,2000,2060,124,3234],
        [8761,6545,3000,8045,647],
        [3211,1067,3214,4000,1006],
        [2146,1034,6745,4764,5000]
    ];

    var chord_layout = d3.layout.chord()
            .padding (0.03)//取得或设置弦片段间的角填充,也就是每一个弦片段的间距啦
            .sortSubgroups(d3.descending)
            .matrix(population); // 取得或设置布局需要的关联矩阵数据

    var width = 800,
            height = 670;
    var innerRadius = width/2*0.7,
            outerRadius = innerRadius*1.1;
    var color = d3.scale.category20();

    var svg = d3.select("body").append("svg")
            .attr("width",width)
            .attr("height",height)
            .append("g")
            .attr("transform","translate("+width/2+","+height/2+")");

    var outer_arc = d3.svg.arc()
            .innerRadius(innerRadius)
            .outerRadius(outerRadius);

    var g_outer = svg.append("g");
    g_outer.selectAll("path")
            .data(chord_layout.groups) //返回index(行索引)、subindex(列索引)、startAngle、endAngle、value
            .enter()
            .append("path")
            .style("fill", function (d) {
                return color(d.index)
            }
    )
            .style("stroke", function (d) {
                return color(d.index)
            })
            .attr("d",outer_arc);

    g_outer.selectAll("text")
            .data(chord_layout.groups)
            .enter()
            .append("text")
            .each(function(d,i){
                d.angle = (d.startAngle+ d.endAngle)/2;
                d.name = city_name[i];
            }) //表示对于任何一个绑定的元素,都执行后面的无名函数 function 的代码,这里的代码为: 计算一个角度,赋值给 d.angle ;获取城市的名称。
            .attr("dy",".35em")
            .attr("transform",function(d){
                return "rotate("+(d.angle*180/Math.PI)+")"+"translate(0,"+-1.0*(outerRadius+10)+")"+((d.angle>Math.PI*3/4 && d.angle<Math.PI*5/4)?"rotate(180)":"");
            })//在用 transform 进行位移时,要注意转换的顺序: rotate -> translate,最后一行转换代码表示:当角度在135°到225°之间时,旋转180°。否则下方的文字是倒的,不利于观看。
            .text(function(d){return d.name;})
            .style("stroke","white");

    var inner_chord = d3.svg.chord()
            .radius(innerRadius);

    svg.append("g")
            .attr("class","chord")
            .selectAll("path")
            .data(chord_layout.chords) //返回index(行索引)、subindex(列索引)、startAngle、endAngle、value等参数
            .enter()
            .append("path")
            .attr("d",inner_chord)
            .style("fill", function(d) { return color(d.source.index); })
            .style("opacity",0.5)
            .on("mouseover",function(d,i){
                d3.select(this)
                        .style("fill","white");
            })
            .on("mouseout",function(d,i){
                d3.select(this)
                        .transition()
                        .duration(1000)
                        .style("fill",color(d.source.index))
            })
</script>
</body>
</html>
图4

3、树布局

3.1、简介:

树布局能够用莱茵戈尔德-蒂尔福德算法产生一个整洁的树状节点-连接图,下面使用了一个国家名,省份名与市名的从属关系树状图展示效果。

3.2、demo:

图5

3.3、代码:

<html>  
  <head>  
        <meta charset="utf-8">  
        <title>树状图</title>  
<style>
body{
    background-color: #000000;
}

.node circle {
  fill: #fff;
  stroke: steelblue;
  stroke-width: 2px;
}

.node {
  font: 16px sans-serif;
}

.link {
  fill: none;
  stroke: white;
  stroke-width: 3.5px;
    opacity: 0.5;
}

</style>
  </head> 
<body>
<script src="../../d3.js"></script>
<script>

var width = 680,
height = 670;

var tree = d3.layout.tree()
    .size([width, height-200])
    .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2); });

var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.y, d.x]; });

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(40,0)");

d3.json("city_tree.json", function(error, root) {

    var nodes = tree.nodes(root);
    var links = tree.links(nodes);

    var link = svg.selectAll(".link")
      .data(links)
      .enter()
      .append("path")
      .attr("class", "link")
      .attr("d", diagonal);

    var node = svg.selectAll(".node")
      .data(nodes)
      .enter()
      .append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });

    node.append("circle")
      .attr("r", 4.5);

    node.append("text")
      .attr("dx", function(d) { return d.children ? -8 : 8; })
      .attr("dy", 3)
      .style("text-anchor", function(d) { return d.children ? "end" : "start"; })
            .style("stroke","yellow")
      .text(function(d) { return d.name; });
    });

</script>

    </body>  
</html>  
/*数据文件city_tree.json*/
{
"name":"中国",
"children":
[
    { 
      "name":"浙江" , 
      "children":
      [
            {"name":"杭州" },
            {"name":"宁波" },
            {"name":"温州" },
            {"name":"绍兴" }
      ] 
    },

    { 
        "name":"广西" , 
        "children":
        [
            {
            "name":"桂林",
            "children":
            [
                {"name":"秀峰区"},
                {"name":"叠彩区"},
                {"name":"象山区"},
                {"name":"七星区"}
            ]
            },
            {"name":"南宁"},
            {"name":"柳州"},
            {"name":"防城港"}
        ] 
    },

    { 
        "name":"黑龙江",
        "children":
        [
            {"name":"哈尔滨"},
            {"name":"齐齐哈尔"},
            {"name":"牡丹江"},
            {"name":"大庆"}
        ] 
    },

    { 
        "name":"新疆" , 
        "children":
        [
            {"name":"乌鲁木齐"},
            {"name":"克拉玛依"},
            {"name":"吐鲁番"},
            {"name":"哈密"}
        ]
    }
]
}
图6

4、力布局

4.1、简介:

力布局使用位置Verlet整合算法实现,适合网络型、社交型图数据的可视化展示。

4.2、demo:

图7

4.3、代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <style>
            .link {
                stroke: #e2e0e1;

                opacity: 0.5;
            }

            .node text {
                pointer-events: auto;
                font: 10px sans-serif;
                color:white;
                opacity: 0.0;
            }

            #Table{
                color:white;
            }
            p,b{
                color:white;
            }
        </style>
    </head>
    <body bgcolor="black">
    <script src="d3.v3.min.js"></script>
    <script>

    var width = 1450,height = 800;
    var radius = 15;

    var colors = d3.scale.category20();
    var rscale = d3.scale.linear()
            .domain([1,30])
            .range([3,15]);

    var color = d3.scale.category20();
    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height)
        /*.call(
            d3.behavior.zoom()
                    .scaleExtent([1,20])
                    .on("zoom",zoom)
    )*/
            .append("g");
        //zoom是定义缩放事件的
    function zoom(){
        svg.attr("transform","translate("+d3.event.translate+")scale("+d3.event.scale+")");
    }

    var force = d3.layout.force()
        .gravity(0.05)
        .distance(90)
        .charge(-80)
        .size([width, height]);

    var label_text_1 = svg.append("text")
            .attr("class","labeltext")
            .attr("x",10)
            .attr("y",16)
            .text("");

    var label_text_2 = svg.append("text")
            .attr("class","labeltext")
            .attr("x",10)
            .attr("y",40)
            .text("");

    d3.json("../haitun - 1000.json", function(error, json) {
        if (error){throw error;}

        force
                .nodes(json.nodes)
                .links(json.links)
                .on("tick", tick)
                .start();

        link = svg.selectAll(".link")
                .data(json.links)
                .enter().append("line")
                .attr("class", "link")
                .attr("id",function(d){
                    return d.value1;
                })
                //.attr("stroke-width","2.5px")
                .attr("stroke","#e2dab8")
                .attr("stroke-width","1.5px");

        /****下面node不加var是为了把node声明为全局变量,让所在函数作用域外的其他函数也能使用该变量**/

        node=svg.selectAll(".node")
                .data(json.nodes)
                .enter().append("g")
                .attr("class", "node")
                .call(force.drag);

        node.append("circle")
                .attr("r",function(d){
                    return rscale(d.number);
                })
                /*.attr("r",8)*/
                .attr("Id",function(d){
                    return d.id;
                })
                .attr("class",function(d){
                    return d.value1
                })
                .attr("stroke","blue")
                .attr("stroke-width",function(d){
                    return 1;
                })
                .style("fill",function(d,i){
                    return color(i);
                });
        var drag = force.drag()
                .on("dragstart", function (d, i) {
                    d.fixed = true;    //拖拽开始后设定被拖拽对象为固定
                    label_text_2.text("");
                })
                .on("dragend", function (d, i) {
                    label_text_2.text("");
                })
                .on("drag", function (d, i) {
                    label_text_2.text("");
                });

        node.append("text")
                .attr("dx", -5)//dx值可以调节text文本相对与圆点circle的位置
                .attr("dy", ".35em")
                .attr("class",function(d){
                    return d.value1
                })
                .attr("Id",function(d){
                    return d.id;
                })
                .attr("val",function(d){
                    return d.value1;
                })
                .text(function (d) {
                    return d.id
                })
                .style("fill","white")
                .on("dblclick", function (d, i) {
                    d.fixed = false;
                })
                .on("mouseover", function (d, i) {
                    d3.select(this)
                            .style("opacity","0.0");})
                .on("mouseout", function (d, i) {
                    d3.select(this)
                            .style("opacity","0.0");})
                .call(drag);

        /*force.on("tick", function () {*/
        function tick(){
            link.attr("x1", function (d) {
                return d.source.x;
            })
                    .attr("y1", function (d) {
                        return d.source.y;
                    })
                    .attr("x2", function (d) {
                        return d.target.x;
                    })
                    .attr("y2", function (d) {
                        return d.target.y;
                    });

            node.attr("transform", function (d) {
                return "translate(" + d.x + "," + d.y + ")";
            });
            }
});
图8

数据文件过大,所以我只列出结点数据和边数据格式截图:

结点:

图9

边:

图10

5、包布局

5.1、简介:

包图采用包含(嵌套)来表现层级结构,能清晰地展现分层效果,但是有浪费空间的缺点。

5.2、demo:

图11

5.3、代码:

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="utf-8"> 
<style> 
body{ background-color: #000000; } 
circle { stroke: #000; } 
text{ stroke:black; font-size: 15px; } 
</style> 
</head> 
<body> 
<script src="../../d3.js"></script> 
<script> 
var root = { children: [ { children: [ {value: 1}, {value: 1}, {value: 1}, {value: 1}, {value: 1} ] }, { children: [ {value: 1}, {value: 3}, {value: 2} ] } ] }; 
var width = 960, height = 500; 
var color =d3.scale.category20(); 
var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); 
var pack = d3.layout.pack() .size([width, height]); 
node = svg.selectAll("circle") .data(pack.nodes(root)) 
.enter()
.append("circle") 
.attr("cx", function(d) { return d.x; }) 
.attr("cy", function(d) { return d.y; }) 
.attr("r", function(d) { return d.r; }) 
.attr("fill", function(d,i) { return color(i); }); 
node.append("text") 
.attr("dx", function(d) { return d.children ? -8 : 8; }) 
.attr("dy", 3) 
.style("text-anchor", function(d) { return d.children ? "end" : "start"; }) .text(function(d) { return d.value; }); 
</script> 
</body> 
</html>

6、分区布局

6.1、简介:

分区布局将会产生邻接的图形:一个节点-连接的树状填充体。结点将被绘制成实心面积图(弧或者矩形),每个节点相对于其他节点的位置显示出了层级结构。

6.2、demo:

6.2.1、城市数据的旭日分区图:

图12

6.2.2、冰柱图:

图13

6.3、代码:

6.3.1、旭日图代码:

<html> 
<head> 
<meta charset="utf-8"> 
<title>Circle - Partition</title> 
</head> 
<style> body{ background-color: #000000; } </style> 
<body> 
<script src="../../d3.js"></script>
 <script>
 var width = 1200, height = 670, radius = Math.min(width, height) / 2 , color = d3.scale.category20(); 
var svg = d3.select("body").append("svg") 
.attr("width", width) 
.attr("height", height) 
.append("g") 
.attr("transform", "translate(" + radius*2 + "," + radius + ")"); 
var partition = d3.layout.partition() .sort(null) .size([2 * Math.PI, radius * radius]) .value(function(d) { return 1; }); 
var arc = d3.svg.arc() .startAngle(function(d) { return d.x; }) .endAngle(function(d) { return d.x + d.dx; }) .innerRadius(function(d) { return Math.sqrt(d.y); }) .outerRadius(function(d) { return Math.sqrt(d.y + d.dy); }); d3.json("city_tree.json", function(error, root) { 
if(error) console.log(error); 
console.log(root); 
var nodes = partition.nodes(root); 
var links = partition.links(nodes); 
console.log(nodes); 
var arcs = svg.selectAll("g") .data(nodes) .enter().append("g"); arcs.append("path") 
.attr("display", function(d) { return d.depth ? null : "none"; }) // hide inner ring .attr("d", arc) .style("stroke", "#fff") .style("fill", function(d) { 
return color((d.children ? d : d.parent).name); }) .
on("mouseover",function(d){ d3.select(this) .style("fill","yellow"); }) .on("mouseout",function(d){ d3.select(this) .transition() .duration(200) .style("fill", function(d) {
 return color((d.children ? d : d.parent).name); }); }); 
arcs.append("text") .style("font-size", "18px") .style("font-family", "simsun") .style("stroke","blue") .attr("text-anchor","middle") .attr("transform",function(d,i){ //第一个元素(最中间的),只平移不旋转 if( i == 0 ) return "translate(" + arc.centroid(d) + ")";
 //其他的元素,既平移也旋转 
var r = 0; 
if( (d.x+d.dx/2)/Math.PI*180 < 180 ) 
// 0 - 180 度以内的 r = 180 * ((d.x + d.dx / 2 - Math.PI / 2) / Math.PI);
 else 
// 180 - 360 度以内的 r = 180 * ((d.x + d.dx / 2 + Math.PI / 2) / Math.PI); 
//既平移也旋转 
return "translate(" + arc.centroid(d) + ")" + "rotate(" + r + ")"; }) .text(function(d) { return d.name; }); }); 
</script> 
</body> 
</html>

数据文件同树布局中的city_tree.json。

6.3.2、冰柱图代码:

<!DOCTYPE html>
        <html>
<head>
    <meta charset="utf-8">
    <title>testD3-34-icicle.html</title>
    <style>

        body{
            background-color: #000000;
        }
        .node {
            fill: #ddd;
            stroke: #fff;
        }

        .label {
            font: 15px sans-serif;
            text-anchor: middle;
        }

    </style>
</head>
<body>
<script src="../../d3.js" charset="utf-8" ></script>

<script>

    var width = 960,
            height = 500;

    var color = d3.scale.category20();

    var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height);
    // (1)冰柱布局
    var partition = d3.layout.partition()//递归分割节点树到一个旭日或冰柱。
            .size([width, height])//在x和y指定的布局大小。
            .value(function(d) { return d.size; });

    d3.json("Ice.json", function(error, root) {//数据接口
        // (2) 用冰柱图布局转换数据
        var nodes = partition.nodes(root);//计算分区布局并返回节点的数组。

        // (3) 设置文字和节点
        svg.selectAll(".node")
                .data(nodes)
                .enter().append("rect")
                .attr("class", "node")
                .attr("x", function(d) { return d.x; })
                .attr("y", function(d) { return d.y; })
                .attr("width", function(d) { return d.dx; })
                .attr("height", function(d) { return d.dy; })
                .style("fill", function(d) { //颜色:有孩子则返回自己的颜色,无孩子则返回爸爸的颜色
                    return color((d.children ? d : d.parent).name);
                });

        svg.selectAll(".label")
                .data(nodes.filter(function(d) {
                    return d.dx > 6;
                }))
                .enter().append("text")
                .attr("class", "label")
                .attr("dy", ".35em")
                .attr("transform", function(d) {
                    return "translate(" + (d.x + d.dx / 2) + "," + (d.y + d.dy / 2) + ")rotate(90)";
                })
                .text(function(d) { return d.name; });
    });

</script>

</body>
</html>

图14

数据文件(Ice.json):

{
    "name": "AAA",
    "children": [
        {
            "name": "BBB",
            "children": [
                {
                    "name": "CCC",
                    "children": [
                        {
                            "name": "DDD",
                            "children": [
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   },
                                {   "name": "EEE", "size": 73   }
                            ]
                        },
                        {   "name": "DDD", "size": 73   },
                        {   "name": "DDD", "size": 39   },
                        {   "name": "DDD", "size": 67   },
                        {   "name": "DDD", "size": 73   },
                        {   "name": "DDD", "size": 39   },
                        {   "name": "DDD", "size": 67   },
                        {   "name": "DDD", "size": 73   },
                        {   "name": "DDD", "size": 39   },
                        {   "name": "DDD", "size": 67   },
                        {   "name": "DDD", "size": 73   },
                        {   "name": "DDD", "size": 39   },
                        {   "name": "DDD", "size": 67   },
                        {   "name": "DDD", "size": 73   },
                        {   "name": "DDD", "size": 39   },
                        {   "name": "DDD", "size": 67   },
                        {   "name": "DDD", "size": 73   }
                    ]
                },
                {   "name": "CCC", "size": 67   },
                {   "name": "CCC", "size": 73   },
                {   "name": "CCC", "size": 39   },
                {   "name": "CCC", "size": 67   },
                {   "name": "CCC", "size": 73   },
                {   "name": "CCC", "size": 39   },
                {   "name": "CCC", "size": 67   },
                {   "name": "CCC", "size": 73   },
                {   "name": "CCC", "size": 39   },
                {   "name": "CCC", "size": 67   },
                {   "name": "CCC", "size": 73   },
                {   "name": "CCC", "size": 39   },
                {   "name": "CCC", "size": 67   },
                {   "name": "CCC", "size": 73   },
                {   "name": "CCC", "size": 39   },
                {   "name": "CCC", "size": 67   },
                {   "name": "CCC", "size": 73   }
            ]
        },
        {   "name": "BBB", "size": 39   },
        {   "name": "BBB", "size": 67   },
        {   "name": "BBB", "size": 73   }
    ]
}

图15

7、堆叠布局

7.1、简介:

堆叠布局需要一个二维的数据数组,并计算基准线。堆叠图可以被水平、垂直叠放,或者径向叠放。

7.2、demo:

面积堆叠图:

图16

方块堆叠图:

图17

7.3、代码(面积堆叠图):

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="utf-8"> 
<style> body{ background-color: #000000; } </style>
 </head> 
<body> 
<script src="../../d3.js"></script> 
<script> 
var width = 1300, height = 670; 
var dataset = [ [ { x: 0, y: 5 },{ x: 1, y: 4 },{ x: 2, y: 2 },{ x: 3, y: 2 }, { x: 4, y: 3 },{ x: 5, y: 1 },{ x: 6, y: 2 },{ x: 7, y: 2 } ],[ { x: 0, y: 2 },{ x: 1, y: 5 },{ x: 2, y: 3 },{ x: 3, y: 3 }, { x: 4, y: 1 },{ x: 5, y: 5 },{ x: 6, y: 3 },{ x: 7, y: 2 } ],[ { x: 0, y: 5 },{ x: 1, y: 8 },{ x: 2, y: 1 },{ x: 3, y: 4 }, { x: 4, y: 3 },{ x: 5, y: 7 },{ x: 6, y: 2 },{ x: 7, y: 6 } ] ]; 
var stack = d3.layout.stack() (dataset); 
var xScale = d3.scale.ordinal() .domain(d3.range(dataset[0].length)) .rangeRoundBands([0, width/2], 0.01); 
var maxHeight=d3.max(dataset, function(d) { return d3.max(d, function(d) { return d.y0 + d.y; }); }); 
var yScale = d3.scale.linear() .domain([0, maxHeight]) .range([0, height]); 
var colors = d3.scale.category20(); 
var svg = d3.select("body") .append("svg") .attr("width", width) .attr("height", height); 
var groups = svg.selectAll("g") .data(dataset) .enter() .append("g") .style("fill", function(d, i) { return colors(i); }); 
var area = d3.svg.area() .interpolate("cardinal") .x(function(d,i) { return xScale(i); }) .y0(function(d) { return height-yScale(d.y0 + d.y); }) .y1(function(d) { return height-yScale(d.y0); }); 
groups.append("path") .attr("d", function(d) { return area(d); }) .style("fill", function(d, i) { return colors(i); }); 
</script> 
</body>
</html>

8、直方图布局

8.1、简介:

直方图布局可以用来表示数据分布,通过将离散数据点分组归纳到矩形条例绘制。

8.2、demo:

图18

8.3、代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
    body{
        background-color: #000000;
    }

.bar text{
    font-weight:bold;
    font-size:16px;
}
.bar rect {
  fill: blue;
  shape-rendering: crispEdges;
}
.axis path, .axis line {
  fill: none;
  stroke: white;
  shape-rendering: crispEdges;
}

</style>
</head>
<body>
<script src="../../d3.js"></script>
<script>
var values = [0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.2,0.3,0.4,
                0.5,0.5,0.5,0.5,0.5,0.1,0.1,0.7,0.7,0.7,0.6,0.4,0.8];

var width = 960,
    height = 500,
    padding=6;

var x = d3.scale.linear()
    .domain([0, 1])
    .range([0, width/2]);

var format = d3.format(".2f");

var data = d3.layout.histogram()
    .bins(x.ticks(10))
//  .frequency(false)   //频率
   .frequency(true) //频数,默认情况
    (values);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var y = d3.scale.linear()
    .domain([0, 0.01+d3.max(data, function(d) { return d.y; })])
    .range([height, 0]);

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var svg = d3.select("body").append("svg")
    .attr("width", width+30)
    .attr("height", height+30)
        .attr("stroke","yellow")
  .append("g")
    .attr("transform", "translate(" + padding*10 + "," + padding + ")");

var bar = svg.selectAll(".bar")
    .data(data)
  .enter().append("g")
    .attr("class", "bar")
    .attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; });

bar.append("rect")
    .attr("x",padding)
    .attr("width", x(data[0].dx)-1)
    .attr("height", function(d) { return height - y(d.y); });

bar.append("text")
    .attr("dy", ".75em")
    .attr("y", 6)
    .attr("x", x(data[0].dx) / 2)
    .attr("text-anchor", "middle")
    .text(function(d) { return format(d.y); })
    .attr("fill", "yellow");

svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate("+padding+"," + height + ")")
    .call(xAxis);

svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate("+padding+"," + 0 + ")")
    .call(yAxis);
</script>
</body>
</html>

图19

9、饼布局

9.1、简介:

展示离散数据点百分占比或者大小比较,很常见。

9.2、demo:

图20

9.3、代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>testD3-20-pie.html</title>
    <script type="text/javascript" src="../../d3.js"></script>
    <style type="text/css">
        body{
            background-color: #000000;
        }
    </style>
</head>
<body>
<script type="text/javascript">
    var dataset=[5,10,20,40,6,25];

    //(1)转化数据为适合生成饼图的对象数组
    var pie=d3.layout.pie(dataset);

    var h=750;
    var w=650;

    var outerRadius=w/2;//外半径

    //(7)圆环内半径
    var innerRadius=w/1024;//增大这个值可以让饼图变成圆环图

    //(2)用svg的path绘制弧形的内置方法
    var arc=d3.svg.arc()//设置弧度的内外径,等待传入的数据生成弧度
            .outerRadius(outerRadius)
            .innerRadius(innerRadius);

    var svg=d3.select("body")
            .append("svg")
            .attr("width",w)
            .attr("height",h);

    //(3)颜色函数
    var color=d3.scale.category10();//创建序数比例尺和包括10中颜色的输出范围

    //(4)准备分组,把每个分组移到图表中心
    var arcs=svg.selectAll("g.arc")
            .data(pie(dataset))
            .enter()
            .append("g")
            .attr("class","arc")
        //移到图表中心
            .attr("transform","translate("+outerRadius+","+outerRadius+")");//translate(a,b)a表示横坐标起点,b表示纵坐标起点

    //(5)为组中每个元素绘制弧形路路径
    arcs.append("path")//每个g元素都追加一个path元素用绑定到这个g的数据d生成路径信息
            .attr("fill",function(d,i){//填充颜色
                return color(i);
            })
            .attr("d",arc);//将角度转为弧度(d3使用弧度绘制)

    //(6)为组中每个元素添加文本
    arcs.append("text")//每个g元素都追加一个path元素用绑定到这个g的数据d生成路径信息
            .attr("transform",function(d){
                return "translate("+arc.centroid(d)+")";//计算每个弧形的中心点(几何中心)
            })
            .attr("text-anchor","middle")
            .style("fill","white")
            .style("font-size","20px")
            .text(function(d){
                return d.value;//这里已经转为对象了
            });
</script>

</body>
</html>

图21

10、地图

10.1、简介:

对于地图的可视化,D3有一些显示和操作地理数据的组件。这些组件使用GeoJSON格式的数据,这是javascript中表示地理特征的标准方法。

10.2、demo:

图22

10.3、代码:

<!DOCTYPE html>
 <html> 
<head> 
<meta charset="utf-8"> 
<style> 
body{ background-color: #000000; } 
</style> 
</head> 
<body> 
<script src="../../d3.js"></script> 
<script> 
var width = 1360, height = 670; 
var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); 
var color=d3.scale.category20c(); 
var projection = d3.geo.mercator() .center([120, 35]) .scale(540); 
var path = d3.geo.path() .projection(projection); d3.json("china.json", function(error, china) { svg.selectAll("path") .data( china.features ) .enter() .append("path") .attr("d",path) .attr("fill","midnightblue"); 
svg.selectAll("circle") .data(china.features) .enter() .append("circle") .attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; }) .attr("r", 3 ) .attr("fill",function(d,i){ return color(i)}); }); 
//添加南海诸岛示意图 
//此图截自Echarts:http://echarts.baidu.com/doc/example/map9.html svg.append("svg:image") .attr("xlink:href","southchinasea.png") .attr({ x:550, y:350, "width":50, "height":70 }); 
</script> <
/body> 
</html>

结语:
实际运用中经常同时利用多种布局方法做一个工程。我学习的经验是先去网上找一些demo,比如官网上,下载工程到本地,先跑起来,能在本地展示出效果,然后再去读代码,理解代码,然后修改代码。当然,首先自己本地得先配置好本地服务器,个人举得xampp不错,安装也是傻瓜式地一步下一步。官网的API写得有点不太好读,如果想详细了解d3的API可以参考书籍《D3API详解》。

上一篇下一篇

猜你喜欢

热点阅读