d3.js绘制【临近坐标图/区域图】

实现如下效果:

临近坐标图/区域图
一、json数据:
 

{
	"data": [[100.00,92.24,84.47,76.71,68.95,61.18,53.42,46.81,40.10,29.00,13.33]],
	"categories": [0,10,20,30,40,50,60, 70, 80, 90, 100],
	"area_data":[
		{"value":[100.000,88.760,77.520,66.290,55.050,43.810,34.440,28.430,21.330,10.000,3.333], "other_value":[100.00,95.08,90.17,85.25,80.33,75.42,70.50,65.71,59.24,47.52,30.00], "color": "#388E3C", "opacity": 0.7}
	],
	"marker":{
		"cross":[
			{"value":[  81.36 ,40] ,"h_step_start":10.17, "h_step_end":10.17, "v_step_start":16.67, "v_step_end":16.67,"desc":"12926.5 ( 81.36 ,40 )"}
		]
	},
	
	"params":{
		"title":"临近坐标图标题测试",
		"x_label":"x轴测试",
		"y_label":"y轴测试",
		"drag_label":"AUC:56.7%",
		
		"colors":["#000"],
		"show_grid":true,
		"show_cross":true,
		"show_area":true
	},
	"size":{
		"width":800,
		"height":600
	}
}
        

参数说明:

  • *data:线条,二维数组
  • *categories:x轴刻度,需要数值型
  • area_data:智信区间的内容, cross[value:中心点, h_step_start:水平右面步长, h_step_end:水平左面步长, v_step_start:垂直下面步长, v_step_end:垂直上面步长,desc:鼠标放十字架上的提示框]
  • marker:包含十字架的内容
  • title:标题
  • x_label:x轴标签
  • y_label:y轴标签
  • drag_label:可以拖拽的文字
  • colors:线条颜色
  • show_grid:false| true, 是否显示网格线
  • show_cross:false| true, 是否显示十字架
  • show_area:false| true, 是否显示智信区间


二、用到的js插件
#jquery插件

<script src="jquery-1.8.3.min.js"></script>
#d3 v3版本插件

<script src="d3-3.min.js"></script>
#图的实现文件
<script src="area_line.js"></script>

三、图的调用
var content = $.parseJSON($('textarea').val()); //从textarea里面取出图的json数据并转化为object
graph.areaLine("container", content);   //把生成图放在#container里面

四、以下为图的代码实现(D3.js实现)

var graph = {
	/**
	 * 临近坐标图(区域+line+mark)
	 *
	 * @return    void
	 **/

	areaLine(container, content)
	{
		d3.select('#'+container).select('svg').remove();
		d3.select('body').select('.arealine_tooltip').remove();
		var colors = ["#388E3C", "#F44336", "#0288D1", "#FF9800", "#727272", "#E91E63", "#673AB7", "#8BC34A", "#2196F3", "#D32F2F", "#FFC107", "#BDBDBD", "#F8BBD0", "#3F51B5", "#CDDC39", "#009688", "#C2185B", "#FFEB3B", "#212121", "#FFCCBC", "#BBDEFB", "#0099CC", "#FFcc99"];

		var width  = content.size.width;
		var height = content.size.height;

		var margin = {
			top    : 50,
			right  : 50,
			bottom : 50,
			left   : 50,
		};

		var grid_width  = width - margin.left - margin.right;
		var grid_height = height - margin.top - margin.bottom;

		// 计算最大值、最小值
		var max_ys = new Array();
		var min_ys = new Array();
	
		for (var i in content.data) {
			max_ys.push(d3.max(content.data[i]));
			min_ys.push(d3.min(content.data[i]));
		}

		if (typeof(content.area_data) != 'undefined') {
			for (var i in content.area_data) {
				min_ys.push(d3.min(content.area_data[i].value));
				min_ys.push(d3.min(content.area_data[i].other_value));
				max_ys.push(d3.max(content.area_data[i].other_value));
				max_ys.push(d3.max(content.area_data[i].other_value));
			}
		}

		var max_y = d3.max(max_ys);
		var min_y = d3.min(min_ys);

		console.log(min_ys, max_ys);

		if (min_y >= 0) {
			min_y -= min_y/2;
		} else {
			min_y += min_y/2;
		}

		if (max_y >= 0) {
			//max_y += max_y/5;
		} else {
			max_y += max_y/2;
		}

		// 计算x的轴刻度值
		var categories = content.categories;

		/*for (var i in content.data[0]){
			categories.push(parseInt(i));
		}*/

		// 定义x,y比例尺
		var x_scale = d3.scale.linear()
			.domain([d3.max(categories),d3.min(categories)])
			.range([0, grid_width]);

		var y_scale = d3.scale.linear()
			.domain([max_y,min_y])
			.range([0, grid_height]);


		// 定义x,y坐标轴
		var x_axis = d3.svg.axis()
			.scale(x_scale)
			.orient('bottom')
			.outerTickSize(0);

		var y_axis = d3.svg.axis()
			.scale(y_scale)
			.orient('left')
			.outerTickSize(0);

		var line = d3.svg.line()
			.x(function(d,i) {
				return x_scale(categories[i]);
			})
			.y(function(d) {
				return y_scale(d);
			});
		

		//开始绘图

		var svg = d3.select('#'+container)
			.append('svg')
			.attr('version', '1.1')
			.attr('style', 'font-family:arial')
			.attr('xmlns', 'http://www.w3.org/2000/svg')
			.attr('width', width)
			.attr('height', height);

		var main = svg.append('g')
			.attr('class', 'main')
			.attr('transform','translate('+margin.left+', '+margin.top+')');

		var xaxis_obj = main.append('g')
			.attr('class', 'axis xaxis')
			.call(x_axis)
			.attr('transform', 'translate(0, '+grid_height+')');

		var yaxis_obj = main.append('g')
			.attr('class', 'axis yaxis')
			.call(y_axis);

		var xtick_values = x_scale.ticks();
		var ytick_values = y_scale.ticks();

		d3.select('.xaxis').selectAll('.tick').each(function() {
			xtick_values.push(d3.select);
		});

		// 是否显示网格线
		if (typeof(content.params.show_grid) != 'undefined' && content.params.show_grid == true) {
			var helplines = main.append('g')
				.attr('class','helplines');

			var y_helpers = helplines.append('g').attr('class', 'y_helps').selectAll('.helpline')
				.data(ytick_values)
				.enter()
				.append('line')
				.attr('class', 'helpline')
				.attr('x1', function() {
					return x_scale(d3.min(xtick_values));
				})
				.attr('y1', function(d) {
					return y_scale(d);
				})
				.attr('x2', function() {
					return x_scale(d3.max(categories));
				})
				.attr('y2', function(d) {
					console.log(graph.getAngle(x_scale(d3.min(xtick_values)),y_scale(d),x_scale(d3.max(categories)),y_scale(d)));
					return y_scale(d);

				});

				

			d3.selectAll('.helplines').selectAll('.helpline').attr('stroke', '#ccc').attr('stroke-dasharray', '5,5');
		}

		//绘制背景
		var bg_obj = main.append('g').attr('class','bg');

			bg_obj.append('rect')
				.attr('width',grid_width)
				.attr('height', grid_height)
				.attr('stroke', '#000')
				.attr('fill', 'none');

			bg_obj.append('line')
				.attr('x1', function() {
					return x_scale(d3.max(categories));
				})
				.attr('y1', function() {
					return y_scale(min_y);
				})
				.attr('x2', function() {
					return x_scale(0);
				})
				.attr('y2', function() {
					return y_scale(max_y);
				})
				.attr('stroke', '#ccc');

		

		if (typeof(content.params.show_area) != 'undefined' && content.params.show_area === true && typeof(content.area_data) != 'undefined'){
		
			// 画区域
			var areas_obj = main.append('g')
				.attr('class', 'area_group')
				.selectAll('.areas')
				.data(content.area_data)
				.enter()
				.append('path')
				.attr('class', 'areas')
				.attr('d', function(d) {
					return graph.drawArea(d,x_scale, y_scale,categories);
				})
				.attr('stroke', function(d) {
					return d.color;
				})
				.attr('fill', function(d) {
					return d.color;
				})
				.attr('fill-opacity', function(d) {
					return d.opacity;
				});
		}

		var line_obj = main.append('g')
			.attr('class', 'line_group')
			.selectAll('.lines')
			.data(content.data)
			.enter()
			.append('path')
			.attr('class', 'lines')
			.attr('d', function(d) {
				return line(d);
			})
			.attr('stroke', function(d, i) {
				return typeof(content.params.colors) != 'undefined' ? content.params.colors[i%content.params.colors.length] : colors[i%colors.length];
			})
			.attr('stroke-width',2)
			.attr('fill', 'none');

		// 创建提示框
		var tooltip = this.createTip();

		var circle_group = main.append('g').attr('class', 'circle_group');
		
		var circle_obj = circle_group.selectAll('.circles')
			.data(content.data)
			.enter()
			.append('g')
			.attr('class', 'circles')
			.each(function(d,i) {
				var self = d3.select(this);
				self.selectAll('.circle_'+i)
					.data(d)
					.enter()
					.append('circle')
					.attr('class', 'circle_'+i)
					.attr('cx', function(dd,ii) {
						return x_scale(categories[ii]);
					})
					.attr('cy', function(dd, ii) {
						return y_scale(dd);
					})
					.attr('r', 5)
					.attr('fill', '#000')
					.attr('fill-opacity', 0.0)
					.on('mouseover', function(d,i) {
						var circle_obj = d3.select(this);
						var page_x     = d3.event.pageX;
						var page_y     = d3.event.pageY+20;
						circle_obj.attr('fill-opacity', 0.7);
						tooltip.html('<b>position:</b>'+categories[i]+"</br> <b>value:</b>"+d)  
							.style("left",page_x+"px")  
							.style("top",page_y+"px")  
							.style("opacity",0.9)
							.style('padding', '5px');
					})
					.on('mouseout', function(){
						var circle_obj = d3.select(this);
						circle_obj.attr('fill-opacity', 0.0);
						tooltip.style('opacity', 0.0);
					});
			});


		// 画十字架
		if (typeof(content.marker) != 'undefined' && typeof(content.marker.cross) != '' && typeof(content.params.show_cross) != 'undefined' && content.params.show_cross === true) {
			var cross_group = main.append('g').attr('class', 'marker').append('g').attr('class', 'cross_group');

			cross_group.selectAll('.cross')
				.data(content.marker.cross)
				.enter()
				.append('g')
				.attr('class', 'cross')
				.attr('transform', function(d, i) {
					return 'rotate(0, '+x_scale(d.value[0])+','+y_scale(d.value[1])+')';
				})
				.each(function(d) {
					var self = d3.select(this);
					self.append('line')
						.attr('class', 'cross_v')
						.attr('x1', function(d, i) {
							return x_scale(d.value[0]);
						})
						.attr('y1', function(d){
							return y_scale(d.value[1]+d.v_step_start);
						})
						.attr('x2', function(d) {
							return x_scale(d.value[0]);
						})
						.attr('y2', function(d) {
							return y_scale(d.value[1] - d.v_step_end);
						})
						.attr('stroke', '#000');
					self.append('line')
						.attr('class', 'cross_v_start')
						.attr('x1', function(d, i) {
							return x_scale(d.value[0])-4;
						})
						.attr('y1', function(d){
							return y_scale(d.value[1]+d.v_step_start);
						})
						.attr('x2', function(d) {
							return x_scale(d.value[0])+4;
						})
						.attr('y2', function(d) {
							return y_scale(d.value[1]+d.v_step_start);
						})
						.attr('stroke', '#000');
					self.append('line')
						.attr('class', 'cross_v_end')
						.attr('x1', function(d, i) {
							return x_scale(d.value[0])-4;
						})
						.attr('y1', function(d){
							return y_scale(d.value[1]-d.v_step_end);
						})
						.attr('x2', function(d) {
							return x_scale(d.value[0])+4;
						})
						.attr('y2', function(d) {
							return y_scale(d.value[1]-d.v_step_end);
						})
						.attr('stroke', '#000');

					self.append('line')
						.attr('class', 'cross_h')
						.attr('x1', function(d, i) {
							return x_scale(d.value[0]-d.h_step_start);
						})
						.attr('y1', function(d){
							return y_scale(d.value[1]);
						})
						.attr('x2', function(d) {
							return x_scale(d.value[0]+d.h_step_end);
						})
						.attr('y2', function(d) {
							return y_scale(d.value[1]);
						})
						.attr('stroke', '#000');
					self.append('line')
						.attr('class', 'cross_h_start')
						.attr('x1', function(d, i) {
							return x_scale(d.value[0]-d.h_step_start);
						})
						.attr('y1', function(d){
							return y_scale(d.value[1])-4;
						})
						.attr('x2', function(d) {
							return x_scale(d.value[0]-d.h_step_start);
						})
						.attr('y2', function(d) {
							return y_scale(d.value[1])+4;
						})
						.attr('stroke', '#000');
					self.append('line')
						.attr('class', 'cross_h_end')
						.attr('x1', function(d, i) {
							return x_scale(d.value[0]+d.h_step_end);
						})
						.attr('y1', function(d){
							return y_scale(d.value[1])-4;
						})
						.attr('x2', function(d) {
							return x_scale(d.value[0]+d.h_step_end);
						})
						.attr('y2', function(d) {
							return y_scale(d.value[1])+4;
						})
						.attr('stroke', '#000');
					
				})
				.on('mouseover', function(d) {
					var self = d3.select(this);
					var page_x     = d3.event.pageX;
						var page_y     = d3.event.pageY+20;
						circle_obj.attr('fill-opacity', 0.7);
						tooltip.html('<b>Description:</b>'+d.desc)  
							.style("left",page_x+"px")  
							.style("top",page_y+"px")  
							.style("opacity",0.9)
							.style('padding', '5px');
				})
				.on('mouseout', function() {
					tooltip.style('opacity', 0.0);
				});

                //去掉定时旋转,
			//setInterval(function() {
				d3.selectAll('.cross').each(function() {
					var self = d3.select(this);
					var rotate = self.attr('transform');
					rotate = rotate.replace(/rotate\(/, '');
					rotate = rotate.replace(/\)/, '');
					var rotates = rotate.split(',');
					var angle = parseInt(rotates[0]) + 10;
					if (angle == 360) {
						angle = 0;
					}
                //去掉倾斜角度
					//self.attr('transform', 'rotate('+angle+', '+rotates[1]+', '+rotates[2]+')');
				});
			//}, 10000);
		}

		
		// 赋x,y刻度样式

		d3.selectAll('.axis').selectAll('line').attr('stroke', '#000').attr('style', 'font-size:11px');
		d3.selectAll('.axis').selectAll('path').attr('stroke', '#000').attr('style', 'font-size:11px').attr('fill', 'none');


		var move_label = typeof(content.params.drag_label) != 'undefined' ? content.params.drag_label: '';
		var move_x = width/2;
		var move_y = grid_height + margin.top - 20;

		if (move_label != '') {
			var drag = this.createMove();
			console.log(drag);
			svg.append('text').text(move_label).attr('x', move_x).attr('y',move_y).attr('style', 'font-weight:bold;font-size:12px;cursor:pointer').call(drag);
		}
		var title = typeof(content.params.title) != 'undefined' ? content.params.title : '';
		var title_per_width = 1;
		if (title != '') {
			var title_x = (width - title.length * title_per_width) /2;
			svg.append('text').text(title).attr('text-anchor', 'middle').attr('x', title_x).attr('y', margin.top/2);
		}

		var x_label = typeof(content.params.x_label) != 'undefined' ? content.params.x_label : '';

		if (x_label != '') {
			var x_label_x = width/2 - x_label.length;
			svg.append('text').text(x_label).attr('text-anchor', 'middle').attr('x', x_label_x).attr('y', height - margin.bottom/4).attr('style', 'font-size:11px');
		}

		var y_label = typeof(content.params.y_label) != 'undefined' ? content.params.y_label : '';

		if (y_label != '') {
			var y_label_x = height/2 - x_label.length;
			svg.append('text').text(y_label).attr('text-anchor', 'middle').attr('x', -y_label_x).attr('y', margin.left/4).attr('transform', 'rotate(-90)').attr('style', 'font-size:11px');
		}

		
	},
	/**
	 *
	 * 画区域
	 **/
	drawArea:function(data, x_scale, y_scale, categories)
	{
		var y0_data = data['value'];
		var y1_data = data['other_value'];

		var area = d3.svg.area()
			.x(function(d,i) {
				return x_scale(categories[i])
			})
			.y0(function(d, i) {
				return y_scale(d);
			})
			.y1(function(d, i) {
				return y_scale(y1_data[i]);
			});
		return area(y0_data);
	},
	/**
	 *
	 * 创建移动事件
	 **/
	createMove:function()
	{
		// 定义拖拽事件
		var drag = d3.behavior.drag()  
            .on("drag",dragmove)

		function dragmove(d){
			d3.select(this)  
				.attr("x", d3.event.x)  
				.attr("y", d3.event.y);
		}

		return drag;
	},
	/**
	 *
	 * 创建提示框
	 **/
	createTip:function()
	{
		var tooltip = d3.select("body").append("div")  
			.attr("class","arealine_tooltip")
			.attr("opacity",0.0);

		return tooltip;
	},
	getAngle:function(x1,y1,x2,y2)
	{
		var x = Math.abs(x1 - x2);
		var y = Math.abs(y1 - y2);

		// 斜边长
		var z = Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
		
		// 余弦

		var cos = y/z;

		//弧度

		var radina = Math.acos(cos);

		//角度

		var angle = 180/ (Math.PI/ radina);

		return angle;

	}
};

以上就是临近坐标图的全部实现,如果有不清楚的地方可以留言,欢迎交流

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值