【 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格式的文件即可。

我製作了一個:southchinasea.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

完整代碼打開以下鏈接,右鍵選擇查看源代碼:

http://www.ourd3js.com/demo/G-6.0/range.html

謝謝閱讀。

文檔信息

發佈了122 篇原創文章 · 獲贊 380 · 訪問量 109萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章