过渡是一种特殊类型的选择器,这种操作符的应用随时间平滑而不是瞬间变换
开始过渡
d3.transition([selection],[name]),创建动画过渡,等价于d3.select(document).transition()
transition.delay([delay]),指定过渡延迟,以毫秒为单位。如果延迟为常量,则所有的元素被赋予相同的延迟,如果延迟是一个函数,则这个函数的返回值将被用来为每个元素的延迟设置值。延迟总是相对一系列过渡中的第一个而言
transition.duration([duration]),指定每个元素的持续时间,单位为毫秒,默认持续时间为250毫秒
transition.ease([value[,arguments]]),指定过渡的缓动函数,cubic-in-out:默认缓动函数,慢入慢出;linear:普通的线性变化;circle:由慢到快的变换到最终状态;elastic:带有弹跳的到达最终状态;bounce:在最终状态处弹跳几次
过渡中的操作
内容
transition.attr(name,value),通过指定的name和value设置过渡属性的值
transition.attrTween(name,tween),name为过渡变化的属性名,tween是补间函数function(d,i,a),d是被绑定的数据,i是索引,a是指定属性的初始值,该函数返回的function(t),就是插值函数,t的范围是[0,1],0表示变化的起始,1表示变化的结束。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>补间动画</title>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<div class="box">
<svg></svg>
</div>
<script type="text/javascript">
var svg = d3.select("svg");
var rect = svg.append("rect")
.attr("fill", "yellow")
.attr("x", 100)
.attr("y", 100)
.attr("width", 100)
.attr("height", 30)
//初始值a等于100,当t等于0时,function(t)返回100。当t等于1时,function(t)返回400.此时,该过渡属性将width属性从100过渡到400,所用时间为2000ms(2s)
var rectTran = rect.transition()
.duration(2000)
.attrTween("width", function(d, i, a) {
return function(t) {
return Number(a) + t * 300
}
})
</script>
</body>
</html>
transition.style(name,value[,priority]),通过指定的name和value设置过渡的css样式属性值,可选参数优先级priority可以指定为null或者字符串“important”(不带感叹号)
transition.styleTween(name,tween[,priority]),通过指定的补间函数指定名称过渡的css样式属性值,补间函数的用法和上面一样
transition.text(value),基于textContent属性,设置的文本内容将取代任何现有的子元素
transition.tween(name,factory),对指定的名称自定义一个补间函数,用法同上
transition.remove(),在过渡结束时删除选定的元素
控制
transition.each([type],listener),遍历每一个元素运行操作,如果不指定触发类型(type),则马上运行操作,当指定触发类型为start或者end时,会在过渡的开始或者结束时运行操作
transition.call(function[,arguments...]),调用指定的函数一次,call操作符和手动执行一个函数是一样的
transition.empty(),如果当前过渡是空的,则返回true;过渡是空的,是指它不包含任何非null元素
transition.node(),返回当前过渡的第一个非空元素,如果为空,则返回null
transition.size(),返回当前过渡元素的个数
定时器
d3.timer(function[,delay[,time]]),启动一个自定义动画计时器,重复的调用指定的函数,直到它返回true,计时器启动后没办法取消。功能相当于setTimeout,但内部用requestAnimationFrame实现,更高效
d3.flush(),立马运行当前没有延迟的计时,可用于处理闪屏问题
插值
插值器是一个函数,用来将值域[0,1]中参数值t映射为一种颜色、数字或者任意值
d3.interpolate(a,b),返回一个介于a和b之间的默认插值器。插值器的类型是基于后面一个值b的类型,使用以下算法:
- 如果b是颜色类型,则返回interpolateRgb插值器
- 如果b是字符串类型,则返回interpolateString插值器
- 如果b是数组类型,则返回interpolateArray插值器
- 如果b是对象类型,且不能强制转换为数字类型,则返回interpolateObject插值器,否则返回interpolateNumber插值器
interpolate(t),对在区间[0,1]中一个给定的参数t,返回相关的插入值。插值器通常结合比例尺一起使用,映射一个输入域到一个输出范围
d3.interpolateNumber(a,b),返回a,b两个数字之间的数字插值器。返回的插值器相当于:
function interpolate(t) {
return a * (1 - t) + b * t;
}
注意:当插值器用于生成一个字符串时,应该避免插入0或者从0返回插值器
d3.interpolateRound(a,b),返回a,b两个数字之间的数字插值器,其结果会四舍五入为整数
d3.interpolateString(a,b),返回一个a和b两个字符串之间的字符串插值器
d3.interpolateRgb(a,b),返回一个a和b两种颜色值之间的RGB颜色空间插值器,插值器的返回值是一个十六进制的RGB字符串
d3.interpolateHsl(a,b),返回一个a和b两种颜色值之间的Hsl颜色空间插值器,插值器的返回值是一个十六进制的RGB字符串
d3.interpolateLab(a,b),返回一个a和b两种颜色值之间的Lab颜色空间插值器,插值器的返回值是一个十六进制的RGB字符串
d3.interpolateHcl(a,b),返回一个a和b两种颜色值之间的Hcl颜色空间插值器,插值器的返回值是一个十六进制的RGB字符串
d3.interpolateArray(a,b),返回一个在两个数组a和b之间的数组插值器
d3.interpolateObject(a,b),返回一个于a和b两个对象之间的插值器
d3.interpolateTransform(a,b),返回一个由a和b表示的二维仿射变换的插值器
d3.interpolateZoom(a,b),在两个点之间平滑的缩放平移
d3.interpolates,内置的自定义插值器数组,由d3.interpolate所使用
下面是两个简单的过渡的例子
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>掉落的小球</title>
<script src="https://d3js.org/d3.v3.min.js"></script>
<style type="text/css">
body{
background: #000000;
}
</style>
</head>
<body>
<div class="box"></div>
<script type="text/javascript">
let width = Math.max(960,innerWidth),
height = Math.max(660,innerHeight);
let svg = d3.select(".box").append("svg")
.attr("width",width)
.attr("height",height);
let j = 0;
function fun(){
let dataset = [];
for(let i=0;i<Math.random()*1000;i++){
let item = {
x:Math.floor(Math.random()*width),
y:-40
}
dataset.push(item)
}
let circle = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx",function(d){
return d.x
})
.attr("cy",function(d){
return d.y
})
.attr("r",18)
.style("fill", d3.hsl((j = (j + 1) % 360), 1, .5))
.transition()
.duration(3000)
.delay(function(d,i){
return 200*i
})
.ease('bounce')
.attr("transform",function(d){
return "translate(0,"+(height-d.y-50)+")"
})
.transition()
.duration(2000)
.ease("linear")
.attr("transform",function(d){
return "translate("+(-d.x)+","+(height-d.y-50)+")"
})
.remove();
}
fun()
let timer = setInterval(fun,2000)
</script>
</body>
</html>
<!DOCTYPE html>
<meta charset="utf-8">
<title>霓虹</title>
<style>
body {
margin: 0;
background: #222;
min-width: 960px;
}
rect {
fill: none;
pointer-events: all;
}
circle {
fill: none;
stroke-width: 2.5px;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = Math.max(960, innerWidth),
height = Math.max(500, innerHeight);
var i = 0;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("width", width)
.attr("height", height)
.on("ontouchstart" in document ? "touchmove" : "mousemove", particle);
let times = []
function particle() {
var m = d3.mouse(this);
times.push(m)
let x1 = times[0][0]
let y1 = times[0][1]
let x2 = times[times.length - 1][0]
let y2 = times[times.length - 1][1]
let length = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
if (length > 80) {
svg.insert("circle", "rect")
.attr("cx", m[0])
.attr("cy", m[1])
.attr("r", 1e-6)
.style("fill", d3.hsl((i = (i + 1) % 360), 1, .5))
.style("opacity", 1)
.transition()
.duration(2000)
.ease('bounce')
.attr("r", 80)
.style("opacity", 1e-6)
.remove();
times = []
} else {
return false
}
d3.event.preventDefault();
}
</script>