Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
creenHunter Pro7是一款非常簡(jiǎn)單又實(shí)用的屏幕截圖、錄制工具。它可以快速捕獲高清屏幕截圖,也可以開(kāi)啟視頻錄制功能,記錄并制作成視頻。軟件功能十分強(qiáng)大,除了基本常見(jiàn)的功能外,它還支持選取區(qū)抓取。用戶可以自定義選擇矩形區(qū)域、活動(dòng)區(qū)域或全屏來(lái)進(jìn)行捕獲,來(lái)保存為BNP或JPG格式。通過(guò)設(shè)定鼠標(biāo)指針和延時(shí)功能,可以制作演示教學(xué)用的Gif動(dòng)態(tài)圖像。軟件還具有獨(dú)特的定時(shí)抓取功能,在設(shè)定時(shí)間后,軟件就會(huì)自動(dòng)抓取電腦屏幕畫(huà)面,并且自動(dòng)生成文件名稱,并轉(zhuǎn)存為JPG、GIF、PNG、BMP等圖片格式。
下載地址:https://www.downkuai.com/soft/118210.html
1、解壓軟件壓縮包、雙擊運(yùn)行ScreenHunter7Pro.exe程序
2、在程序主界面中有個(gè)相機(jī)和攝影機(jī)的圖標(biāo),分別為捕獲和錄制
3、點(diǎn)擊相機(jī)圖片,鼠標(biāo)會(huì)進(jìn)入選區(qū)狀態(tài),劃分圖片捕獲區(qū)域
4、捕獲的區(qū)域會(huì)自動(dòng)保存在編輯器中
5、點(diǎn)擊左上角文件>另存為>選擇保存的路徑,即可保存截圖
1、圖像編輯器中增加高質(zhì)量的畫(huà)圖工具和注釋。
2、新按鈕打開(kāi)圖片收藏夾。
3、ScreenHunter綠色版一鍵添加到開(kāi)機(jī)啟動(dòng)。
4、加強(qiáng)打印設(shè)置。
5、其他優(yōu)化功能。
6、豐富的截取功能,包括:自定義區(qū)域、窗口、控件、菜單、超長(zhǎng)滾動(dòng)頁(yè)面、攝像頭、多對(duì)象、甚至文字的截取。
7、可鎖定需要截取的窗口,甚至可截取“最小化”的窗口內(nèi)容。
8、可截取Dos程序、DirectX游戲、視頻、橢圓、圓形等等各類圖像。
9、支持多顯示器。
10、延遲截取、計(jì)劃截取、周期循環(huán)截取。
11、加入多種特效,包括:標(biāo)題、水印、邊框陰影,可自動(dòng)縮放圖像及加入色彩渲染。
12、多種輸出格式,包括:PDF、JPEG、GIF、PNG、TIFF,可輸出到剪切板、E-Mail或自動(dòng)命名保存。
以各種格式保存圖像。
將屏幕捕獲發(fā)送到電子郵件。
捕獲DirectX和屏幕保護(hù)程序。
捕獲程序MS-DOS的屏幕。
自動(dòng)添加邊框和水印的屏幕截圖。
將所有創(chuàng)建的屏幕截圖放在單獨(dú)的窗口中。
通過(guò)滾動(dòng)從網(wǎng)頁(yè)和長(zhǎng)文檔中捕獲圖像。
從掃描儀接收?qǐng)D像。
自動(dòng)調(diào)整捕獲窗口的透明度級(jí)別。
使用內(nèi)置圖形編輯器。
支持多個(gè)監(jiān)視器。
遞歸快照和計(jì)時(shí)器快照。
自動(dòng)命名已保存的文件。
所見(jiàn)即所得印刷。
選擇“套索”風(fēng)格的任意區(qū)域。
從屏幕拍攝視頻文件。
拍攝系統(tǒng)啟動(dòng)和屏幕保護(hù)程序。
本篇文章,Rachel Andrew將會(huì)帶著大家了解下瀏覽器在CSS方面的未來(lái)動(dòng)向, 例如Flexbox行和列布局支持gap間隙屬性的標(biāo)準(zhǔn)。
這是一件令網(wǎng)站開(kāi)發(fā)人員十分振奮的事情。我們將會(huì)領(lǐng)略未來(lái)CSS發(fā)展的全新屬性和相關(guān)書(shū)寫(xiě)規(guī)范,其中一些已列入日程或在正在測(cè)試版本中進(jìn)行使用,但是你將會(huì)很快在陸續(xù)的瀏覽器發(fā)布版本中看到它們。
CSS網(wǎng)格布局引入了 grid-column-gap, grid-row-gapl和grid-gapl 等屬性,多列布局可以使用 column-gap 屬性, 因此,從Grid和Multicol規(guī)范中刪除這些屬性并將它們放入Box(盒子模型) Alignment是有意義的。在Box Alignment中處理規(guī)范布局的方式和對(duì)齊的方式。因此相關(guān)屬性的名稱改成了column-gap, row-gap和gap應(yīng)用于布局,比如flexbox布局方式。
在撰寫(xiě)本文時(shí),F(xiàn)irefox是目前唯一支持Flexbox這些新屬性的瀏覽器,預(yù)計(jì)將在Firefox 63中版本中發(fā)布(在您閱讀本文時(shí)應(yīng)該可以使用它)。 但是我希望其他瀏覽器也會(huì)效仿。 這應(yīng)該意味著您不必使用margin屬性在Flex內(nèi)容元素之間控制間距,而是可以使用網(wǎng)格布局的方式。
.flex{ display: flex: flex-wrap: wrap row-gap: 20px; column-gap: 10px; }
我們的CSS屬性和值傳對(duì)應(yīng)的是屏幕的物理屬性。例如,我們使用寬度和高度,并在元素的右上角,底部和左側(cè)設(shè)置邊距。在水平和從上到下的布局方式,這些物理屬性看起來(lái)很奇怪。舉個(gè)簡(jiǎn)單的例子,我們可以考慮下面的一個(gè)盒子模型:
.box{ height: 150 px width: 250px }
我們的盒子在屏幕上高150像素,寬250像素。即使我們將寫(xiě)入模式(writing-mode)更改為垂直模式。盒子將繼續(xù)保持原先的物理屬性,唯一的差別就是橫著擺放或者豎著擺放。
我們現(xiàn)在有了新的邏輯屬性和值,使我們能夠調(diào)整元素大小或引用它們的邊距,填充和邊框,即使寫(xiě)入模式發(fā)生變化(writing-mode)。回到我們上一個(gè)示例,我們可能希望我們的box框始終具有250像素的長(zhǎng)度,而不管方向如何。
這些新屬性是在寫(xiě)入模式下(writing-mode)運(yùn)行的方式——水平布局,在任何垂直書(shū)寫(xiě)模式下水平布局。然后我們希望它在塊維度中具有150個(gè)像素的長(zhǎng)度,常用在特定寫(xiě)入模式中顯示例如文章段落的塊狀的顯示方式。所以我們可以按如下方式調(diào)整塊我們的BOX布局:
.box { block-size: 150px inline-size: 250px }
該Box盒子模型在寫(xiě)入模式(writing-mode)下運(yùn)行。目前Firefox瀏覽器支持這些邏輯值的新特性。
Subgrids——你能夠在一個(gè)網(wǎng)格內(nèi)部繼續(xù)布局一個(gè)子網(wǎng)格,該子網(wǎng)格繼承父網(wǎng)格的相關(guān)屬性。
Grid(網(wǎng)格) level 2相關(guān)的規(guī)范正在制定中,主要增加了 subgrid(子網(wǎng)格)的新特性。
現(xiàn)在沒(méi)有任何瀏覽器支持這些新屬性,但是我相信并希望這一天能夠快點(diǎn)到來(lái)。
Initial Letter——目前僅適用WebKit的瀏覽器,是一個(gè)解決常見(jiàn)問(wèn)題的小功能。 它可以創(chuàng)建一個(gè)大的首字母沉入其后的文本中,效果如上圖。
這個(gè)CSS特性只有一個(gè)屬性值:initial-letter,使用這個(gè)屬性你需要加上webkit前綴,此屬性接受兩個(gè)參數(shù)值,第一個(gè)表示行高,第二個(gè)表示要跨越的行數(shù),如果要實(shí)現(xiàn)上圖效果,我們可以這樣寫(xiě)
h1+p: first-letter { font-weight: bold; webkit-initial-letter: 43 3; initial-letter: 43 3; }
如果您曾在設(shè)計(jì)中使用過(guò)Web字體,您需要明白這些問(wèn)題 – 您的用戶需要下載您需要使用的每種字體。對(duì)于大多數(shù)字體,您將需要常規(guī)字體,粗體和斜體版本。為了要表現(xiàn)字體的效果,您的用戶要同時(shí)下載好幾種字體。
Variable Fonts(可變字體)——無(wú)需多個(gè)文件就能通過(guò)編程方式讓單一文件適應(yīng)和生成自定義字體樣式。 OpenType Font Variations 可變字體是由微軟,谷歌,蘋(píng)果和Adobe共同開(kāi)發(fā)的技術(shù),這個(gè)功能應(yīng)用讓我們?cè)诰W(wǎng)站上使用更豐富更漂亮的字體。
要使用可變字體,您需要使用支持該功能的字體,以及支持font-variation-settings屬性的瀏覽器,現(xiàn)代瀏覽器中對(duì)這個(gè)屬性的支持非常好。要了解可變字體的可行性。可以查看Axis Praxis網(wǎng)站(axis-praxis.org),您可以在線體驗(yàn)各種可變字體并復(fù)制用于您創(chuàng)建的可變字體的css。
要查找和測(cè)試可變字體,您可以訪問(wèn) http://v-fonts. com。可變字體Twitter帳戶(http://twitter.com/variablefonts)值得關(guān)注以——發(fā)現(xiàn)新的字體版本和最新的動(dòng)態(tài)新聞。
CSS Scroll Snapping意味著您可以創(chuàng)建捕捉滾動(dòng)點(diǎn)的界面。這讓您很方便在網(wǎng)頁(yè)上實(shí)現(xiàn)與移動(dòng)應(yīng)用程序類那樣整頁(yè)滑動(dòng)效果(滑塊效果),可以在頁(yè)面之間進(jìn)行捕捉。
Scroll snapping——方便您實(shí)現(xiàn)類似APP那樣的整頁(yè)滑動(dòng)的效果。
下面的代碼創(chuàng)建了一個(gè)項(xiàng)目列表,其中父項(xiàng)具有固定高度,溢出設(shè)置為滾動(dòng)。我希望項(xiàng)目在滑動(dòng)到頂部進(jìn)行捕捉。
在父元素上,我們添加了屬性scroll-snap-type,滾動(dòng)的軸方向的值,然后是一個(gè)必需或接近的關(guān)鍵數(shù)值設(shè)置捕捉點(diǎn),因此在使用它時(shí)應(yīng)該小心您不會(huì)因?yàn)闈L動(dòng)捕捉而導(dǎo)致用戶無(wú)法滾動(dòng)到某些內(nèi)容。
在項(xiàng)目上,我們使用屬性scroll-snap-align指定要捕捉到的位置(指定元素哪一部分應(yīng)該與容器對(duì)齊)。它有三個(gè)值可選擇:start、center和end。這些是相對(duì)于滾動(dòng)方向的。如果是垂直滾動(dòng),start指的是元素的頂部邊緣。如果是水平滾動(dòng)條,它指的是左邊緣。center和end遵循相同的原則。你可以為滾動(dòng)條的不同方向設(shè)置不同的值,這兩個(gè)值之間用空格分隔開(kāi)。
ul { list-style: none; border: 5px solid rgb(126, 63, 222); border-radius: 5em; height: 300px; padding: 0; overflow-y: scroll; scroll-snap-type: y mandatory; } li { background-color: rgba(126, 63, 222,. 3); padding: 40px 20px: border-bottom: 1px solid rgb(126, 63, 222); min-height: 150px; scroll-snap-align: start; }
目前瀏覽器的支持情況
Media Queries Level 4規(guī)范為我們提供了一些有趣的新方法來(lái)檢測(cè)訪問(wèn)者正在使用的設(shè)備,以及一些有助于使Media Queries更簡(jiǎn)潔的語(yǔ)法改進(jìn),
有興趣的話可以查看這個(gè)網(wǎng)址 https://www.w3.org/TR/mediaqueries-4/#intro
人們與您的網(wǎng)站或應(yīng)用程序交互的方式正在發(fā)生變化。您的訪問(wèn)者可能正在使用鍵盤(pán)、鼠標(biāo)或可觸摸設(shè)備訪問(wèn)您的網(wǎng)站。
例如微軟Surface Book就像傳統(tǒng)筆記本電腦一樣,也有觸摸屏。因此,查看屏幕大小并不是查找用戶實(shí)際擁有的設(shè)備類型的好方法。 Media Queries level 4 介紹了交互媒體功能,使我們能夠找出用戶具有什么類型的指針,并測(cè)試此類屬性是否為懸停。
例如,如果我想為觸摸屏用戶添加一些css。我可以使用以下代碼監(jiān)測(cè)觸摸并定義相關(guān)屬性:
@media(pointer: coarse){ / *CSS rules for touch screen*/ }
我也可以監(jiān)測(cè)hover屬性,定義相關(guān)的CSS樣式屬性。
@media(hover){ /*CSS rules useful to people with devices that have hover support*/ }
這些媒體查詢?yōu)槟峁┝肆硪环N測(cè)試設(shè)備能力的方法,以便您可以很方便的為所有訪問(wèn)您的站點(diǎn)的用戶提供很好的體驗(yàn)。這個(gè)新特性除了Firefox之外的所有現(xiàn)代瀏覽器都支持。
Level 4規(guī)范還包括一些語(yǔ)法改進(jìn),因?yàn)槊襟w查詢當(dāng)前非常冗長(zhǎng) – 特別是在指定范圍時(shí),例如:
@media(min-width: 40em)and(max-width:59em){ / *CSS rules for screen sizes between 40em and 59em*/ }
新規(guī)范使我們能夠使用以下語(yǔ)法并實(shí)現(xiàn)相同的功能
@media(40em < width < 59em ){ /*CSS rules for screen sizes between 40em and 59em */ }
這個(gè)語(yǔ)法起初看起來(lái)很奇怪,但是簡(jiǎn)潔容易理解,舊的的語(yǔ)法不會(huì)消失,兩種寫(xiě)法會(huì)共存。
CSS甚至開(kāi)發(fā)了一種方法,您可以使用功能查詢來(lái)測(cè)試瀏覽器對(duì)新CSS功能的支持。功能查詢的行為與媒體查詢的行為大致相同,不同之處在于功能查詢不是向?yàn)g覽器詢問(wèn)有關(guān)用于查看站點(diǎn)的設(shè)備的信息,而是詢問(wèn)瀏覽器是否支持特定的CSS功能。這使得以安全逐步增強(qiáng)的方式使用新功能變得更加容易。
@supports(display: grid){ /*CSS rules for browsers that support grid layout */ }
瀏覽器對(duì)功能查詢的支持很棒,但I(xiàn)nternet Explorer 11及更低版本不支持它們。只要您測(cè)試支持然后編寫(xiě)支持瀏覽器的代碼,就可以覆蓋以前在CSS中為舊瀏覽器執(zhí)行的任何操作。任何進(jìn)入css的新功能都可以使用功能查詢進(jìn)行測(cè)試。我認(rèn)為它們是使用css新特性的最佳方式之一,因?yàn)樗鼈兪刮覀兡軌蚋斓亻_(kāi)始使用新屬性,正如您在本文中所看到的,有很多特性可以開(kāi)始使用(如下圖所示)!
今天的文章分享就到這里,由于翻譯水平有限,敬請(qǐng)見(jiàn)諒,最后給大家分享幾個(gè)網(wǎng)站方便大家進(jìn)行延伸閱讀理解本文的內(nèi)容:
MDN
https://developer.mozilla.org/en-US/docs/Web/CSS
CSS Grid level 2 Here Comes subgrid
http://smashingmagazine.com/2018/07/css-grid-2/
Practical Scroll Snapping
Practical CSS Scroll Snapping
Using Feature Queries in CSS
http://hacks.mozilla.org/2016/08/using-feature-queries-in-css/
Grid By Example
http://gridbyexample.com
CSS Layout News
http://csslayout.news
英文作者:Rachel Andrew
web開(kāi)發(fā),技術(shù)文章自由撰稿人和技術(shù)培訓(xùn)講師;
Perch cms系統(tǒng)的聯(lián)合創(chuàng)始人;
Notist、Smashing雜志的主編;
CSS工作組的特邀專家
個(gè)人博客:https://rachelandrew.co.uk/
更多精彩內(nèi)容,請(qǐng)微信關(guān)注“前端達(dá)人”公眾號(hào)!
D3.js 是網(wǎng)絡(luò)上幾乎所有最具創(chuàng)新性和令人興奮的信息可視化的幕后黑手。D3 代表數(shù)據(jù)驅(qū)動(dòng)文檔,它是一個(gè)品牌名稱,也是多年來(lái)以某種形式提供的一類應(yīng)用程序。我們可以使用這個(gè)庫(kù)來(lái)構(gòu)建各種數(shù)據(jù)驅(qū)動(dòng)的項(xiàng)目,從簡(jiǎn)單的條形圖到動(dòng)態(tài)地圖,再到復(fù)雜的空間和時(shí)間探索。當(dāng)您希望在數(shù)據(jù)可視化方面獲得完全的創(chuàng)意和技術(shù)自由時(shí),無(wú)論您是構(gòu)建用于研究的交互式原型、頂級(jí)科技公司廣泛且完全響應(yīng)的數(shù)據(jù)儀表板,還是揭示數(shù)據(jù)故事的長(zhǎng)篇文章,D3 都是您的首選工具當(dāng)用戶滾動(dòng)時(shí)。
D3 是一個(gè)開(kāi)源 JavaScript 庫(kù),由 Mike Bostock 于 2011 年創(chuàng)建,用于為 Web 生成動(dòng)態(tài)和交互式數(shù)據(jù)可視化。盡管過(guò)去幾年推出了許多新的數(shù)據(jù)可視化庫(kù),但它們通常在底層使用 D3。這是因?yàn)?D3 與 JavaScript 一樣,非常靈活且強(qiáng)大。
圖 1.1 漢密爾頓中每條線的交互式可視化,這是Shirley Wu創(chuàng)建的 D3 項(xiàng)目
D3.js 的創(chuàng)建是為了滿足對(duì)可通過(guò)網(wǎng)絡(luò)訪問(wèn)的復(fù)雜數(shù)據(jù)可視化的迫切需求。假設(shè)您的公司正在使用商業(yè)智能工具,但它沒(méi)有顯示您的團(tuán)隊(duì)所需的數(shù)據(jù)模式。您必須構(gòu)建一個(gè)自定義儀表板,根據(jù)您的特定領(lǐng)域量身定制,準(zhǔn)確顯示客戶的行為方式。該儀表板需要快速、交互式且可在整個(gè)組織內(nèi)共享。D3 將是此類項(xiàng)目的自然選擇。
或者想象一下,您被雇用來(lái)實(shí)現(xiàn)一個(gè)網(wǎng)頁(yè),該網(wǎng)頁(yè)以可視化方式展示 LGBTQ+ 群體(女同性戀、男同性戀、雙性戀、跨性別者、酷兒等)的權(quán)利在過(guò)去幾十年和全世界的演變情況。此頁(yè)面包含許多隨著用戶滾動(dòng)而變化的創(chuàng)意可視化效果。它們通過(guò)鼠標(biāo)事件顯示更多信息并適應(yīng)屏幕大小。D3 將是構(gòu)建此類項(xiàng)目的首選工具。
Mike Bostock 最初創(chuàng)建 D3 是為了利用新興的 Web 標(biāo)準(zhǔn),正如他所說(shuō),“避免了專有表示并提供了非凡的靈活性,暴露了 CSS3、HTML5 和 SVG 等 Web 標(biāo)準(zhǔn)的全部功能”(http: // d3js.org)。D3.js 版本 7 是這個(gè)流行庫(kù)的最新版本,它通過(guò)模塊化 D3 的各個(gè)部分來(lái)延續(xù)這一趨勢(shì),使其與 ECMAScript 模塊(一種基于 JavaScript 的腳本語(yǔ)言)和現(xiàn)代應(yīng)用程序開(kāi)發(fā)完全兼容。
D3.js 使開(kāi)發(fā)人員不僅能夠制作豐富的交互式應(yīng)用程序,而且能夠制作樣式和服務(wù)類似于傳統(tǒng) Web 內(nèi)容的應(yīng)用程序。這使得它們更可移植,更適合增長(zhǎng),并且更容易由其他團(tuán)隊(duì)成員可能不知道 D3 的具體語(yǔ)法的大型團(tuán)體維護(hù)。
圖 1.2 D3 開(kāi)發(fā)人員可以訪問(wèn)各種數(shù)據(jù)表示形式,地圖就是一個(gè)例子。這是由Christophe Viau創(chuàng)建的數(shù)字高程模型 (DEM) 地圖。
Bostock 決定廣泛處理數(shù)據(jù)并創(chuàng)建一個(gè)能夠像圖表一樣簡(jiǎn)單、像網(wǎng)絡(luò)一樣簡(jiǎn)單、像列表一樣簡(jiǎn)單地呈現(xiàn)地圖的庫(kù),這也意味著開(kāi)發(fā)人員不需要了解以下內(nèi)容的抽象和語(yǔ)法:一個(gè)用于地圖的庫(kù),另一個(gè)用于動(dòng)態(tài)文本內(nèi)容的庫(kù),還有另一個(gè)用于傳統(tǒng)圖形的庫(kù)。相反,用于運(yùn)行交互式網(wǎng)絡(luò)可視化的代碼接近于純 JavaScript,并且也類似于表示 D3 地圖上的動(dòng)態(tài)點(diǎn)的代碼。方法是相同的,但數(shù)據(jù)也可以是相同的,以一種方式制定用于網(wǎng)絡(luò)的節(jié)點(diǎn)和鏈路,而以另一種方式制定用于地圖上的地理空間表示。
D3 不僅可以創(chuàng)建復(fù)雜多樣的圖形,還可以嵌入用戶期望的高水平交互性,這對(duì)于現(xiàn)代 Web 開(kāi)發(fā)至關(guān)重要。使用 D3,每個(gè)圖表的每個(gè)元素(從旋轉(zhuǎn)的地球儀到餅圖的切片)都以相同的方式進(jìn)行交互。由于 D3 是由精通數(shù)據(jù)可視化實(shí)踐的人編寫(xiě)的,因此它包含數(shù)據(jù)可視化和 Web 開(kāi)發(fā)中標(biāo)準(zhǔn)的交互式組件和行為。
圖 1.3 交互性是 D3 的核心。在此網(wǎng)絡(luò)可視化中,鼠標(biāo)交互揭示了不同組織之間的關(guān)系以及特定于所選節(jié)點(diǎn)的信息(https://amdufour.github.io/organizations-against-polization)。
數(shù)據(jù)可視化領(lǐng)域正在蓬勃發(fā)展,可用于生成數(shù)據(jù)綁定圖形的工具數(shù)量在過(guò)去十年中呈爆炸式增長(zhǎng)。我們擁有 Excel(數(shù)據(jù)可視化的常用入口)和 Power BI(用于構(gòu)建儀表板的 Microsoft 解決方案)等商業(yè)智能工具。另一方面,更有經(jīng)驗(yàn)的數(shù)據(jù)科學(xué)家通常會(huì)轉(zhuǎn)向 R 的 ggplot2 或 Python 的 matplotlib。
基于瀏覽器的點(diǎn)擊式工具(例如 Tableau、Flourish、DataWrapper、RAWGraphs 和 Google 圖表)也占據(jù)了主導(dǎo)地位,允許用最少的技術(shù)知識(shí)創(chuàng)建令人驚嘆的作品。
最后,HighCharts、Chart.js 和 D3.js 等 JavaScript 庫(kù)專門(mén)用于開(kāi)發(fā)基于 Web 的交互式可視化。
而且這個(gè)列表遠(yuǎn)非詳盡無(wú)遺......
那么,D3 在數(shù)據(jù)可視化工具的海洋中處于什么位置呢?我們何時(shí)以及如何使用它?我們可以說(shuō),雖然 D3 完全可以構(gòu)建此處列出的數(shù)據(jù)可視化庫(kù)提供的任何圖表,但它通常不是構(gòu)建簡(jiǎn)單的傳統(tǒng)圖表或探索階段(我們調(diào)查哪種類型的可視化是)的首選選項(xiàng)。最適合代表我們的數(shù)據(jù)。構(gòu)建 D3 項(xiàng)目需要時(shí)間,而 D3 在復(fù)雜、交互式和定制的項(xiàng)目中真正表現(xiàn)出色。數(shù)據(jù)可視化不僅僅是折線圖和散點(diǎn)圖!雖然上面提到的工具通常專注于預(yù)定義的圖表,但 D3 允許我們將數(shù)據(jù)綁定到任何圖形元素,并通過(guò)以獨(dú)特的方式組合這些視覺(jué)元素來(lái)打破常規(guī)。
圖 1.4 D3 具有 SVG 和畫(huà)布繪圖功能,允許開(kāi)發(fā)人員構(gòu)建自定義可視化效果,例如Elijah Meeks的樂(lè)譜表示形式。
以下是我們?nèi)绾卧跀?shù)據(jù)可視化項(xiàng)目范圍內(nèi)使用 D3 的示例。首先,我們從預(yù)先存在的數(shù)據(jù)集或手動(dòng)收集的數(shù)據(jù)開(kāi)始。在開(kāi)始數(shù)據(jù)分析過(guò)程之前,我們通常會(huì)花費(fèi)大量時(shí)間清理、格式化和準(zhǔn)備數(shù)據(jù)。Python 和 R 等數(shù)據(jù)科學(xué)工具在這方面功能強(qiáng)大,可以幫助我們識(shí)別隱藏在數(shù)據(jù)中的故事。Excel 還可以完成簡(jiǎn)單的數(shù)據(jù)整理和數(shù)據(jù)分析工作,并且需要較少的技術(shù)背景。我們甚至可以使用 JavaScript 和 D3 進(jìn)行基本數(shù)據(jù)探索,因?yàn)樗鼈兲峁┝宋覀儗⒃诒緯?shū)后面討論的統(tǒng)計(jì)方法。
一旦數(shù)據(jù)分析開(kāi)始,通常會(huì)創(chuàng)建一些原型來(lái)幫助完善我們的故事。Tableau 和 RawGraphs 等工具使我們能夠快速生成此類圖表。這是非常重要的一步,在此階段創(chuàng)建的可視化通常并不花哨或精致。我們不想在原型設(shè)計(jì)階段過(guò)于執(zhí)著于我們的想法,花費(fèi)大量時(shí)間。我們可能會(huì)發(fā)現(xiàn)自己必須“殺死我們的寶貝”并重新開(kāi)始幾次,直到我們找到最適合我們想要講述的故事的可視化效果。網(wǎng)絡(luò)圖可能是一個(gè)例外,直接跳到 D3 對(duì)于這些項(xiàng)目通常是有意義的。
最后,一旦我們知道要?jiǎng)?chuàng)建的可視化類型,就該卷起袖子,對(duì)其進(jìn)行編碼,并使用 D3 對(duì)其進(jìn)行完善。如今,編碼步驟通常發(fā)生在單頁(yè)應(yīng)用程序 (SPA) 中,使用 React 或 Svelte 等框架。
圖 1.5 使用 D3 構(gòu)建的自定義可視化的另一個(gè)示例,其中形狀與每首歌曲的不同屬性(例如持續(xù)時(shí)間、流派和節(jié)奏)成比例(https://amdufour.github.io/spotify-hits)。
您可能已經(jīng)嘗試過(guò) D3,并發(fā)現(xiàn)它并不容易上手。也許那是因?yàn)槟M且粋€(gè)簡(jiǎn)單的圖表庫(kù)。一個(gè)恰當(dāng)?shù)睦邮莿?chuàng)建條形圖,我們將在第 2 章和第 3 章中進(jìn)行此操作。D3 沒(méi)有一個(gè)函數(shù)來(lái)創(chuàng)建條形圖。相反,它有一個(gè)將<svg>容器附加到文檔對(duì)象模型 (DOM) 的函數(shù),以及另一組附加容器的函數(shù)。<rect>每個(gè)數(shù)據(jù)點(diǎn)的元素。然后,我們使用比例來(lái)計(jì)算構(gòu)成直方圖的矩形的長(zhǎng)度并設(shè)置它們的屬性。最后,我們調(diào)用另一組函數(shù),將 x 軸和 y 軸添加到條形圖中。如圖 1.6 所示,這個(gè)過(guò)程比使用 Highcharts 等專用圖表庫(kù)要長(zhǎng)得多。但 D3 處理數(shù)據(jù)和圖形的明確方式也是它的優(yōu)勢(shì)。盡管其他圖表庫(kù)允許您方便地制作折線圖和餅圖,但當(dāng)您想要?jiǎng)?chuàng)建不屬于傳統(tǒng)圖表范圍的可視化效果或?qū)崿F(xiàn)自定義交互時(shí),它們很快就會(huì)崩潰。不是D3。D3 允許您構(gòu)建您可以想象的任何數(shù)據(jù)驅(qū)動(dòng)圖形和交互性。
圖 1.6 使用 Highcharts 與 D3.js 生成的條形圖。Highcharts 的代碼更簡(jiǎn)單、更短,但 D3.js 更通用。
在圖 1.7 中,您可以看到我們通常如何使用 D3 進(jìn)行數(shù)據(jù)可視化編碼的地圖。我們從一個(gè)數(shù)據(jù)集(通常是 CSV 或 JSON 文件)開(kāi)始,然后使用 d3-fetch 模塊將此數(shù)據(jù)集加載到我們的項(xiàng)目中。我們通常需要執(zhí)行一些操作來(lái)格式化數(shù)據(jù)。例如,我們確保數(shù)字和日期的格式正確。如果我們之前沒(méi)有這樣做,我們可能還想詢問(wèn)我們的數(shù)據(jù)集以找到其主要特征。例如,提前知道其最大值和最小值通常很有幫助。然后我們準(zhǔn)備開(kāi)始構(gòu)建可視化,為此我們將結(jié)合我們將在本書(shū)中學(xué)習(xí)的不同 D3 函數(shù)。最后,我們通過(guò)監(jiān)聽(tīng)鼠標(biāo)事件來(lái)添加交互性,允許用戶過(guò)濾數(shù)據(jù)或放大可視化。
圖 1.7 如何使用 D3.js 實(shí)現(xiàn)數(shù)據(jù)可視化
D3.js 從來(lái)不會(huì)單獨(dú)使用,而是我們結(jié)合起來(lái)創(chuàng)建豐富的 Web 界面的技術(shù)和工具生態(tài)系統(tǒng)的一部分。與任何網(wǎng)頁(yè)一樣,D3 項(xiàng)目是在 DOM(文檔對(duì)象模型)內(nèi)構(gòu)建的,并利用 HTML5 的強(qiáng)大功能。盡管 D3 可以創(chuàng)建和操作傳統(tǒng)的 HTML 元素,例如分區(qū) ( <div>) 和列表 ( <ul>, <ol>),但我們主要使用 SVG 圖形或在畫(huà)布(從腳本渲染位圖圖像的 HTML 元素)內(nèi)生成可視化效果。然后,我們還可以使用舊的 CSS 樣式表,它可以增強(qiáng) D3 項(xiàng)目并使其設(shè)計(jì)更易于維護(hù),尤其是在廣泛的團(tuán)隊(duì)中。
鑒于 D3 是一個(gè) JavaScript 庫(kù),我們自然傾向于將 D3 方法與本機(jī) JavaScript 函數(shù)結(jié)合起來(lái)來(lái)訪問(wèn)和操作數(shù)據(jù)。D3 現(xiàn)在完全支持 JavaScript 的 ECMAScript 2015 或 ES6 修訂版以及大多數(shù)最新更新。D3 還作為模塊提供,可以集成到我們構(gòu)建 Web 項(xiàng)目所用的最新框架和庫(kù)中。使用這些模塊通常是首選方法,因?yàn)樗粫?huì)污染我們應(yīng)用程序的全局范圍。
在本節(jié)中,我們將簡(jiǎn)要討論這些技術(shù)及其在 D3 生態(tài)系統(tǒng)中的作用。由于 SVG 知識(shí)是理解 D3 的基礎(chǔ),因此我們將花時(shí)間更詳細(xì)地解釋您開(kāi)始構(gòu)建可視化所需理解的基礎(chǔ)知識(shí)。如果您已經(jīng)熟悉 HTML、SVG 元素、CSS、JavaScript 和 JavaScript 模塊,請(qǐng)隨意瀏覽或跳至第 1.3 節(jié)。
與 GIF 動(dòng)畫(huà)和框架成為網(wǎng)絡(luò)動(dòng)態(tài)內(nèi)容頂峰的時(shí)代相比,我們已經(jīng)走過(guò)了很長(zhǎng)一段路。在圖 1.8 中,您可以看到為什么 GIF 從未在強(qiáng)大的基于 Web 的數(shù)據(jù)可視化中流行起來(lái)。GIF 與設(shè)計(jì)用于使用 VML(矢量標(biāo)記語(yǔ)言)的 infoviz 庫(kù)一樣,對(duì)于早期瀏覽器來(lái)說(shuō)是必需的,但 D3 是為不再需要向后兼容性的現(xiàn)代瀏覽器而設(shè)計(jì)的。
圖 1.8 20 世紀(jì) 90 年代的一些例子,比如dpgraph.com,仍然存在,讓我們想起動(dòng)畫(huà) GIF 無(wú)處不在的時(shí)代。
當(dāng)您登陸網(wǎng)頁(yè)時(shí),要加載的第一個(gè)文件是超文本標(biāo)記語(yǔ)言或 HTML 文件,如下例所示。瀏覽器解析 HTML 文件以構(gòu)建文檔對(duì)象模型或 DOM,這是用于 Web 文檔的編程接口。我們經(jīng)常將其稱為 DOM 樹(shù),因?yàn)樗梢唤M嵌套元素(也稱為節(jié)點(diǎn)或標(biāo)簽)組成。在我們的示例中,<head>和 the<body>元素是<html>父元素的子元素。同樣,標(biāo)簽是、the和標(biāo)簽<body>的父標(biāo)簽。標(biāo)題也是該元素的同級(jí)元素。當(dāng)您加載網(wǎng)頁(yè)時(shí),您在屏幕上看到的是標(biāo)記中包含的元素。
<!DOCTYPE#nbsp;html>
<html>
<head>
<meta charset="UTF-8">
<title>A simple HTML file | D3.js in Action</title>
</head>
<body>
<h1>I am a title</h1>
<div>
<p>I am a paragraph.</p>
<p>I am another paragraph.</p>
</div>
</body>
</html>
在 DOM 中,每個(gè)元素的三類信息定義了其行為和外觀:樣式、屬性和特性。樣式?jīng)Q定顏色、大小、邊框、不透明度等。屬性包括類、id 和交互行為,盡管某些屬性也可以確定外觀,具體取決于您正在處理的元素類型。對(duì)于 SVG 元素,屬性用于設(shè)置不同形狀的位置、大小和比例。屬性通常指的是狀態(tài),例如復(fù)選框的“checked”屬性,如果該框被選中,則該屬性為 true;如果該框未被選中,則該屬性為 false。盡管術(shù)語(yǔ)“屬性”和“屬性”經(jīng)常互換使用,但它們是兩個(gè)不同的東西。呈現(xiàn) DOM 時(shí),屬性顯示為初始狀態(tài)。屬性是元素的當(dāng)前狀態(tài),并且可以隨著用戶與界面交互而改變。在第2章中,我們將討論用于生成或修改HTML和SVG元素的樣式和屬性的D3方法。
DOM 還決定元素在屏幕上的繪制順序,子元素在父元素之后和內(nèi)部繪制。盡管 CSS 屬性z-index使我們能夠部分控制傳統(tǒng) HTML 元素繪制到屏幕上的順序,但 SVG 元素嚴(yán)格遵循它們?cè)?DOM 中出現(xiàn)的順序。根據(jù)畫(huà)家的模型,之后繪制的內(nèi)容出現(xiàn)在之前繪制的內(nèi)容之上。
可擴(kuò)展矢量圖形 (SVG) 的引入確實(shí)改變了網(wǎng)絡(luò)的面貌。幾年之內(nèi),SVG 圖形成為主要的 Web 開(kāi)發(fā)工具。光柵圖形(PNG 和 JPG)由微小的像素組成,當(dāng)我們放大得太近時(shí),這些像素就會(huì)變得可見(jiàn),而矢量圖形則是通過(guò)數(shù)學(xué)和幾何圖形構(gòu)建的。它們?cè)谌魏纬叽绾腿魏纹聊环直媛氏露寄鼙3智逦耐庥^。SVG 圖形的另一個(gè)顯著優(yōu)勢(shì)是它們可以直接注入 DOM,允許開(kāi)發(fā)人員操縱其元素并為其設(shè)置動(dòng)畫(huà),并使屏幕閱讀器可以訪問(wèn)它們。如果構(gòu)建正確,SVG 也具有高性能,其文件大小僅為等效光柵圖像的一小部分。
當(dāng)使用 D3 創(chuàng)建數(shù)據(jù)可視化時(shí),我們通常將 SVG 形狀注入 DOM 并修改其屬性以生成組成可視化的視覺(jué)元素。了解 SVG 的工作原理、主要 SVG 形狀及其表示屬性對(duì)于大多數(shù) D3 項(xiàng)目至關(guān)重要。
本書(shū)的每一章都包含旨在支持您的學(xué)習(xí)體驗(yàn)的代碼練習(xí)。我們強(qiáng)烈建議您“做”這本書(shū),而不僅僅是“讀”這本書(shū),這意味著在閱讀章節(jié)時(shí)完成練習(xí)。通過(guò)這種方式,您將保留更多信息,并很快就能構(gòu)建自己的 D3 項(xiàng)目!
對(duì)于每個(gè)練習(xí)和項(xiàng)目,您都可以訪問(wèn)現(xiàn)成的代碼文件。您可以在本書(shū)的 Github 存儲(chǔ)庫(kù)(https://github.com/d3js-in-action-third-edition/code-files)上找到它們。如果您熟悉 Git,則可以將存儲(chǔ)庫(kù)克隆到您的計(jì)算機(jī)上。您還可以下載壓縮文件。
從 Github 存儲(chǔ)庫(kù)下載代碼文件
每一章都有自己的文件夾,其中包含一個(gè)或多個(gè)練習(xí),按照每章中的部分編號(hào)。練習(xí)包括一個(gè)start文件夾,其中包含入門(mén)所需的所有文件。您將在文件夾中找到練習(xí)的完整解決方案end。當(dāng)您完成一章的各個(gè)部分時(shí),您可以繼續(xù)在上一部分使用的文件中進(jìn)行編碼,或者使用專用于該部分的文件夾重新開(kāi)始。兩種選擇都會(huì)導(dǎo)致相同的結(jié)果。
讓我們開(kāi)始探索矢量圖形。轉(zhuǎn)到本書(shū)提供的代碼文件。找到end中的文件夾chapter_01/SVG_Shapes_Gallery并右鍵單擊該文件index.html。在菜單中,轉(zhuǎn)到打開(kāi)方式并選擇瀏覽器。我們建議使用 Chrome 或 Firefox,因?yàn)樗鼈兙哂谐錾臋z查器工具。該文件將在新的瀏覽器選項(xiàng)卡中打開(kāi),并且將出現(xiàn)您在圖 1.9 中看到的矢量圖形。您還可以在 Github 托管項(xiàng)目 ( https://d3js-in-action-third-edition.github.io/svg-shapes-gallery ) 上查看這些 SVG 形狀。
圖 1.9 我們將在本節(jié)中構(gòu)建的基本 SVG 形狀圖庫(kù)。
您正在查看的 SVG 圖形包含創(chuàng)建 D3 可視化時(shí)最常使用的形狀:線條、矩形、圓形、橢圓形、路徑和文本。
使用 D3 時(shí),您通常會(huì)告訴庫(kù)應(yīng)將哪些形狀附加到 DOM。您還負(fù)責(zé)了解需要計(jì)算哪些表示屬性才能使形狀具有您正在尋找的尺寸、顏色和位置。在下面的練習(xí)中,您將編寫(xiě)創(chuàng)建圖 1.9 中每個(gè) SVG 元素的代碼。我們將此練習(xí)稱為SVG 形狀圖庫(kù)。之后,您將了解入門(mén)所需的所有 SVG 基礎(chǔ)知識(shí)。
在您選擇的代碼編輯器中打開(kāi)練習(xí)文件夾index.html中的文件。我們推薦VS Code,這是一個(gè)免費(fèi)、易于使用的代碼編輯器,并且具有多種功能,對(duì)前端開(kāi)發(fā)很有幫助。startSVG_Shapes_Gallery
正如您所看到的,index.html是一個(gè)簡(jiǎn)單的 HTML 文件。如果您在瀏覽器中打開(kāi)此文件(右鍵單擊該文件并在“打開(kāi)方式”菜單中選擇瀏覽器),您將只會(huì)看到一個(gè)空白頁(yè)面。這是因?yàn)樵?lt;body>元素為空。在接下來(lái)的小節(jié)中,我們將向此<body>元素添加 SVG 形狀。
清單 1.1.a SVG 形狀庫(kù)練習(xí)的起始 HTML 文件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SVG Shapes Gallery | D3.js in Action</title>
</head>
<body>
</body>
</html>
以下部分將介紹多個(gè) SVG 元素及其屬性。作為開(kāi)發(fā)人員,我們?cè)跇?gòu)建項(xiàng)目、使用我們不熟悉的 SVG 元素或?qū)ふ?JavaScript 函數(shù)來(lái)執(zhí)行特定操作時(shí)嚴(yán)重依賴在線資源。在前端開(kāi)發(fā)中,MDN Web Docs ( https://developer.mozilla.org/ ) 始終是可靠且全面的資源。它包含 HTML 元素及其屬性、CSS 屬性和 JavaScript 函數(shù)的易于理解且通常可編輯的示例。
在 SVG 圖形的世界中,<svg></svg>容器是在其上繪制所有內(nèi)容的白板。每個(gè) SVG 形狀都嵌套在<svg>父級(jí)中。要查看其實(shí)際效果,請(qǐng)?jiān)谠豬ndex.html內(nèi)編輯并添加 SVG 容器<body>。在瀏覽器中重新加載頁(yè)面。目前還看不到任何東西。
<body>
<svg></svg>
</body>
打開(kāi)瀏覽器的檢查器工具(在瀏覽器窗口中右鍵單擊并選擇“檢查”)。在檢查器窗口中,您將看到組成頁(yè)面的 DOM。找到<svg></svg>容器,也稱為 SVG 節(jié)點(diǎn)。當(dāng)您在檢查器中將鼠標(biāo)移到它上面時(shí),SVG 元素會(huì)在頁(yè)面上突出顯示。您可以在圖 1.5 中看到此效果。
圖 1.10 在 DOM 樹(shù)中選擇并在視口中突出顯示的 SVG 節(jié)點(diǎn)
默認(rèn)情況下,瀏覽器為 SVG 容器提供寬度300px和高度。150px但我們也可以使用屬性來(lái)分配這些值。屬性用于提供有關(guān) HTML 元素的附加信息。對(duì)于內(nèi)聯(lián) SVG,我們主要使用屬性來(lái)設(shè)置組成 SVG 圖形的元素和形狀的大小和位置。
例如,我們可以設(shè)置SVG 容器的寬度和高度屬性。返回到文本編輯器,并將 awidth和 aheight屬性添加到 SVG 容器。將它們的值設(shè)置為900和300并保存文件。
<svg width="900" height="300"></svg>
在瀏覽器中重新加載項(xiàng)目并在檢查工具中找到 SVG 節(jié)點(diǎn)。請(qǐng)注意,寬度和高度屬性現(xiàn)在顯示在 SVG 容器的括號(hào)內(nèi)。如果將鼠標(biāo)移到檢查工具 DOM 樹(shù)中的 SVG 節(jié)點(diǎn)上,您還會(huì)看到視口中的 SVG 容器現(xiàn)在的大小為 900 像素 x 300 像素。
圖1.11 SVG節(jié)點(diǎn)采用其屬性指定的大小
為了幫助我們查看 SVG 容器,而不必從檢查器中突出顯示它,讓我們給它一個(gè)邊框。向 SVG 容器添加樣式屬性并插入 CSS 邊框?qū)傩浴T谙乱粋€(gè)代碼片段中,我們使用 border 速記屬性創(chuàng)建一個(gè)寬度為 1px 的黑色實(shí)心邊框。
<svg width="900" height="300" style="border:1px solid black;"></svg>
保存文件,重新加載頁(yè)面并確認(rèn) SVG 容器周?chē)羞吙颉,F(xiàn)在,調(diào)整瀏覽器窗口的大小,直到它小于 SVG 容器。您將觀察到 SVG 容器保持固定的寬度和高度,并且不適應(yīng)瀏覽器窗口的大小。讓我們嘗試使 SVG 容器具有響應(yīng)能力。
之前,我們將 SVG 屬性設(shè)置為絕對(duì)值 (900和300),瀏覽器將它們解釋為以像素為單位的測(cè)量值 (900px和300px)。但我們也可以使用百分比。在文本編輯器中,將寬度屬性更改為相對(duì)值“ 100%”,保存文件并重新加載頁(yè)面。
<svg width="100%" height="300" style="border:1px solid black;"></svg>
再次調(diào)整瀏覽器大小,并注意 SVG 如何獲取可用的完整寬度并保持 300 像素的固定高度。這更好,但我們失去了原來(lái)的縱橫比。
為了使內(nèi)聯(lián) SVG 具有響應(yīng)能力,我們可以使用viewBox 屬性。在代碼編輯器中,從 SVG 容器中刪除width和屬性,并將它們替換為屬性。給它一個(gè)值。heightviewBox"0 0 900 300"
<svg viewBox="0 0 900 300" style="border:1px solid black;"></svg>
再次調(diào)整瀏覽器窗口的大小。你注意到了什么?SVG 容器現(xiàn)在可以適應(yīng)任何屏幕尺寸,同時(shí)保持其縱橫比為 900:300。我們有一個(gè)響應(yīng)式 SVG!
正如您所注意到的,viewBox 屬性由四個(gè)值的列表組成。前兩個(gè)數(shù)字指定 viewBox 坐標(biāo)系的原點(diǎn)(x 和 y)。在本書(shū)中,我們將始終使用0 0,但很高興知道這些值可用于更改 SVG 容器的哪一部分在屏幕上可見(jiàn)。viewBox 屬性的最后兩個(gè)數(shù)字是其寬度和高度。它們定義 SVG 的縱橫比,并確保其完美縮放以適合任何容器而不變形。
安裝在容器內(nèi)是這里的關(guān)鍵。到目前為止,我們的內(nèi)聯(lián) SVG 的容器是 HTML<body>元素,它通常會(huì)擴(kuò)展以適應(yīng)瀏覽器的視口。如果視口變得非常大,SVG 也會(huì)變得非常大。通常,我們希望 SVG 具有最大寬度,以便它不會(huì)大于頁(yè)面上的其余內(nèi)容。為此,請(qǐng)將 SVG 容器包裝在寬度為 100%、最大寬度為 1200px 的 div 內(nèi)。為簡(jiǎn)單起見(jiàn),我們將這些屬性設(shè)置為內(nèi)聯(lián)樣式,但在實(shí)際項(xiàng)目中,這些屬性將來(lái)自 CSS 文件。請(qǐng)注意,我們還添加了值邊距“ 0 auto”,以使 SVG 在頁(yè)面上水平居中。
<div style="width:100%; max-width:1200px; margin:0 auto;">
<svg viewBox="0 0 900 300" style="border:1px solid black;"> ... </svg>
</div>
嘗試再次調(diào)整瀏覽器的大小,看看我們的 SVG 如何優(yōu)雅地適應(yīng)任何屏幕尺寸,同時(shí)尊重其容器的最大寬度。該策略有助于將 D3 可視化注入響應(yīng)式網(wǎng)頁(yè),我們將在本書(shū)中使用它。
既然我們知道了如何使內(nèi)聯(lián) SVG 具有響應(yīng)性,那么解決 SVG 形狀在 SVG 容器內(nèi)的定位方式就很重要了。SVG 容器就像一張白紙,我們可以在上面繪制矢量形狀。矢量形狀是根據(jù)基本幾何原理定義的,并參考 SVG 容器的坐標(biāo)系進(jìn)行定位。
SVG 坐標(biāo)系與笛卡爾坐標(biāo)系類似。其 2D 平面使用兩個(gè)垂直軸來(lái)確定元素的位置,稱為 x 和 y。這兩個(gè)軸源自SVG 容器的左上角,如圖 1.12 所示。意思是y軸的正方向是從上到下。記住這一點(diǎn)可以讓你避免一些頭痛!
圖1.12 SVG容器的坐標(biāo)系和元素的位置
為了在 SVG 容器內(nèi)定位元素,我們從左上角的原點(diǎn)開(kāi)始向右移動(dòng)。這將為我們提供元素的水平 (x) 位置。對(duì)于垂直 (y) 位置,我們從頂部開(kāi)始向下移動(dòng)。這些位置由每個(gè) SVG 形狀的表示屬性定義。
現(xiàn)在,我們將了解您在構(gòu)建 D3 項(xiàng)目時(shí)經(jīng)常遇到的 SVG 形狀。我們還將討論它們的主要表現(xiàn)屬性。這里的目標(biāo)絕不是編寫(xiě) SVG 提供的所有形狀和功能的綜合指南,而是涵蓋支持您的 D3 之旅的基礎(chǔ)知識(shí)。
出色的藝術(shù)家可以用矢量圖形繪制任何東西,但您可能不會(huì)因?yàn)槟且幻囆g(shù)家而關(guān)注 D3。相反,您正在處理圖形并考慮更務(wù)實(shí)的目標(biāo)。從這個(gè)角度來(lái)看,理解幾何基元(也稱為圖形基元)的概念至關(guān)重要。幾何基元是簡(jiǎn)單的形狀,例如點(diǎn)、線、圓和矩形。這些形狀可以組合成更復(fù)雜的圖形,特別方便直觀地顯示信息。
基元對(duì)于理解您在現(xiàn)實(shí)世界中看到的復(fù)雜信息可視化也很有用。樹(shù)形布局,就像我們將在第 10 章中構(gòu)建的那樣,當(dāng)您意識(shí)到它們只是圓形和直線時(shí),它們就不那么令人生畏了。當(dāng)您將交互式時(shí)間線視為矩形和點(diǎn)的集合時(shí),它們更容易理解和創(chuàng)建。即使是主要以多邊形、點(diǎn)和線形式出現(xiàn)的地理數(shù)據(jù),當(dāng)您將其分解為最基本的圖形結(jié)構(gòu)時(shí),也不會(huì)那么混亂。
線條元素可能是所有 SVG 形狀中最簡(jiǎn)單的。它獲取兩個(gè)點(diǎn)的位置,設(shè)置為屬性,并在它們之間繪制一條直線。返回到該index.html文件,并在 SVG 容器內(nèi)添加一個(gè)<line />元素。聲明其屬性x1和y1并分別賦予它們值 50 和 45。這意味著我們的線的起點(diǎn)位于(50, 45)SVG 容器的坐標(biāo)系中。如果從 SVG 容器的左上角開(kāi)始,向右移動(dòng) 50 像素,向下移動(dòng) 45 像素,您將遇到線條的起點(diǎn)。(140, 225)同樣,使用屬性x2和y2將線的端點(diǎn)設(shè)置為。
<svg>
<line x1="50" y1="45" x2="140" y2="225" />
</svg>
圖1.13 在SVG容器的坐標(biāo)系中定位線元素
如果您保存并重新加載項(xiàng)目,您的線條將不可見(jiàn),您可能想知道發(fā)生了什么。為了使 SVG 線條在屏幕上可見(jiàn),我們還需要設(shè)置其描邊屬性,該屬性控制線條的顏色。border 屬性的值與 CSS color 屬性類似。它可以是顏色名稱 ( black, blue, ...)、RGB 顏色 ( rgb(255,0,0)) 或十六進(jìn)制值 ( #808080)。向您的線條添加筆劃屬性,并為其指定您選擇的顏色(我們使用黑色)。現(xiàn)在它應(yīng)該在屏幕上可見(jiàn)。
<line x1="50" y1="45" x2="140" y2="225" stroke="black" />
如果我們想設(shè)置線條的寬度,我們可以使用描邊寬度屬性。此屬性接受絕對(duì)數(shù)字(轉(zhuǎn)換為像素)或相對(duì)值 (%)。例如,以下行的 a 為stroke-width3px。如果stroke-width未聲明該屬性,瀏覽器將應(yīng)用默認(rèn)值 1px。
<line x1="50" y1="45" x2="140" y2="225" stroke="black" stroke-width="3" />
打開(kāi)瀏覽器的檢查器工具并找到 SVG 節(jié)點(diǎn)及其包含的行。雙擊其中一個(gè)屬性,更改其值并觀察新值如何修改線的起點(diǎn)或終點(diǎn)。花時(shí)間嘗試不同的值,以確認(rèn)您了解屬性x1、y1、x2和如何y2影響線條的位置和長(zhǎng)度。
-20現(xiàn)在,為屬性賦予 值x1。你看到線的起點(diǎn)是如何消失的嗎?落在 SVG viewBox 之外的任何形狀或形狀部分在屏幕上都不可見(jiàn)。不過(guò),該元素仍然存在于 DOM 中。我們可以訪問(wèn)和操縱它。如果 SVG 中的某個(gè)元素不可見(jiàn),并且您不知道為什么首先要檢查它是否在 SVG viewBox 之外!請(qǐng)記住,您始終可以通過(guò)使用開(kāi)發(fā)人員工具檢查 DOM 來(lái)找到它。正如我們之前所做的那樣,如果將鼠標(biāo)移到檢查器工具中的元素上,即使它位于 SVG viewBox 之外,它也會(huì)在視口中突出顯示。
圖 1.14 SVG 線在 SVG 容器外部時(shí)部分隱藏
為了提高效率,大多數(shù) SVG 元素只需要一個(gè)自閉合標(biāo)簽(我們使用 <line /> 而不是 <line></line>)。與其他一些 HTML 標(biāo)簽一樣,SVG 元素的固有結(jié)構(gòu)在自閉合標(biāo)簽中提供了所有必需的信息。這對(duì)于 SVG 文本元素有所不同,其中文本放置在開(kāi)始標(biāo)簽和結(jié)束標(biāo)簽之間。
顧名思義,矩形元素<rect />在屏幕上繪制一個(gè)矩形形狀。該<rect />元素需要四個(gè)屬性才能可見(jiàn)。屬性x和y聲明矩形左上角的位置,而屬性width和height分別控制其寬度和高度。<rect />在 SVG 容器中添加以下元素及其屬性。
<rect x="260" y="25" width="120" height="60" />
在我們的示例中,矩形的左上角位于SVG 容器原點(diǎn)的260px右側(cè)和下方。25px它的寬度為120px,高度為60px。與其他位置屬性一樣,我們可以使用百分比而不是絕對(duì)數(shù)字來(lái)設(shè)置它們的值。例如,如果我們將該width屬性設(shè)置為50%,則矩形將擴(kuò)展到 SVG 容器寬度的一半。
圖 1.15 在 SVG 容器的坐標(biāo)系中定位矩形并調(diào)整其大小
您可能已經(jīng)注意到我們的矩形充滿了黑色。默認(rèn)情況下,瀏覽器對(duì)大多數(shù) SVG 形狀應(yīng)用黑色填充。我們可以通過(guò)設(shè)置fill屬性并為其指定任何 CSS 顏色來(lái)更改該顏色。如果我們想給矩形添加邊框,我們添加一個(gè)描邊屬性。圖 1.16 顯示了一些示例。請(qǐng)注意,如果不聲明屬性,則矩形周?chē)粫?huì)繪制邊框stroke。另外,在最后一個(gè)矩形中,屬性fill-opacity和border-opacity用于使fill和stroke半透明。與 CSS 中一樣,不透明度可以設(shè)置為絕對(duì)值 ( 0.3) 或百分比 (30%)。與填充和描邊相關(guān)的所有屬性也可以從 CSS 文件設(shè)置或修改。
圖 1.16 應(yīng)用于矩形 SVG 形狀的不同樣式屬性
如果您希望矩形具有圓角,則只需添加rx和ry屬性,分別是水平和垂直角半徑。這些屬性接受絕對(duì)值(以像素為單位)和相對(duì)值(百分比)。例如,下面矩形的每個(gè)角的半徑都是 20px。將此矩形添加到您的形狀庫(kù)中。
<rect x="260" y="100" width="120" height="60" rx="20" ry="20" />
此時(shí),您可能想知道 SVG 中是否有一個(gè)可以繪制正方形的元素。我們不需要一個(gè)!在 SVG 中,我們<rect />通過(guò)賦予元素相等width和height屬性來(lái)繪制帶有元素的正方形。例如,以下<rect />元素將繪制一個(gè) 60px x 60px 的正方形。也將它添加到您的形狀庫(kù)中。
<rect x="260" y="175" width="60" height="60" />
作為參考,我們的形狀庫(kù)中現(xiàn)在有三種類型的 SVG 矩形:經(jīng)典矩形、圓角矩形和正方形。為了好玩,我們給了它們顏色#6ba5d7并玩弄它們stroke和fill屬性。請(qǐng)注意,只有筆劃在正方形上可見(jiàn),因?yàn)槠鋐ill屬性值為transparent或none。您的矩形應(yīng)該類似于圖 1.17 中的矩形,除非您更改了它們的屬性(我們鼓勵(lì)您這樣做)!
<rect x="260" y="25" width="120" height="60" fill="#6ba5d7" />
<rect x="260" y="100" width="120" height="60" rx="20" ry="20"
? fill="#6ba5d7" />
<rect x="260" y="175" width="60" height="60" fill="transparent"
? stroke="#6ba5d7" />
當(dāng)您嘗試在可視化中對(duì)齊形狀時(shí)需要記住的一點(diǎn)是,筆劃是均勻地繪制在 SVG 形狀的內(nèi)部和外部邊界上的。如下圖所示,如果矩形的width屬性為 40px,則應(yīng)用 ofstroke-width會(huì)1在視覺(jué)上向矩形的左側(cè)添加 0.5px,向右側(cè)添加 0.5px(而不是像我們本能地認(rèn)為的那樣,向每邊添加 1px) ),實(shí)際總寬度為 41px。如果stroke-width是2,它會(huì)在每邊添加 1px,依此類推。
筆劃寬度對(duì) SVG 形狀實(shí)際寬度的影響
圓形形狀經(jīng)常用于數(shù)據(jù)可視化。它們自然地吸引眼球,并使可視化感覺(jué)更加友好和有趣。我們使用<circle />元素繪制 SVG 圓圈。其所需屬性是圓心的位置 ( cx , cy ) 及其半徑 ( r )。圓的半徑是從圓心到其邊界上任意點(diǎn)所繪制的直線的長(zhǎng)度。將以下圓圈添加到您的形狀庫(kù)中。將其中心定位于(530, 80)并為其指定 50px 的半徑。
<circle cx="530" cy="80" r="50" />
圖 1.18 在 SVG 容器的坐標(biāo)系中定位圓和橢圓并調(diào)整其大小
您還可以使用圓形的填充和描邊屬性。為了生成圖 1.18 中的效果,我們使用了透明填充和 3px 的描邊,顏色為#81c21c。
類似地,<ellipse />元素需要形狀中心位置的屬性 ( cx, cy)。圓形具有恒定的半徑,而橢圓形的半徑則不同,從而使其具有扁平形狀。我們通過(guò)聲明水平半徑 ( rx ) 和垂直半徑 ( ry ) 來(lái)創(chuàng)建這種扁平化效果。將下一個(gè)片段添加到您的圖庫(kù)中。它將在圓下方繪制一個(gè)橢圓,水平半徑為 50px,垂直半徑為 30px。
<ellipse cx="530" cy="205" rx="50" ry="30" />
SVG路徑是迄今為止所有 SVG 元素中最靈活的。它們?cè)?D3 中廣泛用于繪制幾乎所有無(wú)法用迄今為止討論的形狀基元之一(直線、矩形、圓形和橢圓形)表示的復(fù)雜形狀和曲線。
d我們通過(guò)聲明其屬性(代表“draw”)來(lái)指示瀏覽器如何繪制路徑。該d屬性包含一個(gè)命令列表,從開(kāi)始繪制路徑的位置到要使用的曲線類型,直到指定我們是否希望路徑成為閉合形狀。例如,將以下路徑元素添加到您的庫(kù)中。在此示例中,d屬性以M680 150開(kāi)頭,表示“移動(dòng)到坐標(biāo)(680, 150)”。然后我們從當(dāng)前點(diǎn) (680, 150) 到字母 C 后面的第三個(gè)坐標(biāo) (755 150) 指定的端點(diǎn)繪制一條三次貝塞爾曲線。三次貝塞爾曲線需要控制點(diǎn),即字母 C 后面、起點(diǎn)和終點(diǎn)之間的坐標(biāo)((710, 80) 和 (725, 80))。這些控制點(diǎn)定義了曲線的陡峭程度。然后我們有字母 S,它代表“停止”。它的工作原理與字母 C 類似,只不過(guò)它通向曲線的端點(diǎn)。這里最后一條曲線的起點(diǎn)是(755 150),終點(diǎn)是(840, 150),控制點(diǎn)是(810, 220)。曲線可以由一個(gè)或兩個(gè)控制點(diǎn)定義。
<path d="M680 150 C 710 80, 725 80, 755 150 S 810 220, 840 150" fill="none"
? stroke="#773b9a" stroke-width="3" />
圖 1.19 一個(gè)簡(jiǎn)單的 SVG 路徑及其控制點(diǎn)
要深入了解 SVG 路徑,請(qǐng)參閱 MDN 的教程:https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths。
手動(dòng)編寫(xiě)d屬性對(duì)于簡(jiǎn)單的形狀是可行的,但隨著形狀變得復(fù)雜而變得乏味。幸運(yùn)的是,D3 具有強(qiáng)大的形狀生成器,我們將在第 4 章中討論。
關(guān)于路徑要記住的另一件重要的事情是瀏覽器將以黑色填充它們,除非我們將它們的fill屬性設(shè)置為noneor transparent。即使路徑未閉合(如我們的示例中所示),情況也是如此。
<div>內(nèi)聯(lián) SVG 圖形的最大優(yōu)點(diǎn)之一是它們可以包含可導(dǎo)航的文本,就像插入一個(gè)或一個(gè)元素中的任何其他 HTML 文本一樣<p>。這對(duì)于可訪問(wèn)性來(lái)說(shuō)是一個(gè)很大的優(yōu)勢(shì)。
由于數(shù)據(jù)可視化通常包含多個(gè)標(biāo)簽,因此有必要了解如何使用<text></text>元素操作 SVG 文本。讓我們向形狀庫(kù)添加標(biāo)簽,以了解 SVG 文本的基本原理。
到目前為止討論的 SVG 形狀使用自閉合標(biāo)簽 ( <line />, <rect />, <path />, ...)。使用 SVGtext元素時(shí),我們需要使用開(kāi)始標(biāo)簽和結(jié)束標(biāo)簽。我們將要顯示的文本放置在這兩個(gè)標(biāo)簽之間。例如,讓我們?cè)?SVG 中添加一個(gè)表示“l(fā)ine”的文本元素。
<text>line</text>
保存文件并重新加載頁(yè)面。您可能希望文本出現(xiàn)在 SVG 容器的左上角,但實(shí)際上卻看不到......這是為什么?默認(rèn)情況下,SVG 文本的位置是參考其基線計(jì)算的,由屬性控制dominant-baseline。如果文本基線的坐標(biāo)是(0, 0),您可以在圖 1.20 中看到實(shí)際文本如何最終出現(xiàn)在 SVG 容器之外。由于位于 SVG 容器外部的任何元素都是不可見(jiàn)的,因此我們看不到文本。
圖 1.20 位于 SVG 容器外部的文本
使用 SVG 文本時(shí)要考慮的另一點(diǎn)是文本的流動(dòng)方式。常規(guī) HTML 元素按照控制內(nèi)容流的特定規(guī)則放置在頁(yè)面上。如果您將一堆<div></div>元素插入頁(yè)面中,它們會(huì)自然地堆疊在一起,并且它們的內(nèi)容將重排,以便它永遠(yuǎn)不會(huì)超出其容器。SVG 文本根本不流動(dòng),每個(gè) SVG 元素必須單獨(dú)定位。一種方法是設(shè)置它們的x和y屬性。如果我們使用這些屬性將文本放置在 處(60, 260),標(biāo)簽“l(fā)ine”將出現(xiàn)在形狀庫(kù)中 SVG 線的下方。
<text x="60" y="260">line</text>
為了練習(xí),創(chuàng)建一個(gè)新的文本元素,將標(biāo)簽“矩形”放置在矩形和正方形下方。
到目前為止,我們已經(jīng)使用x和y屬性來(lái)聲明文本元素的左下角。但是如果我們想設(shè)置文本中點(diǎn)的位置怎么辦?我們可以通過(guò)使用屬性text-anchor并為其指定值來(lái)做到這一點(diǎn)middle。例如,我們可以使用此屬性將圓形的文本標(biāo)簽居中。
<text x="530" y="155" text-anchor="middle">circle</text>
圖1.21 text-anchor屬性影響SVG文本的對(duì)齊方式。它的默認(rèn)值是“開(kāi)始”。為了根據(jù)中間對(duì)齊文本元素,我們應(yīng)用“middle”的 text-andchor 屬性。類似地,為了根據(jù)文本的結(jié)尾對(duì)齊文本,我們應(yīng)用“end”的 text-andchor 屬性。
最后為橢圓添加一個(gè)標(biāo)簽,為路徑元素添加另一個(gè)標(biāo)簽。默認(rèn)情況下,SVG 文本為黑色。您可以使用屬性更改其顏色fill。
我們將在本節(jié)中討論的最后一個(gè) SVG 元素是組元素。group 或<g></g>元素與我們迄今為止討論的 SVG 元素不同,因?yàn)樗鼪](méi)有圖形表示,也不作為有界空間存在。相反,它是元素的邏輯分組。在創(chuàng)建由多個(gè)形狀和文本元素組成的可視化效果時(shí),您需要廣泛使用組。
如果我們希望正方形和“rect”標(biāo)簽一起顯示并在 SVG 容器中作為一個(gè)整體移動(dòng),我們可以將它們放置在一個(gè)<g>元素內(nèi),如下例所示。請(qǐng)注意元素的左上角如何<rect>更改為(0, 0)。位于<text>處以(0, 85)保持其低于<rect>。
<g>
<rect x="0" y="0" width="60" height="60" />
<text x="0" y="85">rect</text>
</g>
包含正方形及其標(biāo)簽的組現(xiàn)在顯示在 SVG 容器的左上角。我們可以將這個(gè)組及其包含的所有元素移動(dòng)到 SVG 容器中任何我們想要的位置,同時(shí)保持正方形與其標(biāo)簽之間的對(duì)齊。
在 SVG 容器中移動(dòng)組是通過(guò)轉(zhuǎn)換屬性完成的。變換屬性比目前討論的屬性有點(diǎn)嚇人,但與 CSS 變換屬性相同。它采用一個(gè)變換(平移、旋轉(zhuǎn)、縮放等)或一堆變換作為值。為了移動(dòng)一個(gè)組,我們使用translate(x, y)變換。如果我們想要將<rect>和<text>元素移回其原始位置,我們需要對(duì)元素應(yīng)用向右 260 像素和向下 175 像素的平移。<g>為此,我們將其 Transform 屬性設(shè)置為transform="translate(260,175)"。
<g transform="translate(260,175)">
<rect x="0" y="0" width="60" height="60" />
<text x="0" y="85">rect</text>
</g>
<g> 元素的另一個(gè)有用的方面是它的子元素繼承它的屬性。為了說(shuō)明這一點(diǎn),讓我們將<g>元素中所有剩余的文本元素分組,除了標(biāo)簽“矩形”,我們已經(jīng)將其與正方形分組。
<g>
<text x="60" y="260">line</text>
<text x="530" y="155" style="text-anchor:middle">circle</text>
<text x="530" y="260" style="text-anchor:middle">ellipse</text>
<text x="730" y="260">path</text>
</g>
#636466如果我們對(duì)組應(yīng)用填充屬性,<text>則該組內(nèi)的每個(gè)元素將繼承相同的顏色。同樣,如果我們向組添加樣式屬性,例如使用font-family和font-size屬性,則組內(nèi)的文本將繼承這些屬性。
<g fill="#636466" style="font-size:16px; font-family:monospace">
<text x="60" y="260">line</text>
<text x="530" y="155" style="text-anchor:middle">circle</text>
<text x="530" y="260" style="text-anchor:middle">ellipse</text>
<text x="730" y="260">path</text>
</g>
最后重新加載頁(yè)面并觀察組內(nèi)的標(biāo)簽如何繼承組的顏色和字體,而保留在該組之外的標(biāo)簽則保持其原始外觀。這種將共享屬性應(yīng)用于組元素的技術(shù)非常方便,可以幫助您將 DRY(不要重復(fù)自己)編碼原則應(yīng)用到您的工作中。當(dāng)您需要更新這些屬性時(shí),它也會(huì)讓您的生活更輕松。
恭喜您完成了本書(shū)的第一個(gè)練習(xí)!您可以在清單 1.1.b 和編碼文件的末尾文件夾中找到形狀庫(kù)的完整代碼。當(dāng)您構(gòu)建第一個(gè) D3 項(xiàng)目時(shí),請(qǐng)使用此練習(xí)作為參考。
清單 1.1.b 用于 SVG 形狀圖庫(kù)練習(xí)的完整 HTML 文件
<!DOCTYPE html>
<html>
<head> [...] </head>
<body>
<div style="width:100%; max-width:1200px; margin:0 auto;">
<svg viewBox="0 0 900 300" style="border:1px solid black;">
<line x1="50" y1="45" x2="140" y2="225" stroke="black" />
<rect x="260" y="25" width="120" height="60" fill="#6ba5d7" />
<rect x="260" y="100" width="120" height="60" rx="20" ry="20"
? fill="#6ba5d7" />
<g transform="translate(260, 175)">
<rect x="0" y="0" width="60" height="60" fill="transparent"
? stroke="#6ba5d7" />
<text x="0" y="85">rect</text>
</g>
<circle cx="530" cy="80" r="50" fill="none" stroke="#81c21c" stroke-
? width="3" />
<ellipse cx="530" cy="205" rx="50" ry="30" fill="#81c21c" />
<path d="M680 150 C 710 80, 725 80, 755 150 S 810 220, 840 150"
? fill="none" stroke="#773b9a" stroke-width="3" />
<g fill="#636466" style="font-size:16px; font-family:monospace">
<text x="60" y="260">line</text>
<text x="530" y="155" style="text-anchor:middle">circle</text>
<text x="530" y="260" style="text-anchor:middle">ellipse</text>
<text x="730" y="260">path</text>
</g>
</svg>
</div>
</body>
</html>
現(xiàn)在輪到你了!創(chuàng)建如下圖所示的 SVG 圖形。您可以在本章代碼文件start內(nèi)的文件夾中工作。02_SVG_exercise以下是一些指導(dǎo)原則:
· 創(chuàng)建一個(gè)寬度和高度均為 400 像素的響應(yīng)式 SVG 容器(當(dāng)屏幕上有足夠的空間時(shí))。
· 繪制一個(gè)寬度和高度均為 200 像素的正方形。將其置于 SVG 容器的中心,并為其提供透明填充和 5px 黑色描邊。
· 在 SVG 容器的中心添加一個(gè)半徑為 100px 的圓。將其填充屬性設(shè)置為 CSS 顏色名稱“plum”。
· 繪制兩條對(duì)角黑線,筆劃為 5 像素。一個(gè)從正方形的左上角到右下角。另一個(gè)從正方形的右上角到左下角。
· 添加文本“SVG 太棒了!” 位于正方形上方并將其置于 SVG 容器的中心。為文本指定以下樣式屬性:字體大小為 18px,字體系列為 sans-serif。
我們鼓勵(lì)您構(gòu)建此 SVG 圖形來(lái)強(qiáng)化本節(jié)中討論的概念。
02_SVG_exercise / end您可以在附錄 D 的 D.1.1 節(jié)和本章代碼文件的文件夾中找到解決方案。我們鼓勵(lì)您嘗試自己完成它。
我們已經(jīng)提到過(guò),我們通常使用 SVG 元素構(gòu)建 D3 項(xiàng)目。有時(shí),我們可能需要從大型數(shù)據(jù)集創(chuàng)建復(fù)雜的可視化效果,而傳統(tǒng)的 SVG 方法可能會(huì)產(chǎn)生性能問(wèn)題。請(qǐng)務(wù)必記住,對(duì)于數(shù)據(jù)可視化中的每個(gè)圖形細(xì)節(jié),D3 都會(huì)將一個(gè)或多個(gè) SVG 元素附加到 DOM。一個(gè)典型的例子是由數(shù)千個(gè)節(jié)點(diǎn)和鏈接組成的大型網(wǎng)絡(luò)可視化。這些可能會(huì)讓你的瀏覽器喘不過(guò)氣來(lái)……盡管瀏覽器可以輕松處理的對(duì)象數(shù)量隨著性能的提高而不斷增加,但普遍接受的經(jīng)驗(yàn)法則是,如果滿足以下條件,我們應(yīng)該考慮使用畫(huà)布而不是 SVG:可視化包含 1000 多個(gè)元素。
Canvas 是一種客戶端繪圖 API,它使用腳本(通常是 JavaScript)來(lái)創(chuàng)建視覺(jué)效果和動(dòng)畫(huà)。它不會(huì)將 XML 元素添加到 DOM,這在從大型數(shù)據(jù)集構(gòu)建可視化時(shí)可以顯著提高性能。
Canvas 還允許您使用 WebGL API 來(lái)創(chuàng)建 3D 對(duì)象。盡管學(xué)習(xí) WebGL 超出了本書(shū)的范圍,但為 Web 創(chuàng)建 3D 數(shù)據(jù)可視化是可能的。目前主要用于實(shí)驗(yàn)項(xiàng)目。在第 15 章中,我們將介紹如何使用畫(huà)布構(gòu)建可視化并討論其優(yōu)點(diǎn)和缺點(diǎn)。
CSS 代表層疊樣式表,是一種描述 DOM 元素如何在屏幕上顯示及其外觀的語(yǔ)言。從頁(yè)面的整體網(wǎng)格布局到文本使用的字體系列,再到散點(diǎn)圖中圓圈的顏色,CSS 可以將普通的 HTML 文件變成令人驚嘆的網(wǎng)頁(yè)。在 D3 項(xiàng)目中,我們通常使用內(nèi)聯(lián)樣式或通過(guò)外部樣式表應(yīng)用 CSS 樣式。
內(nèi)聯(lián)樣式應(yīng)用于具有該style屬性的元素,如以下示例所示。該style屬性可以在傳統(tǒng)的 HTML 或 SVG 元素上使用,D3 有一個(gè)方便的方法來(lái)設(shè)置或修改該屬性,我們將在第 2 章中討論。
<div style="padding:10px; background:#00ced1;"> ... </div>
<text style="font-size:16px; font-family:serif;"> ... </text>
內(nèi)聯(lián)樣式僅影響應(yīng)用它們的元素。如果我們想要將相同的設(shè)計(jì)傳播到多個(gè)元素,我們需要將相同的style屬性應(yīng)用于每個(gè)元素(或?qū)⑺性匕b在一起的 SVG 組)。它當(dāng)然有效,但不是最有效的方法。
另一方面,外部 CSS 樣式表非常適合全局應(yīng)用樣式。一種策略是要求 D3 將相同的類名添加到多個(gè)元素。然后,我們使用此類名稱作為外部樣式表中的選擇器,并將相同的樣式屬性應(yīng)用于目標(biāo)元素組,如以下示例所示。這種方法效率更高,尤其是在維護(hù)大型項(xiàng)目時(shí)。它還遵循關(guān)注點(diǎn)分離原則,即我們將由 JavaScript 控制的行為與由 CSS 監(jiān)管的樣式分開(kāi)。請(qǐng)注意,CSS 預(yù)處理器(例如 SASS 和 LESS)是此處描述的外部樣式表方法的一部分。
在 CSS 樣式表中:
.my-class {
font-size: 16px;
font-family: serif;
}
In the DOM:
<text class="my-class"> ... </text>
請(qǐng)記住,內(nèi)聯(lián)樣式優(yōu)先于從外部樣式表應(yīng)用的樣式。在任何前端開(kāi)發(fā)項(xiàng)目中,規(guī)劃 CSS 樣式的架構(gòu)并考慮級(jí)聯(lián)順序非常重要。
D3 是一個(gè) JavaScript 庫(kù)。它在 JavaScript 現(xiàn)有核心功能的基礎(chǔ)上添加了新方法。這意味著在使用 D3 時(shí),具有一點(diǎn) JavaScript 經(jīng)驗(yàn)會(huì)很有幫助。這也意味著,在構(gòu)建 D3 項(xiàng)目時(shí),您可以訪問(wèn)所有現(xiàn)有的 JavaScript 功能。
在本節(jié)中,我們將解釋 D3 項(xiàng)目中廣泛使用的兩個(gè) JavaScript 主題:方法鏈和對(duì)象操作。
如果您在網(wǎng)絡(luò)上搜索 D3 項(xiàng)目的示例,您會(huì)發(fā)現(xiàn)在同一選擇上會(huì)依次調(diào)用方法。這種技術(shù)就是我們所說(shuō)的方法鏈,有助于保持代碼簡(jiǎn)潔和可讀。
我們可以將方法鏈視為汽車(chē)裝配線。假設(shè)我們編寫(xiě)了運(yùn)行這樣一條裝配線的腳本。正如您在下面的示例中看到的,我們首先聲明一個(gè)car創(chuàng)建新Car()對(duì)象的變量。然后我們調(diào)用函數(shù)putOnHood(),將引擎蓋放在汽車(chē)頂部,然后我們繼續(xù)調(diào)用將放置車(chē)輪、輪胎和燈的函數(shù)。每個(gè)連續(xù)的調(diào)用都會(huì)添加一個(gè)元素到Car()對(duì)象,并且,一旦執(zhí)行了所有方法,汽車(chē)就有了引擎蓋、車(chē)輪、輪胎和車(chē)燈。每個(gè)方法都會(huì)將更新后的汽車(chē)對(duì)象傳遞給下一個(gè)方法,從而“鏈接”。請(qǐng)注意,每個(gè)調(diào)用都用點(diǎn)分隔,并且調(diào)用方法的順序很重要。在我們的汽車(chē)裝配線示例中,我們需要先安裝車(chē)輪,然后才能將輪胎安裝到車(chē)輪上。
let car = new Car().putOnHood().putOnWheels().putOnTires().putOnLights();
現(xiàn)在讓我們看看如何在 D3 中使用方法鏈接。想象一下,我們想要從 DOM 中獲取所有 div 并在每個(gè) div 中添加一個(gè)段落元素。段落元素應(yīng)具有類屬性my-class并包含文本“Wow”。然后,我們要在每個(gè)段落中插入一個(gè) span 元素,并將文本“Even More Wow”以粗體顯示。如果沒(méi)有方法鏈接,我們需要將每個(gè)操作存儲(chǔ)到一個(gè)常量中,然后在執(zhí)行下一個(gè)操作時(shí)調(diào)用該常量,如下所示。光是看著就已經(jīng)很累了……
const mySelection = d3.selectAll("div");
const myParagraphs = mySelection.append("p");
const myParagraphsWithAClass = myParagraphs.attr("class", "my-class");
const myParagraphsWithText = myParagraphsWithAClass.text("Wow");
const mySpans = myParagraphsWithText.append("span");
const mySpansWithText = mySpans.text("Even More Wow")
const myBoldSpans = mySpansWithText.style("font-weight", "900");
由于方法鏈接,相同的示例變得更加簡(jiǎn)潔。
d3.selectAll("div").append("p").attr("class", "my-class").text("Wow")
? .append("span").text("Even More Wow").style("font-weight", "900");
在 D3 中,斷行(JavaScript 會(huì)忽略這一點(diǎn))以及縮進(jìn)鏈接方法是很常見(jiàn)的。這使得代碼更容易閱讀,并且縮進(jìn)可以幫助我們看到我們正在處理哪個(gè)元素。
d3.selectAll("div")
.append("p")
.attr("class", "my-class")
.text("Wow")
.append("span")
.text("Even More Wow")
.style("font-weight", "900");
不要擔(dān)心理解前面的代碼示例的作用,盡管您完全可以從不同方法的名稱中猜出它!目前,我們只希望您熟悉如何在 JavaScript 中鏈接方法。我們將在第 2 章中介紹 D3 特定的術(shù)語(yǔ)。
D3 都是關(guān)于數(shù)據(jù)的,而數(shù)據(jù)通常被構(gòu)造為 JavaScript 對(duì)象。了解這些對(duì)象的構(gòu)造以及如何訪問(wèn)和操作它們包含的數(shù)據(jù)將為您構(gòu)建可視化提供巨大幫助。
我們首先討論簡(jiǎn)單數(shù)組,它是元素列表。在與數(shù)據(jù)相關(guān)的項(xiàng)目中,數(shù)組通常是數(shù)字或字符串的有序列表。
const arrayOfNumbers = [17, 82, 9, 500, 40];
const arrayOfStrings = ["blue", "red", "yellow", "orange"];
數(shù)組中的每個(gè)元素都有一個(gè)數(shù)字位置,稱為索引,數(shù)組中第一個(gè)元素的索引為 0。
arrayOfNumbers[0] // => 17
arrayOfStrings[2] // => "yellow"
數(shù)組具有長(zhǎng)度屬性,對(duì)于非稀疏數(shù)組,該屬性指定它們包含的元素?cái)?shù)量。由于數(shù)組是零索引的,因此數(shù)組中最后一個(gè)元素的索引對(duì)應(yīng)于數(shù)組長(zhǎng)度減一。
arrayOfNumbers.length; // => 5
arrayOfStrings[arrayOfStrings.length - 1] // => "orange"
我們還可以使用方法來(lái)確定數(shù)組是否包含特定值includes()。true如果數(shù)組中的元素之一與作為參數(shù)傳遞的值完全對(duì)應(yīng),則此方法返回。否則,它返回false。
arrayOfNumbers.includes(9) // => true
arrayOfStrings.includes("pink") // => false
arrayOfStrings.includes("ellow") // => false
然而,大多數(shù)數(shù)據(jù)集并不是簡(jiǎn)單的數(shù)字或字符串列表,它們的每個(gè)數(shù)據(jù)點(diǎn)通常由多個(gè)屬性組成。讓我們想象一個(gè)虛構(gòu)機(jī)構(gòu)的員工數(shù)據(jù)庫(kù),如表 1.1 所示。該表包含四列:每個(gè)員工的 ID、姓名和職位,以及該員工是否在 D3 工作。
ID | 姓名 | 位置 | 與_d3一起工作 |
1 | 佐伊 | 數(shù)據(jù)分析師 | 錯(cuò)誤的 |
2 | 詹姆士 | 前端開(kāi)發(fā)人員 | 真的 |
3 | 愛(ài)麗絲 | 全棧開(kāi)發(fā)人員 | 真的 |
4 | 休伯特 | 設(shè)計(jì)師 | 錯(cuò)誤的 |
數(shù)據(jù)集中的每一行或數(shù)據(jù)點(diǎn)都可以由 JavaScript 對(duì)象表示,如下所示row1。
const row1 = {
id:"1",
name:"Zoe",
position:"Data analyst",
works_with_d3:false
};
我們可以使用點(diǎn)符號(hào)輕松訪問(wèn)對(duì)象中每個(gè)屬性的值。
row1.name // => "Zoe"
row1.works_with_d3 // => false
我們還可以使用括號(hào)表示法訪問(wèn)這些值。如果屬性名稱包含空格等特殊字符,或者如果我們之前將屬性名稱保存在常量或變量中,那么括號(hào)表示法會(huì)很方便。
row1["position"] // => "Data analyst"
const myProperty = "works_with_d3";
row1[myProperty] // => false
在現(xiàn)實(shí)生活中,數(shù)據(jù)集通常被格式化為對(duì)象數(shù)組。例如,如果我們使用 D3 加載表 1.2 中包含的數(shù)據(jù)集(正如我們將在第 3 章中學(xué)習(xí)的那樣),我們將獲得以下對(duì)象數(shù)組,可以將其保存在名為 的常量中data。
const data = [
{id:"1", name:"Zoe", position:"Data analyst", works_with_d3:false},
{id:"2", name:"James", position:"Frontend developer", works_with_d3:true},
{id:"3", name:"Alice", position:"Fullstack developer", works_with_d3:true},
{id:"4", name:"Hubert", position:"Designer", works_with_d3:false}
];
data我們可以使用循環(huán)遍歷數(shù)組中的每個(gè)元素或數(shù)據(jù)點(diǎn)。更具體地說(shuō),JavaScript forEach循環(huán)非常方便且易于編寫(xiě)和閱讀。迭代數(shù)據(jù)集的一個(gè)常見(jiàn)用例是數(shù)據(jù)整理。當(dāng)我們加載外部 CSV 文件時(shí),數(shù)字通常被格式化為字符串。讓我們以data數(shù)組為例,將屬性的值id從字符串轉(zhuǎn)換為數(shù)字。
在下面的示例中,數(shù)組迭代器使d我們能夠訪問(wèn)每個(gè)對(duì)象。使用點(diǎn)符號(hào),我們id使用運(yùn)算符將?每個(gè)值轉(zhuǎn)換為數(shù)字+。
data.forEach(d => {
d.id = +d.id;
});
JavaScript 提供了許多數(shù)組迭代器方法,可以幫助我們與數(shù)據(jù)交互,甚至在需要時(shí)重塑數(shù)據(jù)。假設(shè)我們想要將數(shù)據(jù)集中的每個(gè)員工定位到可視化上。創(chuàng)建一個(gè)僅包含員工姓名的簡(jiǎn)單數(shù)組可能會(huì)派上用場(chǎng),為此我們將使用map()方法。
data.map(d => d.name); // => ["Zoe", "James", "Alice", "Hubert"]
同樣,如果我們只想隔離使用 D3 的員工,我們可以使用這些filter()方法。
data.filter(d => d.works_with_d3);
// => [
{id:2, name:"James", position:"Frontend developer", works_with_d3:true},
{id:4, name:"Hubert", position:"Designer", works_with_d3:true}
];
最后,我們可以通過(guò)該方法找到id為3的員工find()。請(qǐng)注意,該find()方法在找到它要查找的值后停止迭代。我們只能在搜索單個(gè)數(shù)據(jù)點(diǎn)時(shí)使用此方法。
data.find(d => d.id === 3);
// => {id:"3", name:"Alice", position:"Fullstack developer", works_with_d3:true}
本節(jié)討論的方法遠(yuǎn)未涵蓋 JavaScript 提供的所有數(shù)組和對(duì)象操作技術(shù)。但在處理數(shù)據(jù)時(shí),您可能會(huì)不斷回想起它們。每當(dāng)您需要找到另一種方法來(lái)訪問(wèn)或操作數(shù)據(jù)時(shí),MDN Web 文檔 ( https://developer.mozilla.org/ ) 始終是包含大量示例的可靠參考。
JavaScript 在過(guò)去十年中發(fā)生了重大變化。現(xiàn)代 JavaScript 的兩個(gè)最重要的趨勢(shì)是 Node.js 的興起和 JavaScript 框架作為大多數(shù)項(xiàng)目標(biāo)準(zhǔn)的建立。
對(duì)于 D3 項(xiàng)目,我們想了解的主要 Node 技術(shù)是 NPM,即 Node Package Manager。NPM 允許您安裝“模塊”或小型 JavaScript 代碼庫(kù)以在應(yīng)用程序中使用。您不必包含<script>對(duì)單個(gè)文件的一堆標(biāo)記引用,并且如果模塊已構(gòu)建為不是一個(gè)整體結(jié)構(gòu),則可以減少應(yīng)用程序中包含的代碼量。
D3.js 版本 7 于 2021 年中期發(fā)布,利用了模塊導(dǎo)入的優(yōu)勢(shì)。在本書(shū)中,您將看到以兩種方式之一使用 D3 的示例。我們要么加載整個(gè) D3 庫(kù),就像我們?cè)诘?2 章中所做的那樣,要么只包含我們需要的 D3 的各個(gè)部分,正如您將在后面的示例中看到的那樣。我們可以使用腳本標(biāo)簽來(lái)做到這一點(diǎn),但從第 2 部分開(kāi)始,我們將使用 NPM 導(dǎo)入 D3 模塊,因?yàn)檫@被認(rèn)為是當(dāng)今的標(biāo)準(zhǔn)做法。如果您交付專業(yè)的 D3 項(xiàng)目,您可能需要熟悉它。
如果您已經(jīng)參與了專業(yè)的 Web 項(xiàng)目,那么您也很有可能正在使用 JavaScript 框架,例如 React、Angular、Vue 或 Svelte。框架為開(kāi)發(fā)人員提供了使用模塊化、可重用且可測(cè)試的代碼構(gòu)建 Web 項(xiàng)目的基礎(chǔ)。這些框架負(fù)責(zé)構(gòu)建和更新 DOM,這也是 D3 庫(kù)所做的事情。在第 8 章中,我們將討論在 JavaScript 框架內(nèi)構(gòu)建 D3 可視化時(shí)避免沖突的策略。
最后,在專業(yè)的工作環(huán)境中,您可能會(huì)將 D3 與 TypeScript 結(jié)合使用。TypeScript 是 JavaScript 的語(yǔ)法超集,為代碼添加了類型安全性。盡管我們不會(huì)在本書(shū)中詳細(xì)討論它,但 D3 方法的類型可以使用 NPM 包 @type/d3 ( https://www.npmjs.com/package/@types/d3 ) 進(jìn)行安裝。在第 8 章中,我們將在 Angular 項(xiàng)目中使用此類類型。
如果您在網(wǎng)絡(luò)上搜索 D3 項(xiàng)目的示例,您無(wú)疑會(huì)遇到 Observable 筆記本 ( observablehq.com )。Observable 是數(shù)據(jù)科學(xué)和可視化的協(xié)作平臺(tái),類似于 Python 項(xiàng)目的 Jupyter 環(huán)境。Observable 平臺(tái)由 Mike Bostock 創(chuàng)建,取代了之前的在線 D3 沙箱bl.ocks.org 。所有官方的 D3 示例現(xiàn)在都位于 Observable 上,并且 D3 社區(qū)在那里非常活躍。
重要的是要知道 Observable 要求您學(xué)習(xí)一種處理特定于該平臺(tái)的 D3 項(xiàng)目的方法。此外,您不能直接將 Observable Notebook 復(fù)制粘貼到前端開(kāi)發(fā)環(huán)境中(但有多種方法可以導(dǎo)出和重用它們)。由于本書(shū)的重點(diǎn)是在類似于我們?nèi)绾谓桓?D3 項(xiàng)目進(jìn)行生產(chǎn)的環(huán)境中構(gòu)建 D3 可視化,因此我們不會(huì)討論 Observable 筆記本。如果您有興趣學(xué)習(xí) Observable,您可以在observablehq.com/tutorials找到一系列優(yōu)秀的教程。您將在本書(shū)中學(xué)到的大部分技術(shù)和概念都可以轉(zhuǎn)化為 Observable 筆記本。
數(shù)據(jù)可視化從未像今天這樣流行。豐富的地圖、圖表以及系統(tǒng)和數(shù)據(jù)集的復(fù)雜表示不僅存在于工作場(chǎng)所,而且還存在于我們的娛樂(lè)和日常生活中。隨著這種流行,使用視覺(jué)手段以及美學(xué)規(guī)則來(lái)表示數(shù)據(jù)和信息的類和子類庫(kù)不斷增長(zhǎng),以促進(jìn)易讀性和理解性。您的受眾,無(wú)論是公眾、學(xué)者還是決策者,已經(jīng)習(xí)慣了我們?cè)?jīng)認(rèn)為極其抽象和復(fù)雜的數(shù)據(jù)趨勢(shì)表示。這使得 D3 這樣的庫(kù)不僅受到數(shù)據(jù)科學(xué)家的歡迎,而且還受到記者、藝術(shù)家、學(xué)者、IT 專業(yè)人士,甚至數(shù)據(jù)可視化愛(ài)好者的歡迎。
如此豐富的選項(xiàng)似乎讓人不知所措,而且修改數(shù)據(jù)集以顯示在流圖、樹(shù)狀圖或直方圖中相對(duì)容易,這往往會(huì)促進(jìn)這樣一種觀念:信息可視化更多地是關(guān)于風(fēng)格而不是實(shí)質(zhì)內(nèi)容。幸運(yùn)的是,完善的規(guī)則規(guī)定了針對(duì)不同系統(tǒng)的不同數(shù)據(jù)類型使用哪些圖表和方法。本書(shū)并不旨在涵蓋數(shù)據(jù)可視化中的所有最佳實(shí)踐,但我們將介紹其中的一些。盡管開(kāi)發(fā)人員使用 D3 徹底改變了顏色和布局的使用,但大多數(shù)人希望創(chuàng)建支持實(shí)際問(wèn)題的數(shù)據(jù)的可視化表示。
當(dāng)您構(gòu)建第一個(gè)可視化項(xiàng)目時(shí),如果有疑問(wèn),請(qǐng)簡(jiǎn)化 - 通常,呈現(xiàn)直方圖比小提琴圖更好,或者分層網(wǎng)絡(luò)布局(如樹(shù)狀圖)比力導(dǎo)向的網(wǎng)絡(luò)布局更好。視覺(jué)上更復(fù)雜的數(shù)據(jù)顯示方法往往會(huì)激發(fā)更多的興奮,但也會(huì)導(dǎo)致觀眾關(guān)注圖形的美觀而不是數(shù)據(jù)。創(chuàng)建酷炫且令人瞠目結(jié)舌的可視化并沒(méi)有什么錯(cuò),但我們永遠(yuǎn)不應(yīng)該忘記任何數(shù)據(jù)可視化的主要目標(biāo)都是講述一個(gè)故事。詢問(wèn)周?chē)娜耸欠窭斫饽愕目梢暬约八麄內(nèi)绾谓忉屗侵陵P(guān)重要的一步。他們需要解釋嗎?他們可以從與您的項(xiàng)目的互動(dòng)中得出哪些結(jié)論?故事被講述了嗎?
盡管如此,為了正確部署信息可視化,您應(yīng)該知道該做什么和不該做什么。您需要對(duì)您的數(shù)據(jù)和受眾有深入的了解。D3 賦予我們巨大的靈活性,但正如俗話所說(shuō),“能力越大,責(zé)任越大”。雖然知道某些圖表更適合表示特定類型的數(shù)據(jù)固然很好,但更重要的是要記住,如果不謹(jǐn)慎地從知情的角度構(gòu)建數(shù)據(jù)可視化,則可能會(huì)攜帶錯(cuò)誤信息。如果您打算設(shè)計(jì)自己的可視化,那么了解數(shù)據(jù)可視化最佳實(shí)踐是至關(guān)重要的。了解這一點(diǎn)的最佳方法是回顧知名設(shè)計(jì)師和信息可視化從業(yè)者的工作。盡管整個(gè)圖書(shū)館的作品都在處理這些問(wèn)題,以下是我們發(fā)現(xiàn)的一些有用的內(nèi)容,可以幫助您了解基礎(chǔ)知識(shí)。這些絕不是學(xué)習(xí)數(shù)據(jù)可視化的唯一文本,但它們是一個(gè)很好的起點(diǎn)。
在閱讀有關(guān)數(shù)據(jù)可視化的內(nèi)容時(shí)要記住的一件事是,文獻(xiàn)通常關(guān)注靜態(tài)圖表。使用 D3,您將進(jìn)行交互式動(dòng)態(tài)可視化。一些交互可以使可視化不僅更具可讀性,而且更有吸引力。感覺(jué)自己是在探索而不是閱讀的用戶,即使只是將鼠標(biāo)懸停在事件上幾次或簡(jiǎn)單地單擊進(jìn)行縮放,也可能會(huì)發(fā)現(xiàn)可視化的內(nèi)容比閱讀靜態(tài)等效內(nèi)容更引人注目和更令人難忘。但這種增加的復(fù)雜性需要了解用戶體驗(yàn)。我們將在第 7 章中更詳細(xì)地討論這一點(diǎn)。
我們的第一章到此結(jié)束!盡管我們還沒(méi)有使用過(guò) D3,但您現(xiàn)在已經(jīng)掌握了入門(mén)所需的所有知識(shí)。當(dāng)您不確定應(yīng)該在可視化中使用哪個(gè) SVG 元素或者需要提醒如何使用 JavaScript 操作數(shù)據(jù)時(shí),請(qǐng)繼續(xù)返回本章。從下一章開(kāi)始,我們將卷起袖子,創(chuàng)建 D3 可視化。
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。