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>
)
}
複製代碼
}