今天是纪录学习d3的第二篇博客,主要还是从源码的角度来分析d3的transition是如何实现的。这篇文章可能比较长,不过如果能够读完的话,我觉得肯定会对d3有更加深刻的认识。
学习资料
和上一篇一样首先列一下学习的资料,这些都能够在d3的github上能够找到
- 官方api
- Working with Transitions
- Creating Animations and Transitions With D3
- General Update Pattern, III
- d3源代码
简单的demo
我们先从一个简单的demo来熟悉一下d3中transition的api
效果很简单就是一个小球在移动呗。
html代码
<svg class = 'world'
width = '600'
height = '400'
version = "1.1"
baseProfile = "full"
xmlns="http://www.w3.org/2000/svg">
<circle class = 'cirlce'
cx = '30'
cy = '30'
r = '20'
fill = 'red'>
</circle>
</svg>
可以看到非常的简单就是定义一个svg和一个circle元素呗
javascript代码
<script type="text/javascript">
(function(d3){
setInterval(function(){
var circle;
circle = d3.select('.cirlce');
circle
.transition('position')
.attr('cx', 570)
.duration(1000)
.ease('bounce')
.transition('position')
.attr('cy', 370)
.transition('position')
.attr('cx', 30)
.ease('cubic')
.transition('position')
.attr('cy', 30)
.ease('bounce');
circle
.transition('size')
.attr('r', 40)
.duration(1000)
.ease('bounce')
.transition('size')
.attr('r', 20)
.duration(1000)
.transition('size')
.attr('r', 40)
.duration(1000)
.transition('size')
.attr('r', 20)
.duration(1000)
}, 4200);
})(d3);
</script>
代码也简单到不要不要的,这里我就不解释了,不过这里有三个地方是需要注意的:
transition函数返回的东西和select返回的东西是不一样的
这里我们定义了两种transition,一种为position,一种是size
我们这里在circle调用transition后通过链式调用再次调用了transition
第一点,transition函数返回对象的类型为d3_transitionPrototype,select函数返回对象类型为d3_selectionPrototype,两者api很相似,但是确实是不一样的东西。
第二点需要注意是因为在d3中,在一个时刻,每一个元素对于一个名字(上面提到的position和size)只能执行一个动画。如果想要在一个时刻对一个元素执行多个动画,就可以像我们demo一样,给元素定义两个不同名字的动画。
第二点其实就是链式调用,因为transition函数返回的对象类型为d3_transitionPrototype,这个对象类型的transition函数所产生的动画是在当前动画执行完之后才会执行。并且新创建的动画会继承d3_selectionPrototype对象创建的transition的一些属性,比如ease,duration和delay等。对于d3_selectionPrototype的transition函数和d3_selectionPrototype的transition函数在后面我们都会进行详细的解释。
源码解析
d3.timer
想要了解d3的transition,我们必须首先了解一下d3.timer,因为d3的transition是基于d3.timer来实现的,对于它的官网解释可以看这个文档d3.timer。按照我的理解,其实d3.timer就是来维护一个动画队列的。我们来看看它的源码吧:
d3.timer = function() {
d3_timer.apply(this, arguments);
};
这里调用了d3_timer,我们就看看d3_timer及其相关的代码呗
var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) {
setTimeout(callback, 17);
};
function d3_timer(callback, delay, then) {
var n = arguments.length;
if (n < 2) delay = 0;
if (n <