比例尺是 D3 中很重要的一個(gè)概念,上一章里曾經(jīng)提到過直接用數(shù)值的大小來代表像素不是一種好方法,本章正是要解決此問題。
http://wiki.jikexueyuan.com/project/d3wiki/images/scale-1.png" alt="柱形圖" />
上一章制作了一個(gè)柱形圖,當(dāng)時(shí)有一個(gè)數(shù)組:
var dataset = [ 250 , 210 , 170 , 130 , 90 ];
繪圖時(shí),直接使用 250 給矩形的寬度賦值,即矩形的寬度就是 250 個(gè)像素。
此方式非常具有局限性,如果數(shù)值過大或過小,例如:
var dataset_1 = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
var dataset_2 = [ 2500, 2100, 1700, 1300, 900 ];
對(duì)以上兩個(gè)數(shù)組,絕不可能用 2.5 個(gè)像素來代表矩形的寬度,那樣根本看不見;也不可能用 2500 個(gè)像素來代表矩形的寬度,因?yàn)楫嫴紱]有那么長。
于是,我們需要一種計(jì)算關(guān)系,能夠:
將某一區(qū)域的值映射到另一區(qū)域,其大小關(guān)系不變。
這就是比例尺(Scale)。
比例尺,很像數(shù)學(xué)中的函數(shù)。例如,對(duì)于一個(gè)一元二次函數(shù),有 x 和 y 兩個(gè)未知數(shù),當(dāng) x 的值確定時(shí),y 的值也就確定了。
在數(shù)學(xué)中,x 的范圍被稱為定義域,y 的范圍被稱為值域。
D3 中的比例尺,也有定義域和值域,分別被稱為 domain 和 range。開發(fā)者需要指定 domain 和 range 的范圍,如此即可得到一個(gè)計(jì)算關(guān)系。
D3 提供了多種比例尺,下面介紹最常用的兩種。
線性比例尺,能將一個(gè)連續(xù)的區(qū)間,映射到另一區(qū)間。要解決柱形圖寬度的問題,就需要線性比例尺。
假設(shè)有以下數(shù)組:
var dataset = [1.2, 2.3, 0.9, 1.5, 3.3];
現(xiàn)有要求如下:
將 dataset 中最小的值,映射成 0;將最大的值,映射成 300。
代碼如下:
var min = d3.min(dataset);
var max = d3.max(dataset);
var linear = d3.scale.linear()
.domain([min, max])
.range([0, 300]);
linear(0.9); //返回 0
linear(2.3); //返回 175
linear(3.3); //返回 300
其中,d3.scale.linear() 返回一個(gè)線性比例尺。domain() 和 range() 分別設(shè)定比例尺的定義域和值域。在這里還用到了兩個(gè)函數(shù),它們經(jīng)常與比例尺一起出現(xiàn):
這兩個(gè)函數(shù)能夠求數(shù)組的最大值和最小值,是 D3 提供的。按照以上代碼,
比例尺的定義域 domain 為:[0.9, 3.3]
比例尺的值域 range 為:[0, 300]
因此,當(dāng)輸入 0.9 時(shí),返回 0;當(dāng)輸入 3.3 時(shí),返回 300。當(dāng)輸入 2.3 時(shí)呢?返回 175,這是按照線性函數(shù)的規(guī)則計(jì)算的。
有一點(diǎn)請(qǐng)大家記?。?/p>
d3.scale.linear() 的返回值,是可以當(dāng)做函數(shù)來使用的。因此,才有這樣的用法:linear(0.9)。
有時(shí)候,定義域和值域不一定是連續(xù)的。例如,有兩個(gè)數(shù)組:
var index = [0, 1, 2, 3, 4];
var color = ["red", "blue", "green", "yellow", "black"];
我們希望 0 對(duì)應(yīng)顏色 red,1 對(duì)應(yīng) blue,依次類推。
但是,這些值都是離散的,線性比例尺不適合,需要用到序數(shù)比例尺。
var ordinal = d3.scale.ordinal()
.domain(index)
.range(color);
ordinal(0); //返回 red
ordinal(2); //返回 green
ordinal(4); //返回 black
用法與線性比例尺是類似的。
在上一章的基礎(chǔ)上,修改一下數(shù)組,再定義一個(gè)線性比例尺。
var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
var linear = d3.scale.linear()
.domain([0, d3.max(dataset)])
.range([0, 250]);
其后,按照上一章的方法添加矩形,在給矩形設(shè)置寬度的時(shí)候,應(yīng)用比例尺。
var rectHeight = 25; //每個(gè)矩形所占的像素高度(包括空白)
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x",20)
.attr("y",function(d,i){
return i * rectHeight;
})
.attr("width",function(d){
return linear(d); //在這里用比例尺
})
.attr("height",rectHeight-2)
.attr("fill","steelblue");
如此一來,所有的數(shù)值,都按照同一個(gè)線性比例尺的關(guān)系來計(jì)算寬度,因此數(shù)值之間的大小關(guān)系不變。
下載地址:rm40.zip
展示地址:http://www.ourd3js.com/demo/rm/R-4.0/UseScaleInChart.html