【 D3.js 高階系列 — 6.0 】 值域和顏色
在【入門 - 第 10 章】作了一張中國地圖,其中各省份的顏色值都是隨意賦值的。如果要將一些值反映在地圖上,可以利用顏色的變化來表示值的變化。
1. 思路
例如,有值域的範圍為:
[10, 500]
現希望10用淺綠表示,500用深綠表示,10到500之間的值用淺綠和深綠之間的顏色表示。顯然,此處需要一個函式,傳入的引數是10到500之間的值,返回值是淺綠到深綠之間的顏色值。
【高階 - 第 5.1 章】介紹的顏色插值函式正好可以派上用場。
var palegreen = d3.rgb(66,251,75); //淺綠 var darkgreen = d3.rgb(2,100,7); //深綠 var color = d3.interpolate(a,b); //顏色插值函式
這段程式碼最後得到的color可作為函式使用,引數的範圍為[0, 1],當引數為0時,返回淺綠,當引數為1時,返回深綠。但是,現在的值域是[10, 500],範圍不是[0, 1]。因此,先定義一個線性比例尺,將[10, 500]按線性關係對映到[0, 1]。
var linear = d3.scale.linear()
.domain([10, 500])
.range([0, 1]);
如此一來,便可結合比例尺來使用顏色插值函式。
color( linear(10) ); //返回淺綠RGB(66,251,75) color( linear(250) ); //返回淺綠和深綠之間的值 color( linear(500) ); //返回深綠RGB(2,100,7)
2. 繪製完整的中國地圖
在【入門 - 第 10 章】有繪製中國地圖的方法。
本例中更改為讀取 TopoJSON 檔案,這種型別的檔案更小,能提高讀取速度。關於 TopoJSON 和 GeoJSON 的區別,請參見【入門 - 第 10.3 章】。
要使用 TopoJSON 的相關函式,需要引用:
<script src="http://d3js.org/topojson.v1.min.js" charset="utf-8"></script>
讀取之後,使用 topojson.feature 將其轉換為 GeoJSON 檔案,不錯,最終使用時還是 GeoJSON 的格式,但是在讀取時速度會快很多。
d3.json("china.topojson", function(error, toporoot) {
if (error)
return console.error(error);
//輸出china.topojson的物件
console.log(toporoot);
//將TopoJSON物件轉換成GeoJSON,儲存在georoot中
var georoot = topojson.feature(toporoot,toporoot.objects.china);
//輸出GeoJSON物件
console.log(georoot);
//包含中國各省路徑的分組元素
var china = svg.append("g");
//新增中國各種的路徑元素
var provinces = china.selectAll("path")
.data( georoot.features )
.enter()
.append("path")
.attr("class","province")
.style("fill", "#ccc")
.attr("d", path );
});
此外,南海諸島的地圖是不包含在地圖檔案裡的。但是,中國的南海諸島,一般只是顯示在右下角,用一個方框框起來而已,不一定要做成GeoJSON格式。直接製作一個SVG格式的檔案即可。
新增到程式碼裡,形如:
d3.xml("southchinasea.svg", function(error, xmlDocument) {
svg.html(function(d){
return d3.select(this).html() + xmlDocument.getElementsByTagName("g")[0].outerHTML;
});
var gSouthSea = d3.select("#southsea");
gSouthSea.attr("transform","translate(540,410)scale(0.5)")
.attr("class","southsea");
});
3. 為各省市新增顏色
假設現在有一組反應各省旅遊業發展的資料,儲存到檔案 tourism.json 裡:
{
"name": "中國",
"provinces":
[
{"name": "北京", "value": 14149 },
{"name": "天津", "value": 2226.41},
{"name": "河北", "value": 1544.94},
{"name": "山西", "value": 3720.24},
// 省略
]
}
讀取此檔案後,按照第一節的思路,建立一個顏色插值函式:
//求最大值和最小值
var maxvalue = d3.max(valuedata.provinces, function(d){ return d.value; });
var minvalue = 0;
//定義一個線性比例尺,將最小值和最大值之間的值對映到[0, 1]
var linear = d3.scale.linear()
.domain([minvalue, maxvalue])
.range([0, 1]);
//定義最小值和最大值對應的顏色
var a = d3.rgb(0,255,255); //淺藍色
var b = d3.rgb(0,0,255); //藍色
//顏色插值函式
var computeColor = d3.interpolate(a,b);
computeColor 是我們需要的函式。接下來,只需要修改各省份的填充色即可,為了方便,將讀取到的資料都放到一個values數組裡,令其索引號為各省的名稱。 //將讀取到的資料存到陣列values,令其索引號為各省的名稱
var values = [];
for(var i=0; i<valuedata.provinces.length; i++){
var name = valuedata.provinces[i].name;
var value = valuedata.provinces[i].value;
values[name] = value;
}
//設定各省份的填充色
provinces.style("fill", function(d,i){
var t = linear( values[d.properties.name] );
var color = computeColor(t);
return color.toString();
});
這樣,雖然把地圖繪製了,填充色也按照值域對應了,但是還需要一個標誌,來告訴使用者什麼顏色對應什麼值。
4. 新增顏色標誌
【高階 - 第 5.1 章】有提到如何將漸變的顏色填充到一個矩形上,在這裡就用此法制作一個顏色標誌。
//定義一個線性漸變
var defs = svg.append("defs");
var linearGradient = defs.append("linearGradient")
.attr("id","linearColor")
.attr("x1","0%")
.attr("y1","0%")
.attr("x2","100%")
.attr("y2","0%");
var stop1 = linearGradient.append("stop")
.attr("offset","0%")
.style("stop-color",a.toString());
var stop2 = linearGradient.append("stop")
.attr("offset","100%")
.style("stop-color",b.toString());
//新增一個矩形,並應用線性漸變
var colorRect = svg.append("rect")
.attr("x", 20)
.attr("y", 490)
.attr("width", 140)
.attr("height", 30)
.style("fill","url(#" + linearGradient.attr("id") + ")");
//新增文字
var minValueText = svg.append("text")
.attr("class","valueText")
.attr("x", 20)
.attr("y", 490)
.attr("dy", "-0.3em")
.text(function(){
return minvalue;
});
var maxValueText = svg.append("text")
.attr("class","valueText")
.attr("x", 160)
.attr("y", 490)
.attr("dy", "-0.3em")
.text(function(){
return maxvalue;
});
5. 結果
結果如下如所示,
完整程式碼開啟以下連結,右鍵選擇檢視原始碼:
謝謝閱讀。
文件資訊
- 發表日期:2015 年 5 月 20 日
- 備註:本文發表於 OUR D3.JS ,轉載請註明出處,謝謝