Scalable Vector Graphics 是一個成熟的W3C標准,被設計用來在web和移動平台 上展示可交互的圖形。和HTML類似,SVG也支持CSS和JavaScript。盡管可以使用 HTML展示數據,SVG才是數據可視化領域的事實標准。
我們在右邊的示例中,簡短回顧一下SVG的常用元素:
- SVG文檔:svg
- 分組:g
- 矩形:rect
- 圓形:circle
- 橢圓:ellipse
- 折線:polyline
- 多邊形:polygon
- 文字:text
- 路徑:path
d3的選擇集支持SVG,我們可以套用HTML的那些操作方法操作SVG文檔。
path構造器
使用path,可以畫出你能想象的任何形狀(參看→_→示例代碼的效果)。但是,如果沒 有編輯器進行交互的繪制,要手寫出這些數值基本是不可能的:
- <svg>
- <!--可以使用path元素畫任意圖形-->
- <path d="..."></path>
- </svg>
為了在自動化的數據處理流水線中使用path元素,d3引入了構造器/generator, 這些構造器的功能,就是根據你給定的一些參數,生成path元素所需要的d 屬性值:
- 曲線構造器:根據給定的關鍵點,返回曲線的d字符串
- 區域構造器:根據給定的關鍵點,返回區域的d字符串
- 圓弧構造器:根據給定的角度坐標,返回圓弧片段的d字符串
→_→的代碼定義了兩個變量:group和clock,看看這兩個變量的定義,體會下構造器的必要性!
曲線構造器
很多數據集可以用二維坐標系中的曲線來進行可視化,每一個數據對應曲線上的一個點:
在SVG中,可以使用path元素表征任意的曲線。為了簡化d屬性的編寫,我們可以使用svg.line()方法創建一個曲線構造器對象:
- d3.svg.line()
曲線構造器(注意,這指的是line()返回的結果)是一個函數,它要求調用者傳入一個數組。 默認情況下,數組的每一項應當是一個包含x、y坐標的數組,第一個值代表x,第二個值代表y。比如:
- var line = d3.svg.line();
- var d = line([[10,20],[20,30],[50,70],[100,60]]);
提醒一下,盡管稱為line,但是這個方法實際和SVG的line元素毫無關系。
試着查看下→_→代碼中line(data)返回的內容,努力記住,line()方法返回的是一個函數!
使用x,y訪問器
很多情況下,我們的數據模型不符合曲線構造器的要求。比如:
- var data=[
- {year:1981,yield:129303},
- {year:1982,yield:901234},
- ......
- ];
這時可以使用構造器的x、y訪問器函數告訴構造如何訪問我們的數據:
- line.x([x_accessor])
- line.y([y_accessor])
構造器會將數據集中的每一個數據傳入訪問器函數,並使用其返回值作為 x坐標或y坐標:
- var line = d3.svg.line()
- .x(function(d){return d.year;})
- .y(function(d){return d.yield;});
- var d = line(data);
定義插值策略
我們為曲線構造器僅僅指定了一些關鍵點,中間點的計算是曲線構造器完成的,這個 過程就是插值。
曲線構造器默認的插值模式是線性插值,所以我們看到一些直線段將我們提供 的各個點連接起來。
使用intepolation()方法,可以告訴構造器使用不同的插值策略:
- line.interpolate([interpolate])
如果inerpolate參數是一個字符串,表示要求構造器使用一個預置的插值 策略,可以是:
- linear - 線性插值
- linear-closed - 線性插值,封閉起點和終點形成多邊形
- step - 步進插值,曲線只能沿x軸和y軸交替伸展
- step-before - 步進插值,曲線只能沿y軸和x軸交替伸展
- step-after - 同step
- basis - B樣條插值
- basis-open - B樣條插值,起點終點不相交
- basis-closed - B樣條插值,連接起點終點形成多邊形
- bundle - 基本等效於basis,除了有額外的tension參數用於拉直樣條
- cardinal - Cardina樣條插值
- cardinal-open - Cardina樣條插值,起點終點不相交
- cardinal-closed - Cardina樣條插值,連接起點終點形成多邊形
- monotone - 立方插值,保留y方向的單調性
interpolate參數也可以是一個函數,這個函數接受傳入的數據點集,返回 path的d字符串。我們先無視掉。
在→_→的代碼中,將插值模式改成上面列的值,看看效果有什么不同?
區域構造器
有些數據集適合用二維坐標系中的曲線區域來進行可視化,這時可認為區域由上下兩條線 包圍組成:
在SVG中,可以使用path元素表征任意的區域。為了簡化d屬性的編寫,我們可以使用svg.area()方法創建一個曲線構造器對象:
- d3.svg.area()
區域構造器是一個函數,它要求調用者傳入一個數組,數組的每一項 應當是一個包含x、y坐標的數組,第一個值代表x,第二個值代表y,這代表上面 那條線上的坐標點,比如:
- var area = d3.svg.area();
- var d = area([[10,20],[20,30],[50,70],[100,60]]);
第二條線和第一條線有相同的點數。默認情況下,第二條線上每個數據點的x和 第一條線對應點的x坐標一樣,y坐標則保持為0。
→_→的示例效果中,你看到第二條線(水平橫線)在上面,這是因為對於SVG坐標系, 原點在左上角。
數據訪問器
區域構造器和曲線構造器一樣,可以使用訪問器定制對用戶數據的讀取:
- area.x([x_accessor]);
- area.y([y_accessor]);
- area.x0([x_accessor]);
- area.y0([y_accessor]);
你注意到,由於區域由兩條線構成,所以多出了一組x0/y0訪問器。
我們通常使用y0訪問器定義比較的基准。
插值
和曲線構造器一樣,也可以使用interpolate()定義區域中曲線的插值策略:
- area.interpolate([interpolate])
在→_→的示例代碼中,改變下y0的值,看看有什么不同?
圓弧構造器
我們對餅圖不陌生,一個圓被分成多份,用不同的顏色表示不同的事物:
在SVG中,可以使用path元素表征圓、圓環或扇形。為了簡化d屬性的編寫,我們可以使用svg.arc()方法創建一個圓弧構造器:
- d3.svg.arc()
圓弧構造器要求數組中的每一項為一個JSON對象,有以下屬性:
- startAngle - 區塊的起始角度,以弧度為單位
- endAngle - 弧度的終止角度,以弧度為單位
- innerRadius - 內圓半徑
- outerRadius - 外圓半徑
→_→的代碼中,先創建了一個g元素作為后續元素的分組容器,並設置transform屬性將 這個分組移動到適合查看的位置。
數據訪問器
和其他構造器一樣,圓弧構造器也可以使用數據訪問器定制對用戶數據的讀取,這使其 可以適應不同的數據結構:
- area.startAngle([sa_accessor]);
- area.endAngle([ea_accessor]);
- area.innerRadius([ir_accessor]);
- area.outerRadius([or_accessor]);
→_→的示例將一組數據轉化為常見的餅圖,每個數據的大小決定了其在整個圓所占 弧度的大小。