D3的全称是 Data-Driven Documents (简单说意思就是:数据驱动的文档)java
D3是一个javaScript的函数库,是用来作数据可视化的。node
文档指DOM,即文档对象模型(Document Object Model)react
D3容许用户绑定任意数据到DOM,而后根据数据来操做文档,建立可交互式的图表。npm
因为做者自身水平有限D3也是最近才学的,文中不免出现错误,恳请你们批评指正,我这边也会跟进修改的。数据结构
app
分别是 1.饼图 2.散点图 3.力学图 dom
1:饼图 svg
↓全↓部↓代↓码↓(后面有拆解)函数
import React from 'react';
import * as d3 from 'd3';
export default class Map extends React.Component{
constructor(props){
super(props);
this.state={}
}
componentDidMount(){
var width = 400;
var height = 400;
var dataset = [ 1 , 2 , 3 , 4 , 5 ];
var svg = d3.select("#body")
.append("svg")
.attr("width", width)
.attr("height", height);
var pie = d3.layout.pie();
var piedata = pie(dataset);
var outerRadius = 150; //外半径
var innerRadius = 0; //内半径,为0则中间没有空白
var arc = d3.svg.arc() //弧生成器
.innerRadius(innerRadius) //设置内半径
.outerRadius(outerRadius); //设置外半径
var color = d3.scale.category10();
var arcs = svg.selectAll("g")
.data(piedata)
.enter()
.append("g")
.attr("transform","translate("+ (width/2) +","+ (width/2) +")");
arcs.append("path")
.attr("fill",function(d,i){
return color(i);
})
.attr("d",function(d){
return arc(d);
});
arcs.append("text")
.attr("transform",function(d){
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor","middle")
.text(function(d){
return d.data;
});
}
render(){
return(
<div id="body"></div>
)
}
}
复制代码
首先咱们必须先必须布局
在cmd内
npm install --save d3
以后在咱们react页面头部中
import * as d3 from 'd3';
复制代码
在咱们的componentDidMount中书写代码(由于饼图我这个饼图代码十分简洁/简单)
var width = 400;
//定义宽度
var height = 400;
//定义高度
var dataset = [ 1 , 2 , 3 , 4 , 5 ];
//定义饼图内的data数据
var svg = d3.select("#body")//把d3代码生成到#body内
.append("svg")//添加的svg
.attr("width", width)//添加的宽度是咱们定义的宽度/高度也是这样
.attr("height", height);
var pie = d3.layout.pie();
//构建一个饼图布局,使用默认的方法访问数据,默认不排序。起始弧度为0,结束弧度为2π,返回的layout能够是对象,也能够是函数。
也就是你能够调用这个函数,这个函数也有额外的方法改变自身的行为,就像其它的d3类同样
var piedata = pie(dataset);
var outerRadius = 150; //外半径
var innerRadius = 0; //内半径,为0则中间没有空白
var arc = d3.svg.arc() //弧生成器
//建立一个arc生成器,也就是扇形。使用默认的内部半径,外部半径,
起始角度,结束角度 访问数据的函数。返回的函数生成path数据来造成闭合的solid arc。
.innerRadius(innerRadius) //设置内半径
.outerRadius(outerRadius); //设置外半径
var color = d3.scale.category10();//颜色比例尺
复制代码
//颜色比例尺
var colors = d3.scale.category10();
console.log(colors.range());
// -> ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"]
var arcs = svg.selectAll("g")
.data(piedata)
.enter()
.append("g")
.attr("transform","translate("+ (width/2) +","+ (width/2) +")");
arcs.append("path")
.attr("fill",function(d,i){
return color(i);
})
.attr("d",function(d){
return arc(d);
});
arcs.append("text")
.attr("transform",function(d){
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor","middle")
.text(function(d){
return d.data;
});
复制代码
↓全↓部↓代↓码↓(后面有拆解)
import React from 'react';
import * as d3 from 'd3';
export default class Index extends React.Component{
constructor(props){
super(props)
this.state={}
}
componentDidMount(){
//圆心数据
var center = [
[0.5,0.5],[0.7,0.8],[0.4,0.9],
[0.11,0.32],[0.88,0.25],[0.75,0.12],
[0.5,0.1],[0.2,0.3],[0.4,0.1],[0.6,0.7]
]
//定义一个svg的绘制区域。
var width = 600; //svg绘制区域的宽度
var height = 500; //svg绘制区域的高度
var svg = d3.select("#body") //选择id为body的div
.append("svg") //在<body>中添加<avg>
.attr("width",width) //设定<svg>的宽度属性
.attr("height",height) //设定<svg>的高度属性
//定义比例尺
//x轴宽度
var xAxisWidth = 300;
//y轴宽度
var yAxisWidth = 300;
//x轴比例尺
var xScale = d3.scale.linear() //建立一个线性比例尺
.domain([0,1.2*d3.max(center,function(d){ //设定定义域
return d[0]
})])
.range([0,xAxisWidth]) //设定值域
//y轴比例尺
var yScale = d3.scale.linear() //建立一个线性比例尺
.domain([0,1.2*d3.max(center,function(d){ //设定定义域
return d[1]
})])
.range([0,yAxisWidth]) //设定值域
//在svg中绘制图形,先绘制圆
//外边框
var padding = {top:30,right:30,bottom:100,left:100};
//绘制圆
var circle = svg.selectAll("circle")
.data(center) //绑定数据
.enter() //获取enter部分
.append("circle") //
.attr("fill","goldEnrod") //设置颜色
.attr("cx",function(d){ //设置圆心的x坐标
return padding.left + xScale(d[0])
})
.attr("cy",function(d){ //设置圆心的y坐标
return height-padding.bottom-yScale(d[1])
})
.attr("r",5) //设置圆的半径
//定义坐标轴
//x轴
var xAxis = d3.svg.axis() //建立一个默认的新坐标轴
.scale(xScale) //设定坐标轴的比例尺
.orient("bottom") //设定坐标轴的方向
yScale.range([yAxisWidth,0]) //从新设置y轴比例尺的值域,与原来的相反
//y轴
var yAxis = d3.svg.axis() //建立一个默认的新坐标轴
.scale(yScale) //设定坐标轴的比例尺
.orient("left") //设定坐标轴的方向
//添加x轴和平移
svg.append("g") //在svg中添加一个包含坐标轴各元素的g元素
.attr("class","axis") //定义class名
.attr("transform","translate("+padding.left+","+(height-padding.bottom)+")") //将x轴进行平移
.call(xAxis) //将自身做为参数传递给xAxis函数
//设置y轴和平移
svg.append("g") //在svg中添加一个包含坐标轴各元素的g元素
.attr("class","axis") //定义class名
.attr("transform","translate("+padding.left+","+(height-padding.bottom-yAxisWidth+")")) //将y轴进行平移
.call(yAxis)
}
render(){
return(
<div id="body" ></div>
)
}
}
复制代码
↓全↓部↓代↓码↓(后面有拆解)
import React from "react"
import * as d3 from 'd3';
export default class Main extends React.Component {
constructor(props) {
super(props);
this.state={}
}
componentDidMount(){
var that = this;
this.linkList = [];//连线数据
this.nodeList = [];//节点数据
this.linkTemp = [];
this.width = 1000,
this.height = 500, // svg的宽和高
this.xDistance = 100,
this.yDistance = 100; // x轴方向节点间距。y轴方向加点间距
this.colorPalette = ["#1836A0", "#00A4FF"] // 色板
this.rectWidth = 70;
this.paddingLeft = 25 + this.rectWidth / 2; // d3 svg 图距离左侧边框的距离
this.svg = d3
.select("#dthree")
.append("svg")
.attr('id','svg')
.attr("width", this.width)
.attr("height", this.height);
let data={
"code":1,
"message":"success",
data:[
{
"source":"ESRBMD",
"target":"QPWWIH"
},
{
"source": "ESRBMD",
"target": "APWWIH"
},
{
"source": "ESRBMD",
"target": "BPWWIH"
},
{
"source": "ESRBMD",
"target": "CPWWIH"
},
{
"source": "PZ9SPU",
"target": "9EWIUJ"
},
{
"source": "PZ9SPU",
"target": "YO9EVH"
},
{
"source": "QPWWIH",
"target": "PZ9SPU"
}
]
}
that.linkList = data.data;
that.linkTemp = _.clone(that.linkList)//此处理解为替版
//获取节点标签列表
that.linkList.forEach( function (item,index){
that.nodeList.push(item.source)
that.nodeList.push(item.target)
})//循环判断并放入nodeList
that.nodeList = _.uniq(that.nodeList)//此处去重
//修改数据结构
that.nodeList.forEach( function (item,index) {
that.nodeList[index] = { "label":item,"index":index}
})//转换成{label: "ESRBMD", index: 0}一类
that.generateNodesList(null)
// 生成符合d3力布局接口的连线数据
that.generateLinkList()
//生成图
that.updateGraph(that.nodeList , that.linkList)
}
generateNodesList(parentnode) {
var that=this;
if(!parentnode){//第一次调用的时候,父节点null,须要找出第一层的界点.
//找第一层的界点
var firstNode = this.getFirstNode()
if(firstNode){
//迭代
this.generateNodesList(firstNode)
}
else{
console.log('Data error: cannot find first node.')
}
}else if(this.linkTemp.length > 0){//指定了父节点时,若是 linktemp空了,表示已完成便利.
let countSubsequence = 0//用于表示同级的节点垂直方向的顺序
let links = _.clone(this.linkTemp)
links.forEach( function (item){
if(item.source === parentnode.label){
let node = null
countSubsequence++;
//从linksTemp中移除已便利的数据
_.remove(that.linkTemp,function(n){
return n.source == item.source && n.target == item.target
})
//更新子节点的层级和坐标
node = that.updateNodeLevel(item.target,parentnode.level + 1,countSubsequence)
that.generateNodesList(node)
}
})
}else{
console.log("Generated nodes finished.")
}
}
getFirstNode(){
var that=this;
let sources = [];
let targets = [];
let firstNodeLabel = ""
let firstNode = null
that.linkList.forEach( function (item){
sources.push(item.source)
})
that.linkList.forEach( function (item){
targets.push(item.target)
})
//找出在source中但不在target中的界点,即为第一层级的界点
sources=_.uniq(sources)
sources.forEach(function (value,i){
if(targets.indexOf(value)==-1){
firstNodeLabel = value
return false
}
})
// console.log('第一层:'+firstNodeLabel)
//根据节点名称.更新第一层级节点的数据
that.nodeList.forEach(function (item,i){
if(item.label === firstNodeLabel){
that.nodeList[i].level=1
that.nodeList[i].x = that.paddingLeft
that.nodeList[i].y = that.yDistance
firstNode = that.nodeList[i];
return false
}
})
return firstNode
}
/**
* 更新指定名称的节点的层级,和坐标
* @param {*} label 指定的节点名称
* @param {*} colIndex 列索引
* @param {*} rowIndex 行索引
*/
updateNodeLevel(label,colIndex,rowIndex){
var that=this;
let node=null
this.nodeList.forEach(function(item,i){
if(item.label===label){
that.nodeList[i].level = colIndex
that.nodeList[i].x = that.xDistance * (colIndex-1) + that.paddingLeft
that.nodeList[i].y = that.yDistance * rowIndex
node = that.nodeList[i]
return false //跳出遍历
}
})
return node
}
generateLinkList(){
var that=this;
that.nodeList.forEach(function(n){
that.linkList.forEach(function(l,j){
if(l.source===n.label){
that.linkList[j].source=n.index
}
if(l.target===n.label){
that.linkList[j].target=n.index
}
})
})
console.log("Generated link finished.")
}
updateGraph(nodes, links){
var that=this;
//初始化力布局
let force = d3.layout
.force()
.size([this.width,this.height]);
let link=that.svg.selectAll('.link');
let node=that.svg.selectAll('.node');
force
.nodes(nodes)
.links(links)
.start();
link = link
.data(links)
.enter()
.append("line")
.attr("class","link")
.attr("stroke","#CBD0D3")
.attr("strokeWidth","1px")
//copy
.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;
});
var nodecontainer = node.data(nodes)
.enter().append("g")
.attr({
"class": "nodes",
"cx": function (d) {
return d.x;
},
"cy": function (d) {
return d.y;
}
});
// 节点方块
node = nodecontainer.append("rect")
.attr({ // 位置。大小
"class": "square",
"x": function (d) {
return d.x - that.rectWidth/2;
},
"y": function (d) {
return d.y - 12;
},
"width": that.rectWidth,
"height": 24,
"rx":"4",
"ry":"4"
})
.attr("fill", function (d) { // 填充色
return that.colorPalette[(d.level - 1) % that.colorPalette.length]
})
.on("click", this.onClickNode); // 监听 click 事件
// 节点文字
let text = nodecontainer
.append('text')
.attr({
"text-anchor": "middle",
"fill": "#ffffff",
"class": "text",
"x": function (d) {
return d.x;
},
"y": function (d) {
return d.y + 5;
},
})
.text(function (d) { return d.label })
.on("click", this.onClickNode);
}
onClickNode(d) {
console.log("You just select node " + d.label)
}
render() {
return (
<div id="dthree" ref='dthree'></div>
)
}
复制代码
}