A. 數據可視化:使用D3js創建動畫地圖,發射動畫
演示頁面
B. 初識 D3.js :打造專屬可視化
隨著現在自定義可視化的需求日益增長,Highcharts、echarts等高度封裝的可視化框架已經無法滿足用戶各種強定製性的可視化需求了,這個時候D3的無限定製的能力就脫穎而出。
如果想要通過D3完成可視化,除了對於D3本身API的學習, 關於web標準的HTML, SVG, CSS, Javascript 和 數據可視化的概念以及標准都是需要學習的。這無疑帶來了較高的學習門檻,但這也是值得的,因為掌握 D3 後,我們幾乎可以實現任何 2d 的可視化需求。
本文通過對D3核心模塊分析以及進行具體案例實踐的方式,來幫助初學者學習了解D3的繪圖思路。
D3的全稱是 Data-Driven Documents(數據驅動文檔),是基於數據來操作文檔的 JavaScript 庫,其核心在於使用繪圖指令對數據進行轉換,在源數據的基礎上創建新的可繪制數據, 生成SVG路徑以及通過數據和方法在DOM中創建數據可視化元素(如軸)。
相對於Echats等開箱即用的可視化框架來說,D3更接近底層,它可以直接控制原生的SVG元素,並且不直接提供任何一種現成的可視化圖表,所有的圖表都需我們在它的庫里挑選合適的方法構建而成,這也大大提高了它的可視化定製能力。而且D3 沒有引入新的圖形元素,它遵循了web標准(HTML, CSS, SVG 以及 Canvas )來展示數據 ,所以它可以不需要依賴其他框架獨立運行在現代瀏覽器中。
在V4版本後,D3的 API 現在已經被拆分成一個個模塊,我們可以根據自己的可視化需求進行按需載入。根據泛義可以將D3 API模塊分為以下的幾大類: DOM操作、數據處理,數據分析轉換、地理路徑,行為等 。
這里我們主要對 D3-selection 和 D3-scale 模塊進行解析:
D3-selection (選擇集) 是 D3js的核心模塊,主要是用來進行選擇元素,設置屬性、數據綁定,事件綁定等操作。
選擇元素: D3-selection 提供了兩種方法來獲取目標元素,d3.select():返回目標元素的第一個節點,d3.selectAll():返回目標元素的集合,乍一看有點類似原生API 的 querySelector 和 querySelectorAll,但是 d3.select 返回的是一個 selection 對象,querySelector 返回的是一個 NodeList 數組。通過控制台列印的信息,可以看到 selection 下的 groups 存放了所有選擇的元素集合,parents 存放了所有選中元素的父節點。
設置屬性或者綁定事件: 我們不需要關心 groups 的結構是怎麼樣的。當調用 selection.attr 或者 selection.style 的時候, selection 中的所有 group 的所有子元素都會被調用,group 存在的唯一影響是: 當我們傳參是一個function 的時候,例如 selection.attr('attrName', function(data, i)) 或 selection.on('click', function(data, i)) 時, 傳遞的 function(data, i) 中, 第二個參數 i 是元素在 group 中的索引而不是在整個 selection 中的索引。
數據綁定: 實際上是給選擇的DOM元素的 __data__ 屬性賦值,這里提供了3種方式進行數據綁定:
(1)給每一個單獨的 DOM 元素調用 selection.datum:d3.select('body').datum(20) 等價於 document.body.__data__ = 20
(2)從父節點中繼承來數據, 比如: append , insert , select,子節點會主動繼承父節點的數據:
(3) 調用 selection.data() 方法,支持傳入裝有基礎數據類型的數據,也支持傳入一個function(parentNode, groupIndex)根據節點索引與數據做映射,data()方法引入了 d3 中非常重要的 join 思想:
綁定 data 到 DOM 元素, 在D3中是通過比較 data 和 DOM 的 key 值來找到對應關系的。 如果我們沒有單獨設置 key 值,那麼默認根據 data 的下標索引來設定,但是當數據順序發生改變,這個默認下標 key 值 就變得不可靠了,這時我們可以使用 selection.data(data, keyFunction) 中的第二個參數 keyFunction,根據當前的數據返回一個對應的 key 值。通過下面的圖例可以看出,不管是有一個還是多個 group(每個group 都是獨立的),只要我們保證在任意一個 group 中的 key 值是唯一的,數據一旦發生變化都會反映給對應的 DOM 元素( update 的過程):
上面提到的都是data數據和DOM元素數量相同的情況下的數據綁定,那如果data數據和DOM元素數量不相同時,我們來看看 D3 又是如何進行數據綁定的:現在終於可以來介紹 D3-selecion 模塊的核心 Join 思想了,這個思想簡單來說就是 「不應該告訴D3去怎麼創建元素, 而是告訴D3,.selectAll() 得到的 selecion 集合應該和 .data(data) 綁定的數據要怎麼一一對應」。
從上圖可以看出,在進行 d3.data(data) 數據綁定的時候,會產生三種狀態的選擇集:
用 Join 的方式來理解意味著,我們要做的事情僅僅是聲明 DOM集合和數據集合之間的關系, 並且通過處理三個不同狀態的集合 enter、update 、 exit 來描述這種關系。這種方式可以大大簡化我們對DOM元素的操作,我們不需要再用 if 和 for 循環的方式來進行復雜的邏輯判斷,來得到我們需要得到的元素集合。並且在處理動態數據的時候,可以通過處理這三種狀態,輕松的展示實時數據和添加平滑的動態交互效果。
D3-scale (比列尺) 提供多種不同類型的比例尺。經常和 D3-axis 坐標軸模塊一起使用。
D3-scale 提供了多種連續性和非連續性的比例尺,總體可以將他們分為三大類:
常用的一些比例尺:
(1)d3-scaleLinear 線性比例尺(連續性輸入和連續性輸出)
可以看出,調用d3.scaleLinear()可以生成線性比例尺,domain()是輸入域,range()是輸出域,相當於將domain中的數據集映射到range的數據集中。
使用示例:
映射關系:
(2)d3-scaleTime 時間比例尺(連續性輸入和連續性輸出)
時間比例尺與線性比例尺類似,只不過輸入域變成了一個時間軸。正常我們使用比例尺都是個正序的過程,但是D3也提供了invert()以及invertExtent()方法,我們可以通過輸出域中的具體值得出對應輸入域的值。
使用示例:
(3)d3.scaleQuantize 量化比例尺(連續性輸入和離散性輸出)
量化比例尺是將連續的輸入域根據輸出域被分割為均勻的片段,所以它的輸出域是離散的。
使用示例:
映射關系:
(4)d3. scaleThreshold 閾值比例尺(連續性輸入和離散性輸出)
閾值比例尺可以為一組連續數據指定分割閾值,閾值比例尺默認的 domain:[0.5] 以及默認的 range:[0, 1] ,因此默認的 d3.scaleThreshold() 等價於 Math.round 函數。 閾值比例尺輸入域為 N 的話,輸出域必須為 N + 1,否則比例尺對某些值可能會返回 undefined,或者輸出域多餘的值會被忽略。
使用示例:
存在三種映射關系:
a. 當domain和range的數據是 N : N+1
b. 當domain和range的數據是 N : N + 大於1
c. 當domain和range的數據是 N + 大於0 : N
(5)d3.scaleOrdinal 序數比例尺(離散性輸入和離散性輸出)
與scaleLinear等連續性比例尺不同,序數比例尺的輸出域和輸入域都是離散的。
使用示例:
存在三種映射關系:
a.當domain和range的數據是一一對應
b.當domain少於range的數據
c.當domain多於range的數據
通過以上的學習,應該對d3是如何操作DOM以及坐標軸的數據映射為相應的可視化表現有了一定的了解,下面我們來實際運用這兩個模塊,來實現我們常見的可視化圖表:柱狀圖。
(1)首先添加一個SVG元素。
(2)根據我們上面說到 d3.scale 模塊以及 d3.axis 模塊繪制坐標軸,d3.scaleBand() 叫做序數分段比例尺,類似我們說的 d3.scaleOrdinal() 序數比例尺,但是它支持連續的數值類型的輸出域,離散的輸入域可以將連續的范圍劃分為均勻的分段。這里再講一個細節,在繪制網格的時候,我們並沒有額外添加 line 元素來實現,而是通過 d3.axis 坐標軸模塊的 axis.ticks() 方法對坐標軸刻度進行了設置,通過 tickSIze() 設置了刻度線長度,來模擬和圖表寬度相等的網格線,並且還可以通過 tickFormat() 對Y軸刻度值進行格式化轉換。
(3)坐標軸繪制好了後,我們通過數據綁定來繪制與之對應的矩形(rect)元素了。
(4)這個時候柱狀圖已經基本繪制好了,我們再豐富內容展示,添加標簽、標題等提示信息。
(5)最後我們通過給柱子綁定監聽事件,實現tooltips的信息浮層交互。
通過對 d3.selection 、d3.scale 以及 d3.axis等模塊的學習,我們已經可以繪制出常用的柱狀圖等圖表,我們也可以通過d3提供的其他模塊繪制出更加復雜的可視化效果,例如通過 d3-hierarchy(層級模塊) 實現層級樹圖可視化,d3-geo(地理投影) 實現地圖數據可視化等,本文講解的內容還只是D3庫的冰山一角。所以等我們掌握了D3後,限制我們實現可視化的不再是技術而是想像力。
C. D3.js畫圖:3D動態餅圖(齒輪圖)
通常畫可視化圖的工具很多,除了d3.js,還有echarts.js等。
通過比較,看起來ECharts.js更容易上手,但是因為我需要更靈活更符合個性定製化的工具,所以選了d3.js。
經過一段時間的磨煉,從折線圖、閉合路徑圖、蜂窩圖、直角坐標、極坐標都玩了個遍。
那這次就來個3D的吧,其實d3.js做3D的圖不是很容易的,有更好的選擇,但我認准了d3.js,一條道走到黑吧(想起高中數學老師說的話,當你解題解到一半時發現有更好的辦法,不,趕緊忘掉,接著當前的方法,只要方法沒錯,總能解出來,也許會傻一點,但是一定會有正確的結果;如果中途放棄,也許另一個方法更快更聰明,但也許更慢或者錯誤,不算到最後,誰都不知道誰最准確。我選擇相信他的話,於是。。。我成了程序員O(∩_∩)O哈哈~)。
有人鄙視拿來主義,要我說,你能拿來那是你的本事,如果還能在此基礎上做出更好的東西,何樂而不為呢?
每個人時間有限,每個項目也有deadline,不可能從每一個螺絲釘怎麼擰開始學起,不然怎麼會有那麼多五花八門的框架,會有封裝好的組件和介面,正因為有人已經做了前期工作,所以時間才能省下來做更有意義的事情,這就是站在巨人肩上的道理所在吧。
但是我們得明白拿來的東西的原理,以及出了問題該怎麼解決的能力。然後才能做出更厲害的東西。
首選當然是官網的例子咯,目測搜了一圈,終於找到一個3D Donut。就是你了,我的巨人。
把該地址的donut3d.js拷貝下來作為畫3D餅圖的基礎js,待會會在此基礎上修改,以滿足我的要求(長的像齒輪的要求)。
那我們就一睹她的芳容吧。
如果這張圖符合你的要求,那就打住,不用往下看了,直接看官網例子即可。
注意d3版本的問題,如果你用d3.v3.js,恭喜你,啥也不用改,直接拿來用;如果你用d3.v5.js,那稍微改下方法,比如d3.v5.js沒有d3.layout,所以d3.layout.pie改成d3.pie。我就是那個不幸的人,用的d3.v5.js。沒關系,改起來很快,運行下,看哪裡有錯,就改哪裡,O(∩_∩)O哈哈~so easy!
還是先上個我已經改好之後的3D餅圖(齒輪圖)吧,方便說明。
其實顯示的時候是個動態的,一節一節顯示出齒輪的。
背景是黑乎乎的,據說現在流行黑乎乎的背景,顯得有科技感,技術也要趕時髦啊,我這么fashion的人,做出來的東西也要fashion啊O(∩_∩)O~
從以上分析可以看出,難啃的骨頭在第4點。這個圖斷斷續續花了3天時間才搞定,為啥是斷斷續續呢,因為還有其他工作要做嘛,你懂得。
那就按順序一條一條實現,總有一天我們的願望都能實現!
首先新建svg及設置寬高。
我是切分成了32個小齒輪(包含透明的),如果你想分的更細,可以分成40或50個,只要你覺得好看就行。
既然要分成32個小立體快,那數據也要切分成32個。
通過以上處理,把數據整合成可以生成齒輪的完整數據dataset。
如果不增加左側面和右側面,那調用donut3d.js的draw方法後,會生成什麼樣的圖形呢?
請各位仔細看。
是不是有種被掏空的感覺?如果你覺得這樣挺好看,那也行,打住吧,後面就不用再看了;如果你想補齊其他面,請耐心往下看。
經過觀察和比較,增加左側面和右側面就能填滿空虛的心啦啦啦~
這次要在donut3d.js這個巨人身上添磚加瓦咯。
然後再用新增加的兩個方法畫出左右側面。
終於填滿需要的每一面,看上去像個立體齒輪圖了。
這個圖是很久之前做的,當時花了很長時間調試,每一個面有4條邊,定位2個點,再加上高度和內半徑,就可以計算出4個點,然後就可以畫出4條邊,最後填充顏色,一個面就完成了。
最近整理文檔時覺得有必要寫出來,方便以後查閱和探討,也告訴自己積累是一個長期過程,不急不躁,慢慢來,一步一步完成既定目標,總有一天你會走遍技術的每個角落。
現在我整理成vue組件,傳一個百分比的參數,就可以顯示3D齒輪圖了,我的3D齒輪圖也成巨人啦。
D. 前端用d3.js繪圖如何做到數據實時更新到界面
你可以看看這個,網頁鏈接
E. 《D3.js數據可視化實戰手冊》epub下載在線閱讀,求百度網盤雲資源
《D3.js數據可視化實戰手冊》([加]Nick Qi Zhu)電子書網盤下載免費在線閱讀
資源鏈接:
鏈接:https://pan..com/s/1rUVmSL08GciR6wS8sLC63Q
書名:D3.js數據可視化實戰手冊
作者:[加]Nick Qi Zhu
譯者:楊銳
豆瓣評分:7.0
出版社:人民郵電出版社
出版年份:2014-9
頁數:294
內容簡介:如今這個互聯網時代,人們每天都產生海量的數據,如果直接面對這些數據,可能讓人無從下手。將數據可視化,用形象立體的形式將其展現,有利於分析其中的關聯,攫取可能存在的商業機會。本書意圖通過大量的示例和代碼,向讀者講述如何利用D3.js來實現數據可視化。只要讀者了解JavaScript,就能完全掌握本書的內容。
F. d3.js直方圖與坐標軸基礎
這里講一下怎麼樣用d3.js,輸入一個數據list,根據數據畫一個帶有坐標軸的簡單直方圖.
以下是目標效果.
引入d3.
<script src="//d3js.org/d3.v4.min.js"></script>
畫矢量圖需要畫布,首先,創建新svg:
我的數據為一個數組: var dataset = [ 25, 6, 21 , 17 , 13 , 9, 6, 2, 20 ];
我想讓我的直方圖向右,縱向排列.
每一個矩形的x向長度既表示了數據的大小.
那麼第一個要解決的問題就是,怎麼把原始數據換算成像素,肯定不能直接畫25px,6px...
這個時候就需要一個比例尺了.
d3提供的 連續比例尺 可以這么寫:
定義變數linear為一個連續比例尺,定義域.domain,值域.range.
在這里,定義域 .domain([0, d3.max(dataset)])是指,我比例尺輸入的數據最小為0,最大是原dataset里最大的那個數(25),所以輸入比例尺的定義域為0到25,換算後的值域為0到400px,既——數據0對應0px,數據25對應400px.
有了長度比例尺,就可以畫直方圖了.
在這里,先定義了每一個矩形框框的高度為30px,
.data() 綁定數據dataset
.enter() 方法是專門用在這種,根據輸入數據動態新建元素的情況下的,具體可以參考 官方說明 :
所以,在這里,我們既是根據輸入 dataset 來新建 <rect> ,
怎麼根據呢?
屬性設置裡面:
表示的是,對於每一個新建的矩形 <rect> ,x坐標為0,y坐標為序號*矩形高度+5px. (5px是矩形之間的空格)
可以理解為,在(0,0)放置一個高度為30px的矩形,再在(0,35)放一個,再在(0,70)放一個,再在(0,105)放一個...
而矩形的寬度要和我們的數據保持一致,所以width屬性,輸入了一個無名函數
這個函數是什麼意思呢,當選擇集需要使用被綁定的數據時,常需要這么使用。其包含兩個參數,其中:
有了直方圖的矩形,我們現在來畫一個 坐標軸 .
坐標軸有4種:
分別是什麼樣子的呢,我們來試一試.
在API使用規范里這樣寫到:
意思是,在使用坐標軸的時候,必須先添加一個 <g> 元素,再 .call(axis) 調用axis. 而默認坐標軸都是從原點(0,0)開始畫,如果需要調整位置,在屬性 transform 里設置 translate(x,y)
所以,我們測試一下在(30,30)畫一個 axisTop .
我們得到結果如下:
而每個坐標軸是由哪些部分組成的呢:
除此之外,我們還可以改樣式.
我們知道了每一個坐標軸有一個 <path class="domain> ,我們可以試試更改樣式.
而且在每一個 <g class="tick"> 內部,有一個 <line> 和一個 <text> .
<line> ,這兩個元素的可用屬性可以參考 line , text
最終,實現效果:
G. d3.js可以處理多大的數據量
處理數據用d3js過分了,因為數據量大會造成讀取速度慢,這樣對於網頁來說太致命了內,所以容一般情況下是處理好之後調用。
但是說處理的話,大概同時繪制幾千個點,電腦好一點的話上萬個點就到極限了,不然讀取速度太慢。
H. d3.js和d3.min.js有什麼區別
d3.js是開發期間使用的,裡面的代碼展示是用戶友好的,便以閱讀及調試。而內d3.min.js是前者經過代容碼壓縮而成的,文件較小,用以在應用發布後部署,可以節省網路傳輸流量,但相應的比較難以閱讀。
本質沒有區別,只是一個適合在開發時使用,一個在應用部署上線時使用。
I. js根據時間范圍生成時間刻度數據
使用d3繪制時間軸圖表,不可避免的涉及到動態變動時間刻度,根據業務需求需要調整查看不同的時間粒度數據。如果後台數據非連續數據,需要前端自己處理的話,就得自己根據時間范圍創建時間刻度數據。
以上方法,親測有效。注意一定要使用固定的時間作為基準點,否則以天為刻度時,會有時區差異。以秒和分鍾作為時間粒度,沒問題,因為是更小一級的單位,進行整除運算沒有問題。
時間桶的概念,就是以該間隔作為時間刻度
為什麼我會前端處理時間軸數據?
相信如果使用過d3進行時間軸圖表定製的同學,一定使用過 d3.scaleTime 或者 d3.scaleUtc 進行時間軸比例尺的繪制,它的智能之處,就是可以根據你的時間范圍,動態的創建出適合當前顯示區域坐標系的時間刻度數據,就算你的數據是不連續的,也沒有問題。但是結合brush刷取api進行使用的時候就用問題了,當初始化數據不符合具體的刷取機制,進行刷取范圍的默認設置,就會出現繪制圖表不連續,移動刷取框更新圖表錯誤的問題。(具體原因未知,有大神有相應的認知可以在評論群告知一波,非常感謝)
基於以上問題,我通過自己創建時間刻度,使用 d3.scaleLinear 線性比例尺,結合brush進行縮放x軸,就沒有任何問題,因為我的數據處理後都是連續的,每個時間刻度已經固定,規避了上面的問題。
J. 想要實現數據的可視化,打算用d3.js,正在學習js的基礎知識,可是網上又有說要用struts2,spring
D3是目前最流行的JavaScript可視化圖表庫之一,D3的圖表類型非常豐富,並且支持SVG格式,因此應用十分廣泛,也有很多圖表插件基於D3開發,比如MetricsGraphics.js,在D3上構建的數據圖表非常強大。D3的特點允許綁定任意數據到DOM,將數據驅動