D3,当上下文发生变化时,第二焦点不会移动

D3, Second focus does not move when context changes

本文关键字:焦点 移动 变化 上下文 D3      更新时间:2023-09-26

我以D3为例:http://bl.ocks.org/mbostock/1667367。在这个例子中,有一个焦点和一个上下文。当上下文发生变化时,焦点将显示上下文中的数据。我的目标是添加另一个焦点(焦点2)。为了更容易,focus2(此时)的功能与focus(原始焦点)相同。预期结果是:当画笔移动时,两个焦点(代码中的焦点和焦点2)将发生变化。这是代码:

<!DOCTYPE html>
<meta charset="utf-8">
<!--head>	
	<link rel="stylesheet" type= "text/css" href="angle_view.css">
</head-->
<style>
svg {
  font: 10px sans-serif;
}
.area {
  fill: steelblue;
  clip-path: url(#clip);
}
.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}
.brush .extent {
  stroke: #fff;
  fill-opacity: .125;
  shape-rendering: crispEdges;
}
</style>
<body>
	<!--script type = "text/javascript" src = "../d3/d3.min.js"> </script-->
   <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.7/d3.min.js"></script>
	
	<p>Select a dataset from the list.</p>
	<select id = "datasetSelect" onchange = "datasetSelectFunction()">
	  <option value="load_small_data_set">small dataset</option>
	  <option value="load_whole_data_set">whole dataset</option>	  
	</select>
	
	<!--script type = "text/javascript" src = "angle_view.js"> </script -->
	
	<script>	
	
	// main script
	var g_fn = null;
	var g_pan = null;
	var g_feature = null;
	var g_fn_pan = null;
	
//	init_angle_feature_view();
	var margin  = {top: 10,  right: 30,  bottom: 370, left: 40};
	var margin2 = {top: 250, right: 30, bottom: 130, left: 40};
	var margin3 = {top: 500, right: 30, bottom: 20, left: 40};
	var width   = 960 - margin.left - margin.right;
	var height  = 600 - margin.top - margin.bottom;
	var height2 = 600 - margin2.top - margin2.bottom;
	var height3 = 600 - margin3.top - margin3.bottom;
	// set scales
	var x  = d3.scale.linear().range([0, width]);
	var x2 = d3.scale.linear().range([0, width]);
	var x3 = d3.scale.linear().range([0, width]);
	var y  = d3.scale.linear().range([height, 0]);
	var y2 = d3.scale.linear().range([height2, 0]);
	var y3 = d3.scale.linear().range([height3, 0]);
	var xAxis  = d3.svg.axis().scale(x).orient("bottom");
	var xAxis2 = d3.svg.axis().scale(x2).orient("bottom");
	var xAxis3 = d3.svg.axis().scale(x3).orient("bottom");
	var yAxis = d3.svg.axis().scale(y).orient("left");
	var brush = d3.svg.brush()
    	.x(x3)     // x scale
    	.on("brush", brushed);
	var area = d3.svg.area()  // area on the top, detailed view of pan angle
    	.interpolate("monotone")
    	.x(function(d) { return x(d.frame_number); })
    	.y0(height)
    	.y1(function(d) { return y(d.pan); });
	
	var area2 = d3.svg.area()  // area in the middle, detailed view of feature
		.interpolate("monotone")
		.x(function(d){return x2(d.frame_number);})
		.y0(height2)
		.y1(function(d){return y2(d.pan); });
	var area3 = d3.svg.area() // area on the bottom, global view of pan angle
    	.interpolate("monotone")
    	.x(function(d) { return x3(d.frame_number); })
    	.y0(height3)
    	.y1(function(d) { return y3(d.pan); });
	var svg = d3.select("body").append("svg")
    	.attr("width", width + margin.left + margin.right)
    	.attr("height", height + margin.top + margin.bottom);
	svg.append("defs").append("clipPath")  // what is defs?, defs is not directly rendered. what is clipPath? draw only inside width x height
    	.attr("id", "clip")  // what is clip and id do
    	.append("rect")
    	.attr("width", width)
    	.attr("height", height);
	var focus = svg.append("g")
    	.attr("class", "focus")   // where does focus come from?
    	.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
	
	var focus2 = svg.append("g")
		.attr("class", "focus")
		.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
	var context = svg.append("g")
    	.attr("class", "context")
    	.attr("transform", "translate(" + margin3.left + "," + margin3.top + ")");	
	
	function datasetSelectFunction(){
		var x = document.getElementById("datasetSelect").value;	
		//console.log(x);
		
		if (x == "load_small_data_set")
		{
			// load frame number, pan data			
			d3.csv("https://dl.dropboxusercontent.com/u/54750216/javascript/sampled_fn_pan_small.csv", function(error, data) {
				if (error) throw error;
				// sparse data			 
			 	data.forEach(function(d){
					d.frame_number  = parseInt(d.frame_number);
					d.pan = parseFloat(d.pan);			 		
			 	});
				g_fn_pan = data;
			  
  			d3.csv("https://dl.dropboxusercontent.com/u/54750216/javascript/sampled_fn_dim_feature_small.csv", function(error, feature) {
  			  if (error) throw error;
  			  // Coerce the CSV data to the appropriate types.    
  			  feature.forEach(function(d) {
  			    d.fn      = parseInt(d.frame_number);
  			    d.dim     = parseInt(d.dim);
  			    d.feature =  parseFloat(d.feature);
  			  });  
  			  g_feature = feature;
			  
			  angle_feature_view(g_fn_pan, g_feature);			  
  		 	});		  
			  
		  	});
			console.log("load_small_data_set");				
			// load frame number, feature data		    			
		    		
		}
		else if (x == "load_whole_data_set")
		{
			// load frame number, pan data			
			d3.csv("sampled_data/sampled_fn_pan.csv", function(error, data) {
				if (error) throw error;
				// sparse data			 
			 	data.forEach(function(d){
					d.frame_number  = parseInt(d.frame_number);
					d.pan = parseFloat(d.pan);			 		
			 	});
				g_fn_pan = data;
			  
  			d3.csv("sampled_data/sampled_fn_dim_feature.csv", function(error, feature) {
  			  if (error) throw error;
  			  // Coerce the CSV data to the appropriate types.    
  			  feature.forEach(function(d) {
  			    d.fn      = parseInt(d.frame_number);
  			    d.dim     = parseInt(d.dim);
  			    d.feature =  parseFloat(d.feature);
  			  });  
  			  g_feature = feature;
			  
			//  angle_feature_view(g_fn_pan, g_feature);			  
  		 	});		  
			  
		  	});
			console.log("load_whole_data_set");
		}		
	}
	
	// visualize frame number, pan angle and feature 
	function angle_feature_view(fn_pan, feature)
	{
		var fn_min  = d3.min(fn_pan, function(d){return d.frame_number});
	    var fn_max  = d3.max(fn_pan, function(d){return d.frame_number});
		var pan_min = d3.min(fn_pan, function(d){return d.pan});
		var pan_max = d3.max(fn_pan, function(d){return d.pan});
  
	  	x.domain([fn_min, fn_max]);  
	  	y.domain([pan_min, pan_max]);	    
  	  	
		x2.domain(x.domain());
		y2.domain(y.domain());
	  	// bottom
	  	x3.domain(x.domain());
	  	y3.domain(y.domain());  
		// draw fn pan detail view
		
	  	focus.append("path")
	      	 .datum(fn_pan)
	      	 .attr("class", "area")
	      	 .attr("d", area);
	  	focus.append("g")
	      .attr("class", "x axis")
	      .attr("transform", "translate(0," + height + ")")
	      .call(xAxis);
	  	focus.append("g")
	      .attr("class", "y axis")
	      .call(yAxis);		
		
		// add focus2 in this place
  		focus2.append("path")
      	  .datum(fn_pan)
      	  .attr("class", "area")
      	  .attr("d", area2);
  	    focus2.append("g")
         .attr("class", "x axis")
         .attr("transform", "translate(0," + height2 + ")")
         .call(xAxis2);
  		focus2.append("g")
      		.attr("class", "y axis")
      		.call(yAxis);  
		// brush?
	  	context.append("path")
	      	.datum(fn_pan)
	      	.attr("class", "area")
	      	.attr("d", area3);
	  	context.append("g")
	      .attr("class", "x axis")
	      .attr("transform", "translate(0," + height3 + ")")
	      .call(xAxis3);
	  	context.append("g")
	      .attr("class", "x brush")
	      .call(brush)
	      .selectAll("rect")
	      .attr("y", -6)
	      .attr("height", height3 + 7); 		
	}
	
	function brushed() {
	  x.domain(brush.empty() ? x3.domain() : brush.extent());
	  focus.select(".area").attr("d", area);
	  focus.select(".x.axis").call(xAxis);
	  focus2.select(".area").attr("d", area2);  // I add focus2 in this place
	  focus2.select(".x.axis").call(xAxis2);
	  console.log("call brushed");
	}	
	
	
	</script>
	
	
</body>	

请注意focus、focus2和上下文相关区域。问题是,当上下文发生变化时,focus2视图不会发生变化。它总是显示整个数据集。

您几乎已经完成了,只忘记了更新第二级的域。

x2.domain(brush.empty() ? x3.domain() : brush.extent());添加到brushed()函数中可以解决此问题。