# d3过渡

过渡是一种特殊类型的选择器(selection),这种操作符的应用随时间平滑而不是瞬间变换。D3过渡实现了一种基于插值的动画。

npm install d3-ease
transition 开启过渡
ease 选择自带的动效函数
duration 持续时间
delay 允许进行转换过了一段时间
  • d3.selection.data的第二个参数,通常这个函数称为对象标识函数:确保返回对象的一致性,更稳定的绑定数据和图形。
  • d3.selection.exit函数会返回一个选集,在remove之前是可以操作的
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Multi-Element Transition</title>
    <link rel="stylesheet" type="text/css" href="../../css/styles.css"/>
    <script src="https://d3js.org/d3.v6.min.js"></script>
</head>

<body>

<script type="text/javascript">
    var id= 0,
        data = [],
        duration = 500,
        chartHeight = 100,
        chartWidth = 680;

    for(var i = 0; i < 20; i++) push(data);

    function render(data) {
        var selection = d3.select("body")
                .selectAll("div.v-bar")
                .data(data, function(d){
					console.log(d)
					return d.id;
				}); // <-A

        // enter
        selection.enter()
                .append("div")
                .attr("class", "v-bar")
                .style("z-index", "0")
                .style("position", "fixed")
                .style("top", chartHeight + "px")
                .style("left", function(d, i){
                    return barLeft(i+1) + "px"; // <-B
                })
                .style("height", "0px") // <-C
                .append("span");

        // update
        selection
                .transition().duration(duration) // <-D
                .style("top", function (d) {
                    return chartHeight - barHeight(d) + "px";
                })
                .style("left", function(d, i){
                    return barLeft(i) + "px";
                })
                .style("height", function (d) {
                    return barHeight(d) + "px";
                })
                .select("span")
                .text(function (d) {return d.value;});

        // exit
        selection.exit()
                .transition().duration(duration) // <-E
                .style("left", function(d, i){
                    return barLeft(-1) + "px"; //<-F
                })
                .remove(); // <-G
    }

    function push(data) {
        data.push({
            id: ++id,
            value: Math.round(Math.random() * chartHeight)
        });
    }

    function barLeft(i) {
        return i * (30 + 2);
    }

    function barHeight(d) {
        return d.value;
    }

    setInterval(function () {
        data.shift();
        push(data);
        render(data);
    }, 2000);

    render(data);

    d3.select("body")
       .append("div")
           .attr("class", "baseline")
           .style("position", "fixed")
           .style("z-index", "1")
           .style("top", chartHeight + "px")
           .style("left", "0px")
           .style("width", chartWidth + "px");
</script>

</body>

</html>
  • .ease函数不支持d选项,所以如果自定义的写法,可以使用each函数里使用
  • 当d3.select("body").selectAll("div").data(data).enter().append("div")之后,其实再选择d3.select("body").selectAll("div")因为粘连_data_,可以直接获取到数据d了
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Easing</title>
    <link rel="stylesheet" type="text/css" href="../../css/styles.css"/>
    <script src="https://d3js.org/d3.v6.min.js"></script>
</head>

<body>

<script type="text/javascript">
    var data = [ // <-A
            {name: 'Linear', fn: d3.easeLinear},
            {name: 'Cubic', fn: d3.easeCubic},
            {name: 'CubicIn', fn: d3.easeCubicIn},
            {name: 'Sin', fn: d3.easeSin},
            {name: 'SinIn', fn: d3.easeSinIn},
            {name: 'Exp', fn: d3.easeExp},
            {name: 'Circle', fn: d3.easeCircle},
            {name: 'Back', fn: d3.easeBack},
            {name: 'Bounce', fn: d3.easeBounce},
            {name: 'Elastic', fn: d3.easeElastic},
            {name: 'Custom', fn: function(t){ return t * t; }}// <-B
        ],
        colors = d3.scaleOrdinal(d3.schemeCategory10);
	console.log(d3.selectAll("div"))
    d3.select("body").selectAll("div")
            .data(data) // <-C
        .enter()
        .append("div")
            .attr("class", "fixed-cell")
            .style("top", function (d, i) {
                return i * 40 + "px";
            })
            .style("background-color", function (d, i) {
                return colors(i);
            })
            .style("color", "white")
            .style("left", "500px")
            .text(function (d) {
                return d.name;
            });
	
	console.log(d3.selectAll("div"))
    d3.selectAll("div").each(function(d){
		// console.log(d)
        d3.select(this)
                .transition().ease(d.fn) // <-D
            .duration(1500)
            .style("left", "10px");
    });
	
	d3.selectAll("div").style("color",d=>{
		console.log(d)
	})

   
    // d3.selectAll("div").transition().ease(d.fn) // does not work
    //     .duration(1500)
    //     .style("left", "10px");
    
</script>

</body>

</html>

# x.ease(type[, arguments…])

x.transition()
    .ease(d3.easeLinear)
  • d3.easeLinear() 函数用于线性缓和到特定元素的过渡效果。该线性缓动函数返回一个恒等函数
    • 参数:该函数不接受任何参数。
    • 返回值:此函数不返回任何值。
<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <meta name="viewport" 
        content="width=device-width,  
                initial-scale=1.0"> 
    <script src="https://d3js.org/d3.v6.min.js"></script>   
</head> 
<body> 
    <h3 style="color:green">GeeksforGeeks</h3> 
    <svg width="500px" height="500px"> 
    </svg>   
    <script> 
        var svg = d3.select("svg");          
        svg.append("circle") 
            .attr("r", 30) 
            .attr("cy",40) 
            .attr("cx",30) 
            .attr("fill", "green") 
            .transition() 
            // Use of easeLinear 
            .ease(d3.easeCubic) 			
            .duration(2000) 
            .attr("cy",40) 
            .attr("cx",200); 		
			console.log(d3.easeElastic)
    </script> 
</body> 
</html>
  • d3.easeBounce 弹跳缓动

# d3-transition中的start和end事件

d3.select("#k2")
   .transition()
   .delay(200)
   .on("start", function() {
	   console.log(d3.select(this))//指的数据组
	   d3.select(this).style("color", "green"); 
	})
	.on("end",()=>{
		console.log(this)//window
		console.log(d3.select(this))
		// d3.select(this).style("color", "orange"); //end事件再去修改会出错
	})
	.transition()
	.delay(2000)
	.style("color", "red");

# d3-transition delay

//整体延迟
.transition()
.duration(1000)
.delay(500)

//个别指定延迟
.transition()
.duration(1000)
.delay(funtion(d,i){
    return 200*i;
})

# d3-transition active和interrupt

  • selection.interrupt([name]) 中断选择集上活动的名为name的过渡。如果name所表示的过渡还没有开始,则也不用开始了。如果没有指定name,则使用null。
selection.interrupt().selectAll("*").interrupt();

返回指定节点上名为name的活动的过渡。如果没有指定name则使用null。这个方法可以方便的创建链式过渡,比如创建一个循环disco过渡

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <meta name="viewport" content= 
        "width=device-width, initial-scale=1.0"> 
</head> 
<body> 		
	<svg height=500 width=500>
		<circle
			cx="25" cy="25" r="20"
		></circle>
		<circle
			cx="75" cy="25" r="20"
			></circle>
		<circle
			cx="125" cy="25" r="20"
		></circle>
	</svg>	
    <!-- Fetching from CDN of D3.js -->
    <script type="text/javascript" 
        src="https://d3js.org/d3.v6.min.js"> 
    </script> 
      
    <script> 
		let n=0;
		d3.selectAll("circle").transition()
		    .delay(function(d, i) { return i * 1000; })
		    .on("start", function repeat() {
				n++;
				console.log(d3.interrupt)
				console.log( d3.active(this))
				console.log(n)
				if(n>=5){
					console.log(d3.select(this))
					d3.selectAll("circle").interrupt();
					console.log("ok")
					return
				}
		        d3.active(this)	
		            .style("fill", "red")
		          .transition()
				  .delay(600)
		            .style("fill", "green")
		          .transition()
				  .delay(800)
		            .style("fill", "blue")
		          .transition()
				  .delay(1000)
		            .on("start", repeat)
		      })	
    </script> 
</body> 
  
</html>

# 中间帧 tween

tween函数式一个工厂函数,用来构造执行中间帧计算的最终函数

.attrTween('d', function(d, i) {
	let interpolate = d3.interpolate(d.startAngle, d.endAngle);
	return function(t) {
		d.endAngle = interpolate(t);
		return arc(d);
	}
})

如下实际中间帧计算函数通过量化尺度对传入的时间参数进行插值。

<!DOCTYPE html>
<html>
  <body>
	 <link rel="stylesheet" type="text/css" href="./style.css"/>
    <script src="http://d3js.org/d3.v5.min.js"></script>
<script type="text/javascript">
    var body = d3.select("body"), duration = 5000;
    
    body.append("div").append("input")
        .attr("type", "button")
        .attr("class", "countdown")
        .attr("value", "0")
        .style("width", "150px")
        .transition().duration(duration).ease(d3.easeLinear)
            .style("width", "400px")
            .attr("value", "9");
            
    body.append("div").append("input")
        .attr("type", "button")
        .attr("class", "countdown")
        .attr("value", "0")
        .transition().duration(duration).ease(d3.easeLinear)
            .styleTween("width", widthTween) // <- A
            .attrTween("value", valueTween); // <- B
            
            
    function widthTween(a){
        var interpolate = d3.scaleQuantize()
            .domain([0, 1])
            .range([150, 200, 250, 350, 400]);
        
        return function(t){
            return interpolate(t) + "px";
        };
    }
            
    function valueTween(){
        var interpolate = d3.scaleQuantize() // <-C
            .domain([0, 1])
            .range([1, 2, 3, 4, 5, 6, 7, 8, 9]);
        
        return function(t){ // <-D
            return interpolate(t);
        };
    }        
</script>
  </body>
</html>

# d3.interpolateRgb

d3.selectAll("circle").transition()
.delay(function(d, i) { return i * 1000; })
.on("start", function repeat() {
	n++;
	console.log(d3.interrupt)
	console.log( d3.active(this))
	console.log(n)
	d3.active(this)	
		.style("fill", "red")
	  .transition()
	  .delay(800)
		.styleTween("fill", function() {
		  return d3.interpolateRgb("purple","orange");
		})
	  .transition()
	  .delay(1000)
		.on("start", repeat)
  })
transition.attrTween("fill", function() {
  return function(t) {
    return "hsl(" + t * 360 + ",100%,50%)";
  };
});
transition.styleTween("fill", function() {
  return d3.interpolateRgb(this.style.fill, "blue");
});

# d3监听过渡事件

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Transition Events</title>
    <link rel="stylesheet" type="text/css" href="../../css/styles.css"/>
    <script src="https://d3js.org/d3.v6.min.js"></script>
</head>

<body>

<script type="text/javascript">
    var body = d3.select("body"), duration = 3000;

    var div = body.append("div")
            .classed("box", true)
            .style("background-color", "steelblue")
            .style("color", "white")
            .text("waiting") // <-A
        .transition().duration(duration) // <-B
                .delay(1000) // <-C
                .on("start", function(){ // <-D
                    d3.select(this).text(function (d, i) {
                        return "transitioning";
                    });
                })
                .on("end", function(){ // <-E
                    d3.select(this).text(function (d, i) {
                        return "done";
                    });
                })
            .style("margin-left", "600px");
</script>

</body>

</html>

# d3.timer

npm install d3-timer

用于在特定时间间隔后运行计时器功能。计时器将在指定的延迟后运行。给出的延迟以毫秒为单位。

d3.timer(function[,delay])
let func=function(e) { 
  console.log(e); 
  if (e>300){ 
	console.log("Timer stopped") 
	timer.stop(); 
  } 
} 
// Delay of 2000ms 
var timer = d3.timer(func, 2000); 

# timer.stop()

用于停止当前正在进行的计时器函数,从而防止对该函数的进一步调用。仅当计时器尚未停止时,此功能才起作用。

# timer.restart() 重启某个函数

  • timer.restart(callback, delay);
    • callback:它是在特定延迟后停止或启动的功能。
    • delay:这是该功能将被执行或停止的时间

# d3.timeout(cb[,delay[,time]])

在执行完第一次回调之后会自动 stops。可以作为 setTimeout 的替换,因为这个方法不会在页面处于非活动状态时运行(内部使用requestAnimationFrame实现)。callback 参数为 elapsed (定义定时器到回调执行之间的时间)。

# d3.interval(callback[, delay[, time]])

这个方法可以用来替换 setInterval 因为基于 requestAnimationFrame 实现,不会在后台执行

# d3.timerFlush()

更多缓动 (opens new window)

最后更新: 2/24/2021, 1:47:16 PM