D3js官網(wǎng):https://d3js.org/
最近在研究D3js,索性總結(jié)一些文檔出來,來總結(jié)一周以來的學(xué)習(xí)心得梯影。
D3js官網(wǎng)全英文湃密,相對于Echarts官網(wǎng)詳細(xì)的文檔诅挑,英文不好的同學(xué),學(xué)起來可能要費(fèi)勁些泛源,不過有伙伴有中文翻譯版的拔妥,附上鏈接:https://github.com/d3/d3/wiki/CN-Home
D3Js是什么
D3.js 是基于數(shù)據(jù)驅(qū)動文檔工作方式的一款JavaScript函數(shù)庫,主要用于網(wǎng)頁作圖达箍、生成互動圖形没龙,是最流行的可視化庫之一,它被很多其他的表格插件所使用缎玫。D3使你有能力借助HTML硬纤,SVG和CSS來生動地可視化各種數(shù)據(jù)。D3不需要你使用某個特定的框架赃磨,它的重點(diǎn)在于對現(xiàn)代主流瀏覽器的兼容筝家,同時結(jié)合了強(qiáng)大的可視化組件,以數(shù)據(jù)驅(qū)動的方式去操作DOM邻辉。
瀏覽器支持
D3js和ECharts一樣都是實(shí)現(xiàn)數(shù)據(jù)可視化的JS庫溪王,比較D3js和ECharts
- D3支持的主流瀏覽器不包括IE8及以前的版本。D3測試了Firefox恩沛、Chrome在扰、Safari、Opera和IE9雷客。D3的大部分組件可以在舊的瀏覽器運(yùn)行芒珠。
- ECharts,一個使用 JavaScript 實(shí)現(xiàn)的開源可視化庫搅裙,可以流暢的運(yùn)行在 PC 和移動設(shè)備上皱卓,兼容當(dāng)前絕大部分瀏覽器(IE8/9/10/11裹芝,Chrome,F(xiàn)irefox娜汁,Safari等)嫂易,底層依賴輕量級的矢量圖形庫 ZRender,提供直觀掐禁,交互豐富怜械,可高度個性化定制的數(shù)據(jù)可視化圖表。
安裝
常用的引入方式:
- script標(biāo)簽引入
<script src="http://d3js.org/d3.v3.min.js"></script>
- npm命令安裝
npm install d3
由于D3版本v5和v4/v3存在較大的變動傅事,本篇文章主要以v3為主缕允,依次由淺入深的聊一聊d3js的具體使用。
D3如何用
api官網(wǎng) https://github.com/d3/d3/wiki/API--%E4%B8%AD%E6%96%87%E6%89%8B%E5%86%8C
簡單了解下蹭越,以下的demo要用到:
選擇器
<body>
<p>Hello World!</p>
<p>Hello World!</p>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var p = d3.select('body')
.selectAll('p')
.text('你好障本!')
p.style("color", "red")
.style("font-size", "72px")
</script>
</body>
d3提供了豐富的dom操作,有點(diǎn)類似于jQuery的用法响鹃。
d3.select() 選擇的是符合條件的第一個元素驾霜,它指定的為一個元素;
括號里面可以寫標(biāo)簽买置、也可以寫class名粪糙,id名,這點(diǎn)與jQuery神似
d3.select('body') //指定body標(biāo)簽內(nèi)
或
d3.select('.red') //指定標(biāo)簽class名為red的第一個標(biāo)簽
或
d3.select('#blue') //指定標(biāo)簽ID名為blue的第一個標(biāo)簽
d3.selectAll('p') 選擇的是所有p標(biāo)簽的元素堕义,它指定的為一個集合猜旬;
.text('你好') 指定文檔內(nèi)容 content
p.style() 就是對p元素定義css樣式
整個代碼執(zhí)行下來 結(jié)果就是兩行紅色字體的 你好!
d3的很多寫法都類似于jQuery倦卖,并不那么陌生洒擦。
datum
<body>
<p>Hello World!</p>
<p>Hello World!</p>
<script src="../js/d3.v3.js"></script>
<script>
var str = "china"
var body = d3.select('body')
var p = body.selectAll('p')
p.datum(str);
p.text(function(d, i) {
return "第" + i + "個元素綁定的數(shù)據(jù)是" + d
})
</script>
</body>
數(shù)據(jù)可視化的源泉在哪?dataset是數(shù)據(jù)源怕膛;
- selection.datum - 取得或設(shè)置單個元素的數(shù)據(jù)熟嫩,不必計算連接。
p.datum() //p標(biāo)簽的元素設(shè)置為str這個外部源
p.text() // 括號里接收一個函數(shù)回調(diào)褐捻,d就是str的值掸茅, i是索引
最后輸出的結(jié)果:
第0個元素綁定的數(shù)據(jù)是china
第1個元素綁定的數(shù)據(jù)是china
data
<body>
<p>Hello World!</p>
<p>Hello World!</p>
<script src="../js/d3.v3.js"></script>
<script>
var dataset = ["I like dogs","I like cats","I like snakes"];
var body = d3.select('body')
var p = body.selectAll('p')
p.data(dataset);
p.text(function(d, i) {
return d
})
</script>
</body>
-
selection.data - 在計算相關(guān)的連接時,取得或設(shè)置一組元素的數(shù)據(jù)柠逞。
數(shù)據(jù)源有3個昧狮,而p標(biāo)簽僅有兩個元素,所以輸出到頁面的結(jié)果為:
I like dogs
I like cats
svg
<script>
var width = 400;
var height = 400;
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
</script>
append 添加svg標(biāo)簽
attr svg設(shè)定寬高
柱狀圖
<script>
var dataset = [ 250 , 210 , 170 , 130 , 90 ]; //數(shù)據(jù)(表示矩形的寬度)
var width = 400;
var height = 400;
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
var rectHeight = 25; //每個矩形所占的像素高度(包括空白)
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", 20)
.attr("y", function(d, i){
return i * rectHeight;
})
.attr("width", function(d){
return d;
})
.attr("height", rectHeight-2)
.attr("fill", "steelblue");
</script>
運(yùn)行結(jié)果:
這里面注意到
.enter() 作用是在為缺失的元素返回占位符
線性比例尺
<script>
// 線性比例尺
var dataset = [1.2, 2.3, 0.9, 1.5, 3.3];
var min = d3.min(dataset);
var max = d3.max(dataset);
var linear = d3.scale.linear()
.domain([min, max])
.range([0, 300])
linear(0.9)
console.log(linear(2.3)) // 175
</script>
d3.min() 返回最小值
d3.max() 返回最大值
d3.scale.linear() 構(gòu)建一個線性比例尺
.domain() 取得或設(shè)置比例尺的定義域
.range() 取得或設(shè)置比例尺的輸出范圍
序數(shù)比例尺
<script>
// 序數(shù)比例尺
var index = [0, 1, 2, 3, 4];
var color = ["red", "blue", "green", "yellow", "black"];
var ordinal = d3.scale.ordinal() // 構(gòu)造一個序數(shù)比例尺
.domain(index) // 獲取或指定比例尺的輸入域
.range(color); // 獲取或指定比例尺的輸出范圍
console.log(ordinal(2)) // 175
</script>
線性比例尺的柱狀圖
<script>
var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
var linear = d3.scale.linear()
.domain([0, d3.max(dataset)])
.range([0, 250])
var rectHeight = 25; //每個矩形所占的像素高度(包括空白)
var svg = d3.select("body")
.append('svg')
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x",20)
.attr("y",function(d,i){
return i * rectHeight;
})
.attr("width",function(d){
return linear(d); //在這里用比例尺
})
.attr("height",rectHeight-2)
.attr("fill","steelblue");
</script>
帶x軸的柱狀圖
<style>
.axis path,
.axis line{
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
</style>
<script>
var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
var linear = d3.scale.linear()
.domain([0, d3.max(dataset)])
.range([0, 250])
var rectHeight = 25; //每個矩形所占的像素高度(包括空白)
var svg = d3.select("body")
.append('svg')
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x",20)
.attr("y",function(d,i){
return i * rectHeight;
})
.attr("width",function(d){
return linear(d); //在這里用比例尺
})
.attr("height",rectHeight-2)
.attr("fill","steelblue");
</script>
輸出結(jié)果為:
帶xy軸的柱狀圖
<style>
.axis path,
.axis line{
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.MyRect {
fill: steelblue;
}
.MyText {
fill: white;
text-anchor: middle;
}
</style>
<script>
//畫布大小
var width = 400;
var height = 400;
//在 body 里添加一個 SVG 畫布
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
//畫布周邊的空白
var padding = {left:30, right:30, top:20, bottom:20};
//定義一個數(shù)組
var dataset = [10, 20, 30, 40, 33, 24, 12, 5];
//x軸的比例尺
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, width - padding.left - padding.right]);
//y軸的比例尺
var yScale = d3.scale.linear()
.domain([0,d3.max(dataset)])
.range([height - padding.top - padding.bottom, 0]);
//定義x軸
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
//定義y軸
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
//矩形之間的空白
var rectPadding = 4;
//添加矩形元素
var rects = svg.selectAll(".MyRect")
.data(dataset)
.enter()
.append("rect")
.attr("class","MyRect")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.attr("x", function(d,i){
return xScale(i) + rectPadding/2;
} )
.attr("y",function(d){
return yScale(d);
})
.attr("width", xScale.rangeBand() - rectPadding )
.attr("height", function(d){
return height - padding.top - padding.bottom - yScale(d);
});
//添加文字元素
var texts = svg.selectAll(".MyText")
.data(dataset)
.enter()
.append("text")
.attr("class","MyText")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.attr("x", function(d,i){
return xScale(i) + rectPadding/2;
} )
.attr("y",function(d){
return yScale(d);
})
.attr("dx",function(){
return (xScale.rangeBand() - rectPadding)/2;
})
.attr("dy",function(d){
return 20;
})
.text(function(d){
return d;
});
//添加x軸
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
.call(xAxis);
//添加y軸
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.call(yAxis);
</script>
帶動畫效果的柱狀圖
<script>
//畫布大小
var width = 400;
var height = 400;
//在 body 里添加一個 SVG 畫布
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
//畫布周邊的空白
var padding = {left:30, right:30, top:20, bottom:20};
//定義一個數(shù)組
var dataset = [10, 20, 30, 40, 33, 24, 12, 5];
//x軸的比例尺
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, width - padding.left - padding.right]);
//y軸的比例尺
var yScale = d3.scale.linear()
.domain([0,d3.max(dataset)])
.range([height - padding.top - padding.bottom, 0]);
//定義x軸
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
//定義y軸
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
//矩形之間的空白
var rectPadding = 4;
//添加矩形元素
var rects = svg.selectAll(".MyRect")
.data(dataset)
.enter()
.append("rect")
.attr("class","MyRect")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.attr("x", function(d,i){
return xScale(i) + rectPadding/2;
} )
.attr("y",function(d){
return yScale(d);
})
.attr("width", xScale.rangeBand() - rectPadding)
.attr("y",function(d){
var min = yScale.domain()[0];
return yScale(min);
})
.attr("height", function(d){
return 0;
})
.transition()
.delay(function(d,i){
return i * 200;
})
.duration(2000)
.ease("bounce")
.attr("y",function(d){
return yScale(d);
})
.attr("height", function(d){
return height - padding.top - padding.bottom - yScale(d);
})
//添加文字元素
var texts = svg.selectAll(".MyText")
.data(dataset)
.enter()
.append("text")
.attr("class","MyText")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.attr("x", function(d,i){
return xScale(i) + rectPadding/2;
} )
.attr("dx",function(){
return (xScale.rangeBand() - rectPadding)/2;
})
.attr("dy",function(d){
return 20;
})
.text(function(d){
return d;
})
.attr("y",function(d){
var min = yScale.domain()[0];
return yScale(min);
})
.transition()
.delay(function(d,i){
return i * 200;
})
.duration(2000)
.ease("bounce")
.attr("y",function(d){
return yScale(d);
});
//添加x軸
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
.call(xAxis);
//添加y軸
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.call(yAxis);
</script>