D3js入門 --- 柱狀圖的制作

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é)果:


image.png

這里面注意到
.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é)果為:


image.png

帶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>
image.png

帶動畫效果的柱狀圖

<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>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末板壮,一起剝皮案震驚了整個濱河市逗鸣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖撒璧,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件透葛,死亡現(xiàn)場離奇詭異,居然都是意外死亡卿樱,警方通過查閱死者的電腦和手機(jī)僚害,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來繁调,“玉大人萨蚕,你說我怎么就攤上這事∩婺伲” “怎么了门岔?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長烤送。 經(jīng)常有香客問我,道長糠悯,這世上最難降的妖魔是什么帮坚? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮互艾,結(jié)果婚禮上试和,老公的妹妹穿的比我還像新娘。我一直安慰自己纫普,他們只是感情好阅悍,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著昨稼,像睡著了一般节视。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上假栓,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天寻行,我揣著相機(jī)與錄音,去河邊找鬼匾荆。 笑死拌蜘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的牙丽。 我是一名探鬼主播简卧,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼烤芦!你這毒婦竟也來了举娩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晓铆,沒想到半個月后勺良,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡骄噪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年尚困,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片链蕊。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡事甜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滔韵,到底是詐尸還是另有隱情逻谦,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布陪蜻,位于F島的核電站邦马,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏宴卖。R本人自食惡果不足惜滋将,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望症昏。 院中可真熱鬧随闽,春花似錦、人聲如沸肝谭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽攘烛。三九已至魏滚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間医寿,已是汗流浹背栏赴。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留靖秩,地道東北人须眷。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像沟突,于是被迫代替她去往敵國和親花颗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 一惠拭、簡介 1. D3是什么扩劝? D3(或D3.js) 是一個用來使用Web標(biāo)準(zhǔn)做數(shù)據(jù)可視化的JavaScript庫庸论。...
    朝朝_c53e閱讀 829評論 0 2
  • d3 (核心部分)選擇集d3.select - 從當(dāng)前文檔中選擇一系列元素。d3.selectAll - 從當(dāng)前文...
    謝大見閱讀 3,451評論 1 4
  • 2. 我為什么用D3棒呛? 1)結(jié)合HTML聂示,SVG,CSS簇秒,D3可以圖形化的鱼喉,生動的展現(xiàn)數(shù)據(jù)。是目前最流行的數(shù)據(jù)可視...
    奮斗的小鳥cx閱讀 1,171評論 0 0
  • 1.發(fā)現(xiàn)故事 本課講述可視化用到的:敘事結(jié)構(gòu)數(shù)據(jù)收集過程數(shù)據(jù)處理 2.新聞方法 給可視化添加語境圍繞數(shù)據(jù)進(jìn)行敘事 ...
    esskeetit閱讀 2,841評論 0 2
  • 技術(shù)分享——用D3.js框架V5版本入門基礎(chǔ) 一趋观、前言 ? 在最近公司項目中扛禽,因為需求原因需要使用D3.js實(shí)...
    DemoGan閱讀 1,385評論 0 1