當前內容所在位置
- 第一部分 D3.js 基礎知識
- 第一章 D3.js 簡介
- 1.1 何為 D3.js?
- 1.2 D3 生態系統——入門須知
- 1.2.1 HTML 與 DOM
- 1.2.2 SVG - 可縮放矢量圖形 ??
- 第一部分
- 【第二部分】??
- 第三部分(精譯中 ?)
- 1.2.3 Canvas 與 WebGL(待翻譯)
- 1.2.4 CSS(待翻譯)
- 1.2.5 JavaScript(待翻譯)
- 1.2.6 Node 與 JavaScript 框架(待翻譯)
- 1.2.7 Observable 記事本(待翻譯)
譯注
(接 1.2.2 小節(一))
……正如您看到的那樣,viewBox
屬性由四個屬性值組成。前兩個數值指定了viewBox
的坐標系原點(x
和y
)。本書將統一使用0 0
,知道這些值可以調整 SVG 容器在屏幕的可見部分還是很有幫助的。viewBox
后兩個數值分別指定了寬度(width)和高度(height)。它們定義了 SVG 的寬高比,并確保它能完美適應任何容器并作相應縮放而不致失真。
(……而不致失真。)這里的關鍵是讓 SVG 的尺寸與容器相適應。此時 SVG 所在容器為 <body>
元素,而 <body>
的尺寸又常常與瀏覽器視口(viewport)相適應。如果視口變得非常大,SVG 也會相應變大。通常,SVG 需要一個最大寬度,以免寬度超過頁面上的其他內容。因此,SVG 需要放進一個 div
里面,并讓該 div
的寬度為 100%
、最大寬度為 1200px
。為簡便起見,我們將這些樣式設為行內樣式;實際項目中,它們都應該來自某個 CSS 文件。注意,為了讓 SVG 水平居中,還多加了一個值為 0 auto
的外邊距:
<div style="width:100%; max-width:1200px; margin:0 auto;"><svg viewBox="0 0 900 300" style="border:1px solid black;"> ... </svg>
</div>
改好后,再次調整瀏覽器大小,看看 SVG 是否能在保持最大寬度的情況下優雅適應任意屏幕大小。該方案有助于將 D3 可視化模塊注入到響應式網頁中,本書后續都將采用該方案進行演示。
2 SVG 的坐標系
實現 SVG 的響應式設計后,接下來需要重點考慮 SVG 圖形在容器內的定位問題。SVG 容器就像一個空白畫布,我們可以在上面繪制矢量圖形。矢量圖形是根據基本幾何原理定義的,并相對于 SVG 容器的坐標系進行定位。
SVG 坐標系類似于直角坐標系,其二維平面通過兩個相互垂直的軸來定位元素,即 x
軸和 y
軸;這兩個軸的起點均為 SVG 容器的 左上角,如圖 1.11 所示。y
軸的正方向為 從上到下,記住它可以少走很多彎路。
圖 1.11 SVG 容器坐標系與元素位置
要在 SVG 容器內定位一個元素,可以從左上角的原點開始向右移動。這樣就得到了元素的水平位置(即 x);垂直位置(即 y)則從頂部開始向下移動。這些位置信息均由 SVG 圖形的呈現屬性(presentational attributes)來定義。
下面來看看構建 D3 項目常見的 SVG 圖形及其主要的呈現屬性。我們的目標并不是編寫一份涵蓋所有 SVG 圖形及其功能特性的全方位指南,而是希望這些基礎知識不會在后續的 D3 學習中拖您后腿。
數據可視化小知識:幾何基元(Geometric primitives)
出色的藝術家可以用矢量圖形來繪制任何事物,但您可能是帶著更實際的目標來學習 D3 的。從這個角度來看,理解幾何基元(也稱圖形基元,graphical primitives)的概念至關重要。幾何基元是一些簡單的形狀,如點、線、圓和矩形。這些圖形可以組合成更復雜的圖形,尤其便于直觀地展示信息。
幾何基元對于理解現實世界中復雜的信息可視化也很有用。比如本書第 11 章要構建的樹形布局,在您意識到它們也不過是一些圓和線時,也就不會那么令人生畏了;當您把交互式時間線看作是矩形和點的集合時,它們就更容易理解和創建了;即使是主要以多邊形、點和線的形式出現的地理數據,如果將其分解為最基本的圖形結構,也就不會那么令人困惑了。
3 直線
直線元素可能是所有 SVG 圖形中最簡單的。它需要兩個點的位置信息作屬性值,并在它們之間繪制出一條直線。回到 index.html
示例文件,在 SVG 容器內添加一個 <line />
元素,并令其 x1
和 y1
屬性分別為 50
和 45
。也就是說,該直線的起點位于 SVG 坐標系的 (50, 45)
。如果從 SVG 容器的左上角開始,右移 50px
、下移 45px
,就會到達該起點;同理,利用屬性 x2
和 y2
可將該直線的終點坐標設為 (140, 225)
,如圖 1.12 所示。
<svg><line x1="50" y1="45" x2="140" y2="225" />
</svg>
圖 1.12 在 SVG 容器坐標系中定位直線元素
如果保存并重新加載項目,會發現直線不可見——要讓它可見,還需要設置其 stroke
屬性(attribute)。stroke
用于控制直線段的描邊顏色,其值與 CSS 的 color
屬性(property)類似;該取值可以是一個顏色名稱(black
、blue
…)、一個 RGB 顏色值(rgb(255,0,0)
)或一個十六進制值(#808080
)。給直線段添加一個 stroke
描邊屬性,并選擇合適的顏色(示例為黑色),應該就能顯示了:
<line x1="50" y1="45" x2="140" y2="225" stroke="black" />
要設置線條寬度,使用 stroke-width
屬性。該屬性可接受一個絕對數(轉換為像素)或一個相對值(%)。例如下面一行代碼,直線的 stroke-width
為 3px
。如果未聲明 stroke-width
,瀏覽器將默認取 1px
。
<line x1="50" y1="45" x2="140" y2="225" stroke="black" stroke-width="3" />
打開瀏覽器的檢查工具(Inspect),找到 SVG 節點及其包含的直線。雙擊其中一個屬性并修改它的值,觀察新的屬性值對直線起點或終點的影響。再嘗試不同的值,以確認您充分理解了屬性 x1
、y1
、x2
及 y2
對直線位置和長度的影響。
接著,令 x1
屬性值為 -20
,如圖 1.13 所示:
圖 1.13 直線在 SVG 容器外的部分被隱藏
看到直線的起點消失了嗎? 在 SVG 中,任何位于 viewBox
之外的形狀(或形狀的一部分)在屏幕上都是不可見的。 此時該元素仍然在 DOM 中,并且可以訪問和操作。當 SVG 元素不可見,而您又不清楚原因時,則需要首先檢查該元素是否在 SVG 的 viewBox
之外!請牢牢記住,您可以隨時通過開發工具查看 DOM 來找到它。前面講過,在檢查工具中只要將鼠標放到該元素上,就算它在 SVG 的 viewBox
之外,也會在視口中高亮顯示。
注意
大多數 SVG 元素只需要一個自閉合標簽即可(如使用
<line />
而非<line></line>
)。與其他一些 HTML 標簽一樣,SVG 元素的固有結構在它們的自閉合標簽內已經提供了所有必要的信息;但文本元素屬于例外——其文本須放到開閉標簽之間。
4 矩形
矩形元素 <rect />
,顧名思義,會在屏幕上畫出一個矩形。<rect />
元素需要四個屬性(attributes)才能正常顯示。如圖 1.14 所示,屬性 x
和 y
聲明了矩形左上角的位置;屬性 width
和 height
分別控制其寬度和高度。在 SVG 容器中添加以下 <rect />
元素及其屬性:
<rect x="260" y="25" width="120" height="60" fill="#6ba5d7" />
示例中,矩形的左上角位于 SVG 容器原點的右側 260px
,下方 25px
;該矩形寬 120px
,高 60px
。與其他定位屬性一樣,這些屬性值也可以用百分比來進行設置。例如將 width
設置為 50%
,則該矩形將占據 SVG 容器寬度的一半。
圖 1.14 在 SVG 坐標系中定位和調整矩形尺寸
您或許注意到了,示例中的矩形被填充成了黑色。默認情況下,瀏覽器會將大多數 SVG 圖形填充為黑色。要修改默認的填充色,可以設置元素的 fill
屬性,令其值為任意 CSS 顏色值即可;要給矩形添加邊框,則可以添加 stroke
屬性。圖 1.15 展示了幾個例子。注意,如果不聲明 stroke
屬性,則矩形四周不會描邊。此外,在最后一個示例矩形中,屬性 fill-opacity
和 stroke-opacity
可分別令 fill
和 stroke
屬性變為半透明效果。與 CSS 一樣,不透明程度(opacity)可設為絕對值(介于 0
和 1
之間)或百分比(30%
);與填充和描邊相關的所有屬性也都可以通過 CSS 文件進行設置或修改。
圖 1.15 應用于矩形 SVG 圖形的不同樣式屬性
如果想繪制帶圓角的矩形,只需添加 rx
和 ry
屬性即可,分別表示水平與垂直角半徑。這些屬性接受絕對值(像素)和相對值(百分比)。例如,下面矩形的每個角的半徑都是 20px
。將該矩形添加到示例中:
<rect x="260" y="100" width="120" height="60" rx="20" ry="20" fill="#6ba5d7" />
講到這您可能會問:SVG 中有沒有專門畫正方形的元素呢?答案是不需要——只要讓 <rect />
元素 width
和 height
屬性相同就行了。例如下面的 <rect />
元素,最終將畫出一個 60px × 60px
的正方形。在示例頁中添加以下內容:
<rect x="260" y="175" width="60" height="60" fill="transparent" stroke="#6ba5d7" />
作為參考,現在 SVG 畫廊里有三種矩形:經典矩形、圓角矩形以及正方形。為了增添趣味性,先將顏色統一設為 #6ba5d7
,再來玩玩它們的 stroke
和 fill
屬性。注意,正方形上只有描邊(stroke)是可見的,因為其 fill
屬性值為 transparent
(為 none
也是一樣的)。這些矩形應該與圖 1.16 相似,除非您更改了屬性值,我們也希望您改改看!
<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" />
圖 1.16 三種 SVG 矩形效果
關于 SVG 描邊(strokes)的位置
當對齊可視化項目中的圖形時,需要特別注意:SVG 圖形繪制出的描邊是在內外邊界上平均展布的。如下圖所示,已知一個
width
屬性為40px
的矩形,令stroke-width
的值為1
,則在視覺效果上會在矩形的左右兩邊各增加寬度為0.5px
的描邊(而不是下意識地以為的那樣在各邊均增加1px
),最終實際的總寬度為41px
;若令stroke-width
的值為2
,則左右兩邊各增加1px
,以此類推。
描邊寬度
stroke-width
對 SVG 圖形實際寬度的影響