1. 程式人生 > >【 D3.js 高階系列 — 6.0 】 值域和顏色

【 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. 結果

結果如下如所示,

601

完整程式碼開啟以下連結,右鍵選擇檢視原始碼:

謝謝閱讀。

文件資訊

  • 發表日期:2015 年 5 月 20 日
  • 備註:本文發表於 OUR D3.JS ,轉載請註明出處,謝謝