• 【 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

    谢谢阅读。

    文档信息

  • 相关阅读:
    POJ 2388(排序)
    优先队列(堆实现)
    POJ 3322(广搜)
    POJ 1190(深搜)
    POJ 1456(贪心)
    poj 2524 (并查集)
    poj 1611(并查集)
    poj 1521
    poj 1220(短除法)
    css 如何实现图片等比例缩放
  • 原文地址:https://www.cnblogs.com/new0801/p/6176776.html
Copyright © 2020-2023  润新知