d3.js学习笔记-09(布局:饼图、力导向图、弦图)

12 篇文章 1 订阅
9 篇文章 2 订阅

d3.js学习笔记-09


D3的12种布局:饼状图、力导向图、弦图、树状图、集群图、捆图、打包图、直方图、分区图、堆栈图、矩阵树图、层级图【不可直接使用】
布局的使用顺序:确定初始数据—>转换数据—>绘制

1 饼状图(Pie)

  • d3.layout.pie():创建一个饼状图布局。
  • pie(values[, index]):转换数据,转换后的每一个对象中都包含有起始角度和终止角度。
  • pie.value([accessor]):设置/获取值访问器,即如何从接收的数据中提取初始值。如果省略参数,则返回当前的
    值访问器。
  • pie.sort([comparator]):设定/获取比较器,用于排序,例如d3.ascending和d3.descending。如果省略,则返回当前的比较器。
  • pie.startAngle([angle]):设置/获取饼状图的起始角度,默认为0(弧度)。
  • pie.endAngle([angle]):设置/获取饼状图的终止角度,默认为2Π(弧度)。

1.1 确定初始数据

var dataset =[["小米",60.8], ["三星", 58.4], ["联想", 47.31],
["苹果", 46-6], ["华为", 41.31], ["酷派", 40.11], 
["其他", 111.5]];

1.2 数据转换

var pie = d3.layout.pie()   // 创建一个饼状图布局
			value(function(d){    // 值访问器,返回数组元素的d[1],即 60.8、58.4......
				return d[1];
			})
var piedate = pie(dataset);

在这里插入图片描述

1.3 绘制

绘制饼状图需要使用弧生成器
//外半径和内半径
var outerRadius = width / 3;
var innerRadius = 0;
// 创建弧生成器
var arc = d3.svg.arc()
			.innerRadius(innerRadius)   // 弧的外半径
			.outerRadius(outerRadius);  // 弧的内半径
var color = d3.scale.category20();  // 颜色比例尺
//添加对应数目的弧组,即<g>元素
var arcs = svg.selectAl1("g")
			.data(piedata) //绑定转换后的数据piedata
			.enter()
			.append("g")
			.attr("transform", "translate("+( width/2 )+","+ (height/2 )+")")

//添加弧的路径元素
arcs.append("path")
	.attr("fi11",function (d,i){
		return color(i);//设定弧的颜色
	})
	.attr("d" ,function(d){
		// 使用弧生成器获取路径
		return arc(d);
	}):

在这里插入图片描述
在弧内添加文字

// 添加弧内的文字元素
arcs.append("text")
	.attr("transform",function(d){
		var x = are.centroid(d)[O] *1.4;//文字的x坐标,are.centroid返回弧中心
		var y = arc.centroid(d)[1]*1.4;//文字的y坐标
		return"translate("+ x +","y+")";
	})
	.attr("text-anchor" ,"middle")
	.text(function (d){
		//计算市场份额的百分比
		var percent = Number(d.value)/d3.sum(dataset, function(d){return d[1];})*100;
		//保留1位小数点,末尾加一个百分号返回
		return percent.toFixed(1) +"%";
));

2 力导向图(force)

  • d3.layout.force():创建一个力导向图布局。
  • force.size([size]):设置/获取力导向图的作用范围,使用方法为force.size([x,y]),此函数用于指定两件事。重心位置为(x/2 , y/2 )所有节点的初始位置限定为[0,x]和[0,y]之间。如果不指定,默认为[1,1]。

节点相关

  • force.nodes([nodes]):设置/获取力导向图布局的节点数组。如果省略参数nodes,则返回当前的节点数组。
  • force.friction([friction]):设置/获取摩擦系数,值的范围是[0,1],默认为0.9。值为1,表示没有速度的损耗;值为0,表示速度的损耗最大。如果省略参数,则返回当前值。
  • force.charge([charge]):设置/获取节点的电荷数。该参数决定是排斥还是吸引,默认值为-30。值为正,则相互吸引,值越大引力越大。值为负,则相互排斥,值越小排斥力越大。
  • force.chargeDistance([distance]):设置/获取引力的作用距离,超过这个距离,则没有引力的作用。默认值为无穷大。
  • force.theta([theta]):设置/获取限制值。如果节点数过多,力导向图布局的计算时间就会增加(复杂度为O(nlogn))。theta就是为了限制这个计算而存在的,默认值为0.8。这个值越小,就能把计算限制得越紧。
  • force.gravity([gravity]):设置/获取重力。以size()设定的中心产生重力,各节点都会向中心运动,默认值为0.1。如果设定为0,则没有重力的作用。

连线相关

  • force.links([links]):设置/获取力导向图布局的连线数组。如果省略参数links,则返回当前的连线数组。
  • force.linkDistance([distance]):设置/获取连线的长度,默认为20。
  • force.linkStrength([strength]):设置/获取连线的坚硬度,值的范围为[0,1],值越大越坚硬。值为1,则拖动一个节点A,与之相连节点会与A保持linkDistance()设定的距离运动;值为0,则拖动一个节点A,与之相连的节点不会运动,连线会被拉长。

动画相关

  • force.alpha([value]): 设置/获取动画的冷却系数,运动过程中该系数会不断减小,直到小于0.005为止,此时动画停止。
  • force.start(): 将alpha设定为0.1后,开始计算。
  • force.stop(): 等价于alpha(0),停止动画。
  • force.resume(): 等价于alpha(0.1),重新启动动画。但是,这个函数通常不直接使用,在 start()和drag()的内部自动调用.
  • force.tick(): 动画的计算进入到下一步。
  • force.on(type,listcner): type是事件类型,有三种事件:start、tick. end。listencr是监听器。

交互式相关

  • force.drag(): 用于拖曳操作的函数。

example

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title></title>
    <script src="../d3.v3.min.js"></script>
  </head>
  <style>
    .forceLine {
      stroke: #444;
      stroke-width: 2;
    }

    .forceCircle {
      stroke: black;
      stroke-width: 2;
    }

    .forceText {
      fill: black;
      text-anchor: middle;
      font-size: 20;
      font-family: arial;
    }
  </style>

  <body>
    <script>
      var width = 600;
      var height = 600;
      var svg = d3
        .select("body")
        .append("svg")
        .attr("width", width)
        .attr("height", height);

      // 初始数据
      var nodes = [
        { name: "0" },
        { name: "1" },
        { name: "2" },
        { name: "3" },
        { name: "4" },
        { name: "5" },
        { name: "6" },
      ];
      var edges = [
        { source: 0, target: 1 },
        { source: 0, target: 2 },
        { source: 0, target: 3 },
        { source: 1, target: 4 },
        { source: 1, target: 5 },
        { source: 1, target: 6 },
      ];

      // 转换数据
      var force = d3.layout
        .force() // 创建一个力导向图布局
        .nodes(nodes) // 节点
        .links(edges) // 定义边
        .size([width, height]) // 定义作用范围
        .linkDistance(90) // 定义连线的距离
        .charge(-400); // 定义电荷数,相互排斥
      force.start(); // 开启布局计算

      //3.绘制
      var color = d3.scale.category20();

      //绘制连线
      var lines = svg
        .selectAll(".forceLine")
        .data(edges)
        .enter()
        .append("line")
        .attr("class", "forceLine");

      //绘制节点
      var circles = svg
        .selectAll(".forceCircle")
        .data(nodes)
        .enter()
        .append("circle")
        .attr("class", "forceCircle")
        .attr("r", 30)
        .style("fill", function (d, i) {
          return color(i);
        })
        .call(force.drag); // 力向导图的拖拽行为

      var drag = force.drag()   // 定义拖拽行为,可以不定义
                    .on("dragstart", function (d) {
                    //拖拽开始后设定被拖拽对象为固定
                    d.fixed = true;
                    })
                    .on("dragend", function (d, i) {
                    //拖拽结束后变为原来的颜色
                    d3.select(this).style("fill", color(i));
                    })
                    .on("drag", function (d) {
                    //拖拽中对象变为黄色
                    d3.select(this).style("fill", "yellow");
                    });

      //绘制文字
      var texts = svg
        .selectAll(".forceText")
        .data(nodes) // 文本的数目与节点的数目相同
        .enter()
        .append("text")
        .attr("class", "forceText")
        .attr("x", function (d) {
          return d.x;
        })
        .attr("y", function (d) {
          return d.y;
        })
        .attr("dy", ".3em")
        .text(function (d) {
          return d.name; // 文本的内容即节点的名称
        });

      //tick事件的监听器
      force.on("tick", function () {
        //更新边的端点坐标
        lines.attr("x1", function (d) {
          return d.source.x;
        });
        lines.attr("y1", function (d) {
          return d.source.y;
        });
        lines.attr("x2", function (d) {
          return d.target.x;
        });
        lines.attr("y2", function (d) {
          return d.target.y;
        });

        //更新节点坐标
        circles.attr("cx", function (d) {
          return d.x;
        });
        circles.attr("cy", function (d) {
          return d.y;
        });

        //更新节点文字的坐标
        texts.attr("x", function (d) {
          return d.x;
        });
        texts.attr("y", function (d) {
          return d.y;
        });
      });

      //事件监听器:运动开始时
      force.on("start", function () {
        console.log("运动开始");
      });

      //运动结束时
      force.on("end", function () {
        console.log("运动结束");
      });
    </script>
  </body>
</html>

在这里插入图片描述

3 弦图(chord)

弦图表示一组元素之间的联系

在这里插入图片描述
在这里插入图片描述

  • d3.layout.chord():创建一个弦图布局
  • chord.matrix([matrix]):设置/获取矩阵,必须是方块矩阵,即行列数相等。
  • chord.padding([padding]):设置/获取元素节点之间的间距,默认为0。
  • chord.sortGroups([comparator]):对节点进行排序。comparator是比较函数,如d3.ascending 和l d3.descending.
  • chord.sortSubgroups([comparator]):对各节点的所在行的数据进行排序,comparator为比较函数。
  • chord.sortChords([comparator]):对弦进行排序
  • chord.chords():返回弦数组,具有:index(行号i)、 sunindex(列号j)、 startAngle(弧的起始角度)、 endAngle(弧的终止角度)、 value(矩阵单元(i, j)的值)等属性
  • chord.groups():返回节点数组,具有:index(行号i)、startAngle(弧的起始角度)、 endAngle(弧的终止角度)、 value(改行所有数值的和)等属性
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title></title>
    <script src="../d3.v3.min.js"></script>
  </head>
  <style>
    .outerPath {
      stroke: black;
    }

    .outerText {
      text-anchor: middle;
      font-size: 16;
    }

    .innerPath {
      stroke: black;
    }
  </style>
  <body>
    <script>
      var width = 600;
      var height = 600;
      var svg = d3
        .select("body")
        .append("svg")
        .attr("width", width)
        .attr("height", height);

      //1.确定初始数据

      var continent = ["亚洲", "欧洲", "非洲", "美洲", "大洋洲"];

      // 各州人口的组成
      //				亚洲		美洲
      //	亚洲		9000		1000
      //	美洲		7000		500
      // 该矩阵表示:
      // 1.亚洲的人口:有9000是本地人,有1000人是来自美洲的移民,总人口为 9000 + 1000
      // 2.美洲的人口:有500是本地人,有7000人是来自亚洲的移民,总人口为 500 + 7000

      var population = [
        [9000, 870, 3000, 1000, 5200],
        [3400, 8000, 2300, 4922, 374],
        [2000, 2000, 7700, 4881, 1050],
        [3000, 8012, 5531, 500, 400],
        [3540, 4310, 1500, 1900, 300],
      ];

      //2.转换数据
      var chord = d3.layout
        .chord()
        .padding(0.03) // 节点之间的间隔
        .sortSubgroups(d3.ascending) // 对节点所在的行进行排序,递增
        .matrix(population);  // 获取方阵

      //3.绘制

      //弦图的<g>元素
      var gChord = svg
        .append("g")
        .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); // 平移到svg的中心

      //节点的<g>元素
      var gOuter = gChord.append("g");

      //弦的<g>元素
      var gInner = gChord.append("g");

      //颜色比例尺
      var color20 = d3.scale.category20();

      //绘制节点
      var innerRadius = (width / 2) * 0.7; // 内半径
      var outerRadius = innerRadius * 1.1; // 外半径

      //弧生成器
      var arcOuter = d3.svg
        .arc()
        .innerRadius(innerRadius)
        .outerRadius(outerRadius);

        // 绘制弦,使用弧生成器
      gOuter.selectAll(".outerPath")
        .data(chord.groups())  // 开始角度、结束角度、值
        .enter()
        .append("path")
        .attr("class", "outerPath")
        .style("fill", function (d) {
          return color20(d.index);
        })
        .attr("d", arcOuter);

        // 添加文本
      gOuter
        .selectAll(".outerText")
        .data(chord.groups())
        .enter()
        .append("text")
        .each(function (d, i) {  // 为绑定的数据添加变量
          d.angle = (d.startAngle + d.endAngle) / 2; // 弧的中心角度
          d.name = continent[i];  //  添加节点的名称
        })
        .attr("class", "outerText")
        .attr("dy", ".35em")
        // 对文本进行旋转、平移
        .attr("transform", function (d) {
          var result = "rotate(" + (d.angle * 180) / Math.PI + ")";

          result += "translate(0," + -1.0 * (outerRadius + 10) + ")";

          if (d.angle > (Math.PI * 3) / 4 && d.angle < (Math.PI * 5) / 4)
            result += "rotate(180)";

          return result;
        })
        .text(function (d) {
          return d.name;
        });

      //绘制弦
      // 创建一个弦生成器
      var arcInner = d3.svg.chord().radius(innerRadius);

      gInner.selectAll(".innerPath")
        .data(chord.chords())
        .enter()
        .append("path")
        .attr("class", "innerPath")
        .attr("d", arcInner)
        .style("fill", function (d) {
          return color20(d.source.index);
        });


        // 交互
        gOuter.selectAll(".outerPath")
			.on("mouseover",fade(0.0))		//鼠标放到节点上只有与节点相连接的弦才显示
			.on("mouseout",fade(1.0));		//鼠标从节点上移开
            
            
        // D3的filter函数用来对选择集进行筛选。
        // 它的参数是一个函数,这个函数会对选择集里的没一个元素执行。
        // 如果执行结果是true那么保存这个元素,否者删除这个元素
		function fade(opacity){
			//返回一个匿名函数function(g, i)
			return function(g,i){
				gInner.selectAll(".innerPath")	//选择所有的弦
						.filter( function(d) { 	//过滤器
							//没有连接到鼠标所在节点的弦才能通过
							return d.source.index != i && d.target.index != i; 
						})
						.transition()	//过渡
						.style("opacity", opacity);	//透明度
			}
			
		}
    </script>
  </body>
</html>

在这里插入图片描述

References

[1] 吕之华.精通D3.js:交互式数据可视化高级编程[M].北京:电子工业出版社,2015∶206-228.

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值