# d3教程:选择器和事件

npm install d3-selection
d3.event - 访问用于交互的当前用户事件(v6移除)
d3.mouse - 获取相对于指定容器的鼠标位置。(v6移除)
d3.select - 从当前文档中选择一个元素。
d3.selectAll - 从当前文档中选择多个元素。
d3.selection - 增强选择器原型,或测试实例类型。
d3.touch - 获取相对于指定容器的单点触摸位置。(v6移除)
d3.touches - 获取相对于指定容器的多点触摸位置。(v6移除)
selection.append - 创建并追加一个新元素。
selection.attr - 取得或设置属性的值。
selection.call - 为当前选择调用一个函数。
selection.classed - 添加或移除CSS类。
selection.data - 在计算相关的连接时,取得或设置一组元素的数据。
selection.datum - 取得或设置单个元素的数据,不必计算连接。
selection.each - 为每个选中的元素调用一个函数。
selection.empty - 如果选择是空则返回true。
selection.enter - 为缺失的元素返回占位符。
selection.exit - 返回不再需要的元素。
selection.filter - 基于数据过滤选择。
selection.html - 取得或设置innerHTML内容。
selection.insert - 在已存在元素之前创建并插入一个元素。
selection.interrupt - 如果有过渡的话,立即中断当前的过渡。
selection.node - 返回选择中的第一个节点。
selection.on - 为交互添加或移除事件监听器。
selection.order - 重排列文档中的元素,以匹配选择。
selection.property - 取得或设置行内属性。
selection.remove - 从当前文档中移除当前元素。
selection.select - 为每个选中元素的在选择一个后代元素。
selection.selectAll - 为每个选中元素的在选择多个后代元素。
selection.size - 返回选择中的元素数。
selection.sort - 基于数据排列文档中的元素。
selection.style - 取得或设置样式属性。
selection.text - 取得或设置文本内容。
selection.transition - 在选中元素上开启过渡。

# D3选择集-类似jquery+css3

# 基本操作

api 作用 例子
select() 仅选择一个DOM元素.如果给定的CSS选择器有多个元素,则只选择第一个元素 d3.select(".myclass").text()
selectAll() 通过匹配给定的CSS选择器来选择所有DOM元素 类似上面
append() 将新元素作为当前选择中元素的最后一个子元素追加 d3.select("div.myclass").append("span")
text() 用于设置所选/附加元素的内容 d3.select("div.myclass").append("span").text("from D3.js")
html() 用于设置所选/附加元素的html内容 d3.select(".myclass").html("Hello World! <span>from D3.js</span>");
attr() 用于添加或更新所选元素的属性 d3.select(".myclass").attr("style", "color: red");
style() 用于设置所选元素的样式属性 d3.select(".myclass").style("color", "red")
classed() 用于设置HTML元素的"class"属性 -

classed

classed()方法专门用于设置HTML元素的"class"属性。 因为,单个HTML元素可以有多个类; 在为HTML元素分配类时,我们需要小心。 此方法知道如何处理元素上的一个或多个类,并且它将具有高性能。

添加类:要添加类,必须将分类方法的第二个参数设置为true。 它定义如下:

d3.select(".myclass").classed("myanotherclass", true);

删除类:要删除类,必须将分类方法的第二个参数设置为false。 它定义如下:

d3.select(".myclass").classed("myanotherclass", false);

检查类:要检查是否存在类,只需省略第二个参数并传递要查询的类名。 如果存在则返回true,如果不存在,则返回false。

d3.select(".myclass").classed("myanotherclass");

如果选择中的任何元素具有类,则返回true。 使用d3.select进行单个元素选择。

切换类:将类翻转到相反的状态 - 如果它已经存在则将其删除,如果它尚不存在则添加它 - 您可以执行以下操作之一。

对于单个元素,代码可能如下所示:

var element = d3.select(".myclass")
element.classed("myanotherclass", !oneBar.classed("myanotherclass"));

# selectAll 从当前文档中选择多个元素

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title></title>
		<style>
			p{border:1px solid red}
		</style>
	</head>
	<body>
			<p>111</p>
			<p>222</p>
	</body>
</html>
<script src="d3.min.js"></script>
<script type="text/javascript">
	// var p =document.getElementsByTagName("p")
	// p[0].style.color="red"
	// p[1].style.setProperty("width","50px")
	
	var p1 =document.createElement("p")
	p1.innerHTML=3333
	document.body.appendChild(p1)
	
	var $=d3
	$.selectAll("p").style("font-size","60px")
	
	var p1 =document.createElement("p")
	p1.innerHTML=4444
	document.body.appendChild(p1)
	$.selectAll("p").style("border","1px solid blue")
	
</script>

# select - 选中与指定选择器字符串匹配的第一个元素

d3.select("td").classed("selected",true);	//设置第一个选中的<td>标签元素的背景色为橘黄色,字体颜色为白色
d3.select("#test").classed("selected",true);	//设置第一个ID为"#test"的元素的背景色为橘黄色,字体颜色为白色
d3.select(".test").classed("selected",true);	//设置第一个类名为".test"的标签元素的背景色为橘黄色,字体颜色为白色
d3.select(document.body).on("click",function(e){ 
	console.log(d3.select(this));
	// d3.select(e.target).style("color","green");//点击选项变色
	d3.select(this).style("color","green");
});	//body监听单击事件,单击body区域设置字体的颜色变为绿色
d3.selectAll("tr").select("td").classed("selected",true);	//选择所有的行,并选择每行的第一列,设置选中元素的背景色为橘黄色

怎么选择还不存在的元素?

var dataset = [ 5, 10, 15, 20, 25 ];
	d3.select("body").selectAll("p")
		.data(dataset)
		.enter()
		.append("p")
		.text("New paragraph!");
//返回五个new paragraph
  • .selectAll("p")

    • 选择 DOM 中的所有段落。因为还没有段落,所以返回空元素。可以认为这个空元素代表马上就会创建的段落。
  • .data(dataset)

    • 解析并数出数据值。 dataset 数组中有 5 个值,因而此后的所有方法都将执行五遍,每次针对一个值。
  • .enter()

    • 要创建新的绑定数据的元素,必须使用 enter() 。这个方法会分析当前选择的DOM 元素和传给它的数据,如果数据值比对应的 DOM 元素多,就创建一个新的占位元素。然后把这个新占位元素的引用交给链中的下一个方法。
  • .append("p")

    • 取得由 enter() 创建的空占位元素,并把一个 p 元素追加到相应的 DOM 中。然后它再把自己刚创建的元素交给链中的下一个方法。

	var dataset = [ 5, 10, 15, 20, 25 ];
	d3.select("body").selectAll("p")
		.data(dataset)
		.enter()
		.append("p")
		.text((data)=>{return data});
//返回 5, 10, 15, 20, 25

提示

在连缀方法中,只要调用 data() 了,就可以随时创建一个接收 d 为输入的匿名函数。与当前元素对应,方法 data() 确保了每个 d 都会被赋予原始数据集中的一个值。

# D3选择操作

(各操作都移除了对象合写的写法,可以直接赋值,也可以以函数形式返回return内容;空值为查,赋值为改)

  • selection.attr(name[, value])

查看/修改属性

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" content="">
		<title>core - selection.attr(name[, value])</title>
		<script type="text/javascript" src="d3.min.js"></script>
	</head>
	<body>
		<script type="text/javascript">
			//绘制矩形的数据
			var dataset = [ 5, 10, 15, 20, 25 ];  
			
			//创建SVG
			var svg = d3.select("body")  
					.append("svg")  
					.attr("width", 960)	//一次设置一个属性值
					.attr("height", 500);

			//创建矩形
			rects=svg.selectAll("rect")
					.data(dataset)
					.enter()
					.append("rect")
					.attr("x",function(d,i){ return 20+i*160/dataset.length})
					.attr("y",function(d){ return 20})
					.attr("width",20)
					.attr(
						"height",100
					)
					.attr("fill","steelblue");
		</script>
	</body>
</html>
d3.select("#k").attr("k",13).attr("class","y1")
d3.select(".y1").style("color","orange")
  • selection.classed(name[, value])

用来设置class属性值得便捷程序,value为true添加class,为false则移除,没有value则是返回为name的class是否存在

	d3.select("#k").classed("t1",true)
	console.log(d3.select("#k").classed("t1"))
  • selection.style(name[, value[, priority]])

给选项修改样式

d3.select("#k").style("font-size","50px")

选择器函数参数

  • 返回的操作参数,第一个为data,如果没有赋值data,则为undefined
  • 第二个参数为选中数组的下标
  • 第三个参数为选中的数组本身
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" content="">
		<title>core - selection.text([value])</title>
		<script type="text/javascript" src="d3.min.js"></script>
	</head>
	<body>
		<div class="k">jqiweh</div>
		<div class="k">jqiweh</div>
		<div class="k">jqiweh</div>
		<script type="text/javascript">
			d3.selectAll(".k").
			data([3,4,5,6])
			.style("color",function(data,i,k){
				console.log(data,i,k)
				return "red"
			})
		</script>
	</body>
</html>
//3 0 (4) [div.k, div.k, div.k, empty]
//4 1 (4) [div.k, div.k, div.k, empty]
//5 2 (4) [div.k, div.k, div.k, empty]
  • selection.property(name[, value])

设置dom内容

<input type="text" id="text-id" /><br>
<input type="checkbox" id="checkbox-id" />.property<br>
<script type="text/javascript">			
	d3.select('#text-id')
		.property('value', function(){ 
			return d3.select(this).property('id');	//获取id属性的值
		});	//设置文本的value属性为此元素的ID值

	d3.select('#checkbox-id')
		.property('checked', true);	//设置复选框的checked属性	
</script>
  • selection.text([value])

设置元素的文本

d3.select('body').text("selection.text([value])");	//设置元素的文本	
d3.select('body')
	.text(function(){ 
		return "new text: "+d3.select(this).text();
	});	//设置元素的文本	

dx dy可控制文字偏移位置

bar.append("text")
		.attr("x", function(d) { return (d*scaleFactor); })
		.attr("y", barHeight / 2)
		.attr("dy", ".35em")
		.text(function(d) { return d; });

# svg文字水平居中 text-anchor

.attr("text-anchor", "middle")
  • selection.html([value])

设置innerHTML的内容

d3.select('body').html("<h1>大家好,我是H1!</h1>");//设置innerHTML的内容	
  • selection.append(name)

创建并追加一个新元素

d3.select("#k1").append("div").text("you")

# selection.insert(name[, before])

在已存在元素之前创建并插入一个元素

d3.select("#k1").append("div").classed("t1",true).text("9527")
d3.select("#k1").insert('div',".t1").text("3366")

<div id="k1">
	<div>3366</div>
	<div class="t1">9527</div>
</div>
  • selection.remove()

从当前文档中移除当前元素

d3.select("#k1").append("div").classed("t1",true).text("9527")
d3.select("#k1").insert('div',".t1").text("3366")
d3.select(".t1").remove()
  • selection.empty() 根据选择的元素是否为空返回true或false
d3.select(".t1").empty() 

# selection.data([values[, key]])

连接指定的一组数据的和当前选择。指定的values是一组数据值(例如,数字或对象)或一个函数返回一组值。如果没有指定key函数,则values的第一数据被分配到当前选择中第一元素,第二数据分配给当前选择的第二个元素,依此类推。当数据被分配给一个元素,它被存储在属性__data__中,从而使数据沾粘,使数据可以再选择。

  • key函数可以被指定为控制数据是如何连接元素。

  • values选择中的每组数据。data应该被指定为一个函数,该函数返回一个数组(假设你对每个组想要不同的数据)

先选中p元素,不管存不存在,然后带入数据data(),enter输出之前没有图形元素的数据项集

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" content="">
		<title>core - selection.append(name)</title>
		<script type="text/javascript" src="d3.min.js"></script>
	</head>
	<body>
		<div id="k1"></div>
		<table border="" cellspacing="" cellpadding="">
			<tr><th>Header</th></tr>
			<tr><td>Data</td></tr>
		</table>
		<script type="text/javascript">
			var matrix = [
			  [11975,  5871, 8916, 2868],
			  [ 1951, 10048, 2060, 6171],
			  [ 8010, 16145, 8090, 8045],
			  [ 1013,   990,  940, 6907]
			];
			
			var tr = d3.select("body").select("table").selectAll("tr")
			    .data(matrix,function(data,i,k){
					console.log(data)
					if(data){
						data.forEach((el,i)=>{
							data[i]=el+"kts"
						})
					}
					
				})
			  .enter().append("tr");
			
			console.log(tr)//返回数组
			var td = tr.selectAll("td")
			    .data(function(d) { 
					console.log(d)
					return d; 
				})
			  .enter().append("td")
			  .text(function(d) { return d; });	
		</script>
	</body>
</html>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title></title>
		
		<style>
			*{
				margin:0;
				padding:0
			}				
		</style>		
	</head>
	<body>
		<p>1</p>
		<p>2</p>
		<p>3</p>
		
	</body>
</html>
<script src="https://d3js.org/d3.v6.min.js"></script>
<!-- <script type="text/javascript" src="d3.js"></script> -->

<script>
var dataset = [3,6,9,12,15];
    	var p = d3.select("body")
    		.selectAll("p");
    	var update = p.data(dataset)//绑定数据,并得到update部分
    	var enter = update.enter();//得到enter部分
    	//下面检验是否真的得到
    	//对于update的处理
    	update.text(function(d,i){
    		return "update: "+d+",index: "+i;
    	})
    	//对于enter的处理
    	//注意,这里需要先添加足够多的<p>,然后在添加文本
    	var pEnter = enter.append("p")//添加足够多的<p>
    	pEnter.text(function(d,i){
    		return "enter: "+d+",index: "+i;
    	})
		/*update: 3,index: 0	
		update: 6,index: 1
		update: 9,index: 2		
		enter: 12,index: 3		
		enter: 15,index: 4
		*/
</script>

# selection.datum([value])

<div data-username="D3 user">4</div>
<div data-username="D3 fans"></div>
<script type="text/javascript">
	d3.selectAll("div")
	.datum(function() { return this.dataset; })	//获取HTML5自定义数据属性
	.text(function(d){ return d.username;});	//使用获取的数据设置文本的值
</script>
<!DOCTYPE html>
<script src="d3.min.js" charset="UTF-8"></script>
<div data-username="D3 user">4</div>
<div data-username="D3 fans"></div>
<script type="text/javascript">
	var s=d3.selectAll("div")
	.datum(function() {
		console.log(this.dataset)
		return this.dataset;
	 })	//获取HTML5自定义数据属性
	s.text(function(d){
		return d.username;
	})
	console.log(s)
	s.text(function(d){		
		return d.username+11
	})
	
	
	setTimeout(function(){
		s.text(function(d){			
			return d.username+22
		})
	},5000)
</script>
D3 user11
D3 fans11
----5S后变-------
D3 user22
D3 fans22
特性 datum data
集合运算 不支持 支持enter、exit函数
唯一性识别 不支持 不支持
旧数据清除 支持 不支持
读取数据 返回集合的第一条数据 返回集合的所有数据
赋值 将集合的每个元素设置为同样的值 集合更新运算,两个集合的交集运算
链式操作 后值总是覆盖前值 不断进行集合的交集运算
对空元素赋值 后续操作无效果 可通过enter添加新元素
//<p>dog</p>
//<p>cat</p>
//<p>pig</p>
var dataset = [3,6,9,12,15];
var p = d3.select("body")
	.selectAll("p");

// p.data(dataset).text(d=>d).enter().append("p").text(d=>d)//3 6 9 12 15
//p.data(dataset).enter().append("p").text(d=>d)//dog cat pig 12 15
  • selection.merge

merge函数实际上是完成Enter+Update步骤,作用就是对进入模式中选中的元素和更新模式中选中的元素进行合并,返回并集

merge处理的是选择集而不是data数据

<!DOCTYPE html>
<html>
  <body>
	 <link rel="stylesheet" type="text/css" href="./style.css"/>
    <script src="http://d3js.org/d3.v6.min.js"></script>

	<script type="text/javascript">
		var data = [10, 15, 30, 50, 80, 65, 55, 30, 20, 10, 8]; // <- A
		function render(data) { // <- B
			var bars = d3.select("body").selectAll("div.h-bar") // <- C
					.data(data); // Update <- D
			// Enter
			bars.enter() // <- E
					.append("div") // <- F
						.attr("class", "h-bar") // <- G
					.merge(bars) // Enter + Update <- H
					.style("width", function (d) {
						console.log(d)
						return (d * 3) + "px"; // <- I
					})
					//用了merge后,后比较更新,所以写在后面也会执行
					.text(function (d) {
						return d; // <- J
					});
			// Exit
			bars.exit() // <- K
					.remove();
		}
		
		//方法二 在更新前后都设置了style,因为第一次设置时还没添加div,可能会出bug(css设置了div颜色,由于I1行无数据不执行,会充满全屏),但是不影响流程,再I2行加上style就不会有bug了
		// function render(data) { // <- B
		//     var bars = d3.select("body").selectAll("div.h-bar") // <- C
		//             .data(data)
					// .style("width", function (d) {
					//     return (d * 3) + "px"; // <- I1
					// })
					// .text(function (d) {
					//     return d; // <- J1
					// });
					//  // Update <- D
					
		//     // Enter
		//     bars.data(data).enter() // <- E
		//             .append("div") // <- F
		//                 .attr("class", "h-bar") // <- G
		//             .style("width", function (d) {
		//                 return (d * 3) + "px"; // <- I2
		//             })
		//             .text(function (d) {
		//                 return d; // <- J2
		//             });
		
		
		//     // Exit
		//     bars.exit() // <- K
		//             .remove();
		// }
		
		
		setInterval(function () { // <- L
			data.shift();
			data.push(Math.round(Math.random() * 100));
			render(data);
		}, 500);
		render(data);
		
		
	</script>
  </body>
</html>

# selection.enter()

为缺失的元素返回占位符;返回输入(enter)选择:当前选择中存在但是当前DOM元素中还不存在的每个数据元素的占位符节点。此方法只在由data运算符返回的更新选择中定义。此外,输入选择只定义了append,insert,select和call操作符;必须使用这些操作符在修改任何内容之前实例化输入元素。当传递函数的参数给这些插入的元素的操作符时,index参数将反映新的位置,而不一定从零开始或者是连续的。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" content="">
		<title>core - selection.enter()</title>
		<script src="d3.min.js" charset="UTF-8"></script>
	</head>
	<body>
	<svg></svg>
		<script type="text/javascript">
			//生成text元素的数据
			var data = [ "text1","text2","text3","text4"];

			//新增元素
			var s=d3.select("svg").selectAll('text')
				.data(data)	//绑定数据
				.enter()		//返回新元素的占位符
				.append('text')	//新增新元素
				.attr('x','20',).attr('y', function (d, i) { return 20 + 20 * i})
				.text(function (d, i) { return d; });	
		
		</script>
	</body>
</html>

  • selection.exit()

返回不再需要的元素

此方法只被定义在data运算符返回的更新选择。exit选择定义了所有的正常操作符,但通常主要使用的是remove;其他操作符存在的主要目的是让您可以根据需要定义一个退出的过渡。请注意,exit操作符只是返回一个exit选择引用。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" content="">
		<title>core - selection.exit()</title>
		<script type="text/javascript" src="d3.min.js"></script>
	</head>
	<body>
		<script type="text/javascript">
			
			//生成6个div标签,内容是1, 2, 3, 4, 5, 6
			d3.select("body").selectAll("div")
				.data([1, 2, 3, 4, 5, 6])
				.enter()
				.append("div")
				.text(function(d) { return d; });
			
			//更新绑定的数组
			divs=d3.select("body").selectAll("div")
				.data([4, 5, 6, 7, 8, 9], function(d) { return d; })
			
			//用新数组生成div标签
			divs.enter()
				.append("div")
				.text(function(d) { return d; });
			
			//将第一个数组中退出的数据对应的元素删除
			//注释掉显示 1 2 3 4 5 6 7 8 9
			//不注释显示4 5 6 7 8 9
			//divs.exit().remove()
			
			//增加索引属性
			d3.selectAll("div").attr("index", function(d, i) { return i; });
		</script>
	</body>
</html>

  • selection.filter(selector)

过滤选择,返回一个新的选择只包含其指定的selector是true的元素。selector可以被指定为一个函数或作为选择的字符串,如“.foo”。和其他操作符一样,该函数被传递当前数据d和索引i,以及this上下文作为当前的DOM元素。过滤器应该只在选择与DOM元素绑定的时候。例如:从append或insert。只绑定的元素和数据的一个子集,可以在data参数中调用内置的数组过滤器filter。像内置函数一样,D3的过滤器不会在返回选择中保留原来的选择的索引;返回移除元素的副本。如果想保留的索引,使用select代替。

//例如,要选择奇数索引(相对于从零开始的索引)的每一个元素:(位运算)
var odds = selection.select(function(d, i) { return i & 1 ? this : null; });
//等价地,使用的过滤器函数:(位运算)
var odds = selection.filter(function(d, i) { return i & 1; });
//或过滤选择器(注意:nth-child伪类是一开始的索引,而不是从零开始的索引):
var odds = selection.filter(":nth-child(even)");
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" content="">
		<title>core - selection.filter(selector)</title>
		<script type="text/javascript" src="d3.min.js"></script>
	</head>
	<body>
	<svg width=960 hight=500></svg>
		<script type="text/javascript">
			//生成text元素的数据
			var data = [ "text1","text2","text3","text4"];
			//新增元素
			d3.select('svg').selectAll('text')
				.data(data)	   
				.enter()		
				.append('text')	
				.attr('x','20')
				.attr('y',function (d, i) {
						return 20 + 20 * i;
					})
				.attr(					
					'fill',"tomato"
				).text(function (d, i) { return d; });
			
			//过滤奇数索引的text,并设置其文本填充色为blue
			d3.select('svg').selectAll('text').filter(function(d, i) {
				return i % 2 == 0;
			}).style("fill", "green");
		</script>
	</body>
</html>

# selection.call -为当前选择调用一个函数

允许将选择集自身作为参数,传递给某一函数

d3.selectAll("div").call(myfun)
d3.select("svg").append("g").attr("id", "xAxisG").call(xAxis)
<====>
xAxis(d3.select("svg").append("g").attr("id", "xAxisG"))
  • selection.each(function)

each(允许对选择集的各元素分别处理)

let persons=[{id:1,name:"apple"},{id:2,name:"purple"}];
			let p=d3.selectAll("body")
			let k=p.selectAll("div").data(persons).enter().append("div")
			//each要写在生成的元素后面,要不然无效
			k.each((d,i)=>{
				console.log(d)
				d.age=20
			}).text(d=>{
				console.log(d)
				return d.id+":"+d.age+d.name
			})
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" content="">
		<title>core - selection.call(function[, arguments…])</title>
		<script type="text/javascript" src="d3.min.js"></script>
		<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.5/d3.js"></script> -->
	</head>
	<body>
	<svg></svg>
		<script type="text/javascript">
			<!DOCTYPE html>
			<html>
				<head>
					<meta charset="UTF-8" content="">
					<title>core - selection.each(function)</title>
					<script type="text/javascript" src="../../d3.js"></script>
				</head>
				<body>
				<svg></svg>
					<script type="text/javascript">
						//添加圆使用的数据集
						var dataset=[1,2,3,4,5,6,7,8,9,10];
						
						//颜色比例尺
						function color(){
							let x=Math.floor(Math.random()*255) 
							let y=Math.floor(Math.random()*255) 
							let z=Math.floor(Math.random()*255) 
							return `rgb(${x},${y},${z})`
						}
						
						//使用数据集添加10个圆
						d3.select('svg').selectAll("circle")
							.data(dataset)
							.enter()
							.append('circle');
						
						//使用each函数为每个圆设置属性
						d3.selectAll("circle")
						.each(function(d){
							d3.select(this)
							.attr('cx',function(d){ return 20*d})
							.attr('cy', 100)
							.attr('r', function(d){ return 3*d;})
							.attr('fill',color())
						});
					</script>
				</body>
			</html>
			
			
		</script>
	</body>
</html>
  • selection.interrupt selection.transition
    • 如果有过渡的话,立即中断当前的过渡
    • 在选中元素上开启过渡
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" content="">
		<title>core - selection.call(function[, arguments…])</title>
		<script type="text/javascript" src="d3.min.js"></script>
		<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.5/d3.js"></script> -->
	</head>
	<body>
	<svg></svg>
		<script type="text/javascript">
			d3.select('svg').append('circle')
							.attr('cx',100)
							.attr('cy', 100)
							.attr('r', 40)
							.attr('fill','orange');
						//开启动画,并设置动画结束时填充色为blue
						d3.select('svg').select('circle').transition().duration(5000)
							.attr("fill", "green");
						//设置定时器,2秒后启动
						setTimeout(function () {
							//2秒后立刻结束当前元素正在执行的动画
							d3.select('svg').select('circle').interrupt();
							//5秒后继续过渡为红色
							d3.select('svg').select('circle').transition().delay(5000)
							.attr("fill", "red");
						}, 2000);
			
		</script>
	</body>
</html>
  • selection.node() selection.node()
    • node()返回当前选择的第一个非空的元素。如果选择为空,则返回null。
    • nodes()函数,它会将选择的元素节点以数组形式返回。
<div>
	<h1>112</h1>
	<h1>142</h1>
	<h1>117</h1>
</div>
<script type="text/javascript">
	let a =d3.selectAll("h1")
	console.log(a.nodes())//[h1, h1, h1]
	console.log(a.node().innerHTML)//112
</script>
  • selection.sort lower rasie order
    • selection.sort() 元素排序
    • selection.lower 所选的元素放在第一位
    • selection.raise 所选的元素放在一位
    • selection.order 重排列文档中的元素,以匹配选择
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" content="">
		<title>core - selection.call(function[, arguments…])</title>
		<script type="text/javascript" src="d3.min.js"></script>
		<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.5/d3.js"></script> -->
		<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.0.0/d3.js"  ></script> -->
	</head>
	<body>
	<svg></svg>
	<ul class="list-group" id="list-group">
	    <li class="list-group-item">0002</li>
	    <li class="list-group-item">0001</li>
	    <li class="list-group-item">0003</li>
	</ul>
		<script type="text/javascript">
			var items = d3.select("#list-group")
						.selectAll(".list-group-item")
						//  对元素进行预处理
						.each(function(d) {
							//  为已有的元素添加数据
							if(d === undefined) {
								d3.select(this).datum({
									index : parseInt(this.textContent)
								})
							}
						})
						
						console.log(items)
						//  只能比较数据,并且会改变数据相关的DOM
						items.sort(function(a, b) {
							//  逆序
							return b.index - a.index;
						})
						
						//  将第二个元素提前
						items.filter(function(d) {
						    return d.index === 2
						}).lower();
						//  又恢复为逆序了,速度极快
						items.order();
		</script>
	</body>
</html>
  • d3.ascending 在sort方法中使用,升序
  • d3.descending 降序
var items =  [11,3,1,5,2];
console.log(items.sort(d3.ascending))
//[1, 2, 3, 5, 11] 升序
console.log(items.sort(d3.descending))
// [11, 5, 3, 2, 1] 降序
  • selection.size() 返回选择中的元素数
var lis =d3.selectAll("li").size()
console.log(lis)

# D3选择器动画交互

  • selection.on(type[, listener[, capture]]) 添加事件
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" content="">
		<title>core - selection.call(function[, arguments…])</title>
		<!-- <script type="text/javascript" src="d3.min.js"></script> -->
		<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.5/d3.js"></script> -->
		<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.0.0/d3.js"  ></script>
	</head>
	<body>
	<div id="k1">111</div>
	<script type="text/javascript">
		
				var svg = d3.select('body').append('svg')
							.attr('width',960)
							.attr('height',500);
						var text1=svg.append('text')
							.attr('x',200)
							.attr('y', 250)
						var text2=svg.append('text')
							.attr('x', 200)
							.attr('y', 300)
						//比较d3.mouse和d3.event的偏移坐标
						svg.on("mousemove", function (event) {
							//之前版本是d3.event 现在和原生一样event d3.event已经被废除
							console.log(event);								
						});
		</script>
	</body>
</html>

# d3data和datum的用法

var g = svg.selectAll("g") :创建组元素以保存接下来需要的内容。
.data(data) :将我们的数据数组绑定到组元素。
.enter() :为我们的组元素创建占位符。
.append("g") :将组元素附加到我们的页面。
<!DOCTYPE html> 
<html lang="en"> 
  
<head> 
    <meta charset="UTF-8"> 
    <meta name="viewport" content= 
        "width=device-width, initial-scale=1.0"> 
</head> 
  
<body> 	
	<ul id="k1">
		<li>datum</li>
		<li>datum</li>
	</ul>
	<hr>
	<ul id="k2">
		<li>data1</li>
		<li>data1</li>
	</ul>
	<hr>
	<ul id="k3">
		<li>data2</li>
		<li>data2</li>
	</ul>
	<hr>
	<ul id="k4">
		<li>data3</li>
		<li>data3</li>
	</ul>
	<hr>
	<ul id="k5">
		<li>data4</li>
		<li>data4</li>
	</ul>
	<hr>
	<ul id="k6">
		<li>data5</li>
		<li>data5</li>
	</ul>
	<hr>
    <!-- Fetching from CDN of D3.js -->
    <script type="text/javascript" 
        src="https://d3js.org/d3.v6.min.js"> 
    </script> 
      
    <script> 
		let arr1=[1,2,3,4]
		let k1 = d3.select("#k1")
		k1.selectAll("li").datum(arr1).text((d,i)=>{
			console.log(d,i)		
			return d[i]
		})
		
		let k2 = d3.select("#k2")
		console.log(k2.selectAll("li"))
		console.log(k2.selectAll("li").data(arr1))
		console.log(k2.data(arr1))
		console.log(k2.data(arr1).selectAll("li"))
		k2.selectAll("li").data(arr1).enter().append("li").text(d=>d)
		
		let k3 = d3.select("#k3")
		k3.selectAll("li").data([]).exit().remove()
		k3.selectAll("li").data(arr1).enter().append("li").text(d=>d)
		
		
		let k4 = d3.select("#k4")
		k4.selectAll("li").data(arr1).text(d=>d).enter().append("li").text(d=>d+"☆")
		
		
		let k5 = d3.select("#k5")
		k5.selectAll("sss").data(arr1).enter().append("li").text(d=>d+"$")
		
		let k6 = d3.select("#k6")
		k6.data(arr1).text(d=>d).enter().append("li").text(d=>d+"@")
		
    </script> 
</body> 
  
</html>

data与datum总结

  1. datum 不支持 enter exit函数,datum处理数组时不同于data,它会一次性填充,除非根据第二个参数i下标按顺序填充
  2. data处理数据与dom元素结合一般是分为三步:selectAll + 选取data + 绑定通过enter() update() exit() 操作
  3. data处理数据,如果不覆盖只更新后续内容,则只需在append后操作即可,如果要清除原先数据,则可以先添加空数组然后exit+remove移除或者在enter前进行操作修改数据
  4. data前不要遗忘selectAll步骤,否则数据会被加载的body上而不是期望的父节点
  5. 如果更改界面上原有的数据,如果依赖data,写在其后!否则获取不到
  • data也可以使用函数绑定数据
var data = []; 
var datum = function (x) { 
	//这个x怎么代表的值?
	return 15 + x * x;
};
var newData = function () { 	
	data.push(datum);
	return data;
};
var divs = d3.select("#container")
			.selectAll("div")
			.data(newData); 

selection.data([data[, key]])

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8"/>
		<title></title>
		<style type="text/css">
			.k1{
				margin: 10px 10px;
				height: 20px;
				background: #0055ff;
			}
		</style>
	</head>
  <body>
	 
    <script src="http://d3js.org/d3.v6.min.js"></script>
	
	<script type="text/javascript">
		
		var dataset = [1, 2, 3];
	    var divs = d3.select("body")
	            .selectAll("div")
	            .data(dataset)
	            .enter()
	            .append("div")
				.attr("class","k1")
				.html(d=>d)
	            .style("width", function (d) {
	                return d * 100 + "px";
	            });
		function change() {
		        dataset = [3];
		        divs.data(dataset)
		            .exit()
		            .remove();
		    }
		    setTimeout(change, 2000)
		
		//  function change() {
		//     dataset = [3];
		//     divs.data(dataset, function(d) {
		//         return d;
		//     })
		//         .exit()
		//         .remove();
		// }
		// setTimeout(change, 2000);
	</script>
  </body>
</html>

data的key函数参数,提供了一种,由data到selection的映射关系

最后更新: 2/23/2021, 8:52:32 AM