D3 學習筆記二:創(chuàng)建柱狀圖葫男,第一部分

(原文地址:https://bost.ocks.org/mike/bar/善涨,原文作者:Mike Bostock

簡介:出于個人學習目的,計劃將 D3 的學習資料逐步翻譯為系列文章亏镰,鑒于本人水平有限,如有不到或錯誤之處拯爽,歡迎大家指正索抓,謝謝!

概述

如果你有一小撥數(shù)據(jù)毯炮,一個數(shù)組:

var data = [4, 8, 15, 16, 23, 42];

簡而來說逼肯,一個柱狀圖就是比例上來正確呈現(xiàn)該數(shù)據(jù)的恰當圖表。本篇教程將介紹如何使用 D3 Javascript 函數(shù)庫來創(chuàng)建柱狀圖桃煎。首先篮幢,我們將介紹 HTML 版的原始數(shù)據(jù)法,然后是更復雜的 SVG 方法备禀,最后提供一個帶動態(tài)過渡的版本洲拇。

本篇教程假設您具備網(wǎng)頁開發(fā)的基礎知識:了解如何編輯頁面并用瀏覽器查看、如何加載 D3 程序庫等曲尸。你也會發(fā)現(xiàn)簡單的從 CodePen 模板修改是最簡單的開始方式赋续。

選擇一個元素

在一般的 JavaScript 編程中,通常一次只能處理一個元素另患,比如要創(chuàng)建一個 div 元素纽乱、設置它的內(nèi)容,然后將其添加到body

var div = document.createElement("div");

div.innerHTML = "Hello, world!";
document.body.appendChild(div);

有了 D3 (當然 jQuery 等類似函數(shù)庫也一樣)昆箕,您可以通過選擇器來實現(xiàn)同樣的功能鸦列,通過大批的處理選擇結(jié)果并賦予它們豐富的操作功能,您可以任意處理器中想要的內(nèi)容而不用重復數(shù)寫代碼鹏倘。雖然這看起來像一個小小的挑戰(zhàn)薯嗤,消滅循環(huán)和其他程序流控制可以讓您的代碼更加整潔。

選擇器可以通過很多種方式實現(xiàn)纤泵,最常見的是通過請求一個通過特殊符號構(gòu)建的選擇符字符串(比如 div.foo 等)骆姐,比如創(chuàng)建一個單一元素的選擇符:

var body = d3.select("body");
var div = body.append("div");

div.html("Hello, world!");

您也可以同樣的處理多種元素:

var section = d3.selectAll("section");
var div = section.append("div");

div.html("Hello, world!");

修改操作的串接

另一種方便的選擇法是通過對選擇器的串接:選擇函數(shù),比如 selection.attr 返回當前的選擇。這樣玻褪,您可以繼續(xù)對該元素進行操作肉渴,比如設置 body 的背景色和文字顏色:

var body = d3.select("body");

body.style("color", "black");
body.style("background-color", "white");

bodybody带射,body同规!”反復的呼叫 body 法可以通過如下的操作串接消除:

d3.select("body")
  .style("color", "black")
  .style("background-color", "white");

注意,我們再也沒有使用一個 var 類型聲明窟社,在進行畢要的操作之后券勺,選擇結(jié)果可以被丟棄。操作串接讓您可以縮短代碼桥爽,減少過多用于變量命名的時間消耗朱灿。

在學到方法串接的好處之后我們要留意昧识,大多數(shù)操作都返回同樣的選擇內(nèi)容钠四,然而有些方法卻不這樣!比如跪楞,selection.append 返回僅包含新元素的選擇缀去,從而讓您可以對新元素進行串接操作:

d3.selectAll("section")
  .attr("class", "special")
  .append("div")
    .html("Hello, world!"); // 注意:本教程中刻意使用縮進來呈現(xiàn)結(jié)構(gòu)關系。

方法串接只能讓選擇內(nèi)容不斷沉入文檔結(jié)構(gòu)內(nèi)甸祭,此時使用 var 可以保留中間過程從而返回原狀態(tài):

var section = d3.selectAll("section");

section.append("div")
  .html("First!");

section.append("div")
  .html("Second.");

手動創(chuàng)建圖表

現(xiàn)在缕碎,假設您需要拋棄 JavaScript 而寫一個柱狀圖,反正在數(shù)據(jù)表中只有六個數(shù)據(jù)池户,所以手工寫幾個 div 并不是復雜的事情咏雌,根據(jù)數(shù)據(jù)設置好它們的寬度,不就完成了:

<!DOCTYPE html>
<html>
<head>
  <style>
  .chart div {
    font: 10px sans-serif;
    background-color: steelblue;
    text-align: right;
    padding: 3px;
    margin: 1px;
    color: white;
  }
  </style>
</head>
<body>
  <div class="chart">
    <div style="width: 40px;">4</div>
    <div style="width: 80px;">8</div>
    <div style="width: 150px;">15</div>
    <div style="width: 160px;">16</div>
    <div style="width: 230px;">23</div>
    <div style="width: 420px;">42</div>
  </div>
</body>
</html>

結(jié)果顯示如下:

本圖用一個 div 做容器校焦,每個柱子采用一個子節(jié)點 div赊抖,子 div 擁有藍色背景色與白色前景色,呈現(xiàn)出了向右對齊的文字標簽寨典。當然您可以移掉容器 div 而讓實現(xiàn)更簡潔氛雪,但一般來說,您的頁面在圖標之外還有其他內(nèi)容耸成,表格容器可以讓您不影響其他頁面的情況下布局和樣式化圖表报亩。

自動創(chuàng)建圖表

手工繪制并不適合現(xiàn)實中絕大多數(shù)數(shù)據(jù)源,本文的目的正是教您如何自動通過數(shù)據(jù)創(chuàng)建圖表井氢,所以讓我們從一個僅包含一個類別為 chartdiv 的空頁面開始弦追,用 D3 創(chuàng)建同樣的圖表:

d3.select(".chart")
  .selectAll("div")
    .data(data)
  .enter().append("div")
    .style("width", function (d) { return d * 10 + "px"; })
    .text(function(d) {return d;});

雖然部分代碼看起來熟悉,我們引入了一個新概念:數(shù)據(jù)接合花竞。下面讓我們將它拆開劲件,將以上簡潔代碼寫成原本的加長格式,從而展現(xiàn)它的工作原理。

首先寇仓,我們使用類別選擇器得到圖表容器:

var chart = d3.select(".chart");

下一步举户,我們通過定義需要接合的部位來接合數(shù)據(jù):

var bar = chart.selectAll("div");

數(shù)據(jù)接合,便是在數(shù)據(jù)改變時遍烦,使用標準模式來創(chuàng)建俭嘁、更新和銷毀元素。這感覺上有些奇怪服猪,好處是您可以只學此單一的模式來改變頁面供填,所以無論您構(gòu)建靜態(tài)圖表還是動態(tài)漸變圖表時都可以保持代碼一致,就像您選擇希望存在的元素時的初始選擇器罢猪。(見“使用接合思考”)近她。

下一步,我們使用 selection.data 將數(shù)據(jù)接合到選擇結(jié)果上:

var barUpdate = bar.data(data);

因為我們知道選擇結(jié)果為空膳帕,其返回的 updateexit 選擇結(jié)果同樣為空粘捎,我們只需要處理包含了不存在的新數(shù)據(jù)的 enter 選擇結(jié)果。

var barEnter = bar.Update.enter().append("div");

下面我們根據(jù)關聯(lián)的數(shù)據(jù)為每個新柱子設置寬度 d

barEnter.style("width", function (d) {
  return d * 10 + "px";
});

因為這些元素是通過數(shù)據(jù)接合創(chuàng)建的危彩,每個柱子已經(jīng)綁定了數(shù)據(jù)攒磨,我們通過傳遞一個計算寬度風格的函數(shù)來恰當設置柱子的尺寸。

最后汤徽,我們使用一個函數(shù)來設置每個柱子的文字標簽:

barEnter.text(function (d) {
  return d;
});

D3 的選擇器操作符娩缰,比如 attrstyle谒府,property拼坎,允許您將數(shù)值設置為常量(每個選擇元素相同)和函數(shù)(每個單獨計算)兩種方式。如果某個屬性必須基于元素綁定的數(shù)據(jù)計算完疫,那么就使用函數(shù)來實現(xiàn)泰鸡,如果每個元素都相同,那么就使用字符串或數(shù)值來賦值趋惨。

用縮放匹配畫幅

以上代碼的軟肋鸟顺,是我們使用固定數(shù)字 10 來轉(zhuǎn)換每個柱子和數(shù)據(jù)的關系。該數(shù)字應當取決于數(shù)據(jù)集內(nèi)容的分布區(qū)域(0到42)和圖表所定制的寬度(420)器虾,當然讯嫂,針對以上圖表,我們選擇 10 是沒有問題的兆沙。

我們可以使用 線性縮放 功能讓以上數(shù)量關系更加明確欧芽,并消滅魔術(shù)數(shù)字 10,D3 的縮放功能輸入為數(shù)據(jù)范圍及顯示尺寸:

var x = d3.scale.linear()
  .domain([0, d3.max(data)])
  .range([0, 420]);

雖然葛圃,在這里 x 看起來像個對象千扔,它也是一個包含根據(jù)輸入數(shù)值轉(zhuǎn)換原始數(shù)據(jù)的函數(shù)憎妙。比如,傳入 4 可以返回 40曲楚, 輸入 16 返回 160厘唾。為了使用新的縮放,我們將手寫的乘法轉(zhuǎn)換代碼變?yōu)楹艚性摵瘮?shù):

d3.select(".chart")
  .selectAll("div")
    .data(data)
  .enter().append("div")
    .style("width", function (d) {
      return x(d) + "px";
    })
    .text(function (d) {
      return d;
    });

下一篇:創(chuàng)建柱狀圖龙誊,第二部分

本篇原始柱狀圖的呈現(xiàn)很容易實現(xiàn)抚垃,但很顯然也是有限的。柱狀圖應當有格線來輔助數(shù)據(jù)對比趟大,您也可能更喜歡垂直的柱狀圖鹤树,或者您想要其他不同的圖表類型,比如餅狀圖和流狀圖等逊朽。為了更好的視覺表達罕伯,您需要下一篇我們將呈現(xiàn)的 SVG 技術(shù)。

個人筆記

本篇教程之中叽讳,D3 的原創(chuàng)作者通過“非圖表”技術(shù)展示了 D3 的選擇器與修改器等功能追他,然而,選擇器與修改器僅僅是 D3 框架之中最基礎部分的功能绽榛,作者書寫本教程的目的應該是為讀者打下開發(fā)的基礎湿酸,而實際并未深入 D3 作為圖形繪制系統(tǒng)的實質(zhì)核心內(nèi)容婿屹。

使用 div 繪制圖表灭美,可能是十年前 Web 技術(shù)沒有發(fā)展到 HTML5 時,使用網(wǎng)站進行數(shù)據(jù)呈現(xiàn)的“權(quán)宜之計”昂利。然而届腐,當今 HTML5 技術(shù)將 Web 技術(shù)提高到了一定的高度,通過 svgcanvas 標簽蜂奸,如今的瀏覽器已經(jīng)成為了強大的矢量繪圖工具(當然犁苏,還有不可忽略的 webgl 圖形接口)。

D3 在 v3 版本及之前扩所,還是一個一體化開發(fā)的普通插件围详,在 v4 到來之時,D3 進行了技術(shù)上的革新祖屏,將原本一體的 Javascript 代碼拆分成了幾十個可以獨立使用的模塊助赞,并已經(jīng)完整提供了對 svg 繪圖組件的全面支持。在 v5 到來之后袁勺,D3 完整支持了 canvas 標簽雹食,并且提供了兩者可以隨意選擇的技術(shù)方案。

我們作為 D3 框架的學習者期丰,特別是掌握了 jQuery 插件使用方法的讀者們肯定感覺到了內(nèi)容的枯燥群叶。但是吃挑,作為未來的 D3 應用者,我們會在未來的開發(fā)使用中越來越發(fā)現(xiàn)這些基礎知識的重要性街立,因為每一幅通過 D3 繪制的 Web 圖表都必須使用以上所描述的內(nèi)容舶衬。

在下一篇,作者將深入 D3 的 svg 支持功能之中赎离,帶領大家進入真正的 D3 領域约炎,來體會高效的繪圖技術(shù)和接口。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蟹瘾,一起剝皮案震驚了整個濱河市圾浅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌憾朴,老刑警劉巖狸捕,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異众雷,居然都是意外死亡灸拍,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門砾省,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸡岗,“玉大人,你說我怎么就攤上這事编兄⌒裕” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵狠鸳,是天一觀的道長揣苏。 經(jīng)常有香客問我,道長件舵,這世上最難降的妖魔是什么卸察? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮铅祸,結(jié)果婚禮上坑质,老公的妹妹穿的比我還像新娘。我一直安慰自己临梗,他們只是感情好涡扼,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著夜焦,像睡著了一般壳澳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茫经,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天巷波,我揣著相機與錄音萎津,去河邊找鬼。 笑死抹镊,一個胖子當著我的面吹牛锉屈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播垮耳,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼颈渊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了终佛?” 一聲冷哼從身側(cè)響起俊嗽,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎铃彰,沒想到半個月后绍豁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡牙捉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年竹揍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邪铲。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡芬位,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出带到,到底是詐尸還是另有隱情昧碉,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布阴孟,位于F島的核電站晌纫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏永丝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一箭养、第九天 我趴在偏房一處隱蔽的房頂上張望慕嚷。 院中可真熱鬧,春花似錦毕泌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愿题。三九已至蛙奖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間杆兵,已是汗流浹背雁仲。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工琐脏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留攒砖,地道東北人日裙。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓吹艇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親昂拂。 傳聞我的和親對象是個殘疾皇子掐暮,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

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

  • 1.發(fā)現(xiàn)故事 本課講述可視化用到的:敘事結(jié)構(gòu)數(shù)據(jù)收集過程數(shù)據(jù)處理 2.新聞方法 給可視化添加語境圍繞數(shù)據(jù)進行敘事 ...
    esskeetit閱讀 2,791評論 0 2
  • d3 (核心部分)選擇集d3.select - 從當前文檔中選擇一系列元素政钟。d3.selectAll - 從當前文...
    謝大見閱讀 3,433評論 1 4
  • 1. 動畫與互動 在敘事結(jié)構(gòu)中全面應用創(chuàng)意D3如何幫你在可視化圖表中添加動畫與互動用地理特征創(chuàng)建D3地圖了解別人如...
    esskeetit閱讀 831評論 1 0
  • 搜集了網(wǎng)上一些常用的開發(fā)小技巧养交,集中到一起看-,- 1 TableView下面的那些cell的空顯示 2 Sc...
    不會學習的睿睿閱讀 216評論 0 0
  • 詞丨印安淋 答答屋檐雨滴響 空調(diào)的暖讓我推開了窗 滿地雪白映入眼簾 我要裹緊我的衣裳 冷 是沒有關掉保險的槍 ...
    歌詞寫作印安淋閱讀 330評論 0 0