美文网首页Web 前端开发
d3.js主要布局种类总结

d3.js主要布局种类总结

作者: stayhungry_e89f | 来源:发表于2020-02-13 18:07 被阅读0次

    (本文在较早之前在本人知乎账号为“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详解》。

    相关文章

      网友评论

        本文标题:d3.js主要布局种类总结

        本文链接:https://www.haomeiwen.com/subject/lbelfhtx.html