一种在D3中编码链接转换的紧凑方法 [英] a compact way to code chained transitions in D3
问题描述
我必须应用两个较长的链式转换序列,这些序列的主要区别在于某些元素上的转换顺序不同,我正在寻找一种紧凑的编码方式. 假设(仅作为玩具示例)我有两个圆圈,并且我必须将以下颜色应用于第一个圆圈:
I have to apply two long sequences of chained transitions which differ mainly in the order of transitions on some elements, and I'm looking for a compact way to code. Suppose (only as a toy example) that I have two circles and I have to apply the following colors to the first one:
orange
-> purple
-> blue
-> yellow
;
orange
-> purple
-> blue
-> yellow
;
,第二种颜色如下:
blue
-> yellow
-> orange
-> purple
.
blue
-> yellow
-> orange
-> purple
.
我尝试使用下面的代码(在此处拨弄),但是它不起作用.哪一种最紧凑的方法可以实现这一目标?
I've tried with the code below (fiddle here), but it doesn't work. Which is the most compact way to achieve this?
var svg = d3.select('svg');
var dataSet = [20, 20];
var group=svg.append("g");
var circles = group.selectAll('circle')
.data(dataSet)
.enter()
.append('circle')
.attr("r",function(d){ return d })
.attr("cx",function(d, i){ return i * 100 + 50 })
.attr("cy",50)
.attr("fill",'black');
var t1 = d3
.transition()
.duration(1000)
.attr("fill","orange")
.transition()
.duration(1000)
.attr("fill","purple");
var t2 = d3
.transition()
.duration(1000)
.attr("fill","blue")
.transition()
.duration(1000)
.attr("fill","yellow");
group.select(":nth-child(1)")
.transition(t1).transition(t2);
group.select(":nth-child(2)")
.transition(t2).transition(t1);
推荐答案
有多种方法可以实现此目的.如另一个答案中所述,为此使用函数将使您的代码紧凑.就我个人而言,我倾向于使用过渡的end事件来触发过渡函数中的下一个过渡.
There are a multitude of ways to achieve this. As noted in the other answer, using a function for this will keep your code compact. Personally I tend to use the transition's end event to trigger the next transition from within the transition function.
这种功能的一般形式如下:
The general form for this sort of function is as follows:
function transition() {
// .... optional logic here.
d3.select(this) // do transition:
.transition()
.attr("fill", ... )
.on("end", transition); // and repeat.
}
可以用selection.each(transition)
管理循环中当前颜色/过渡的一种方法是使用自定义属性.下面,我使用.attr("i")
进行跟踪:
One approach to managing the current color/transition in the cycle is to use a custom attribute. Below I use .attr("i")
to keep track:
var data = [
["orange","purple","blue","yellow"],
["blue","yellow","orange","purple"]
];
var svg = d3.select("svg");
var circles = svg.selectAll()
.data(data)
.enter()
.append("circle")
.attr("r", 20)
.attr("cx", function(d,i) { return i * 50 + 50; })
.attr("cy", 50)
.attr("fill", function(d) { return d[0]; })
.attr("i",0)
.each(transition);
// cycle endlessly:
function transition() {
var selection = d3.select(this);
// keep track of current value:
var i = selection.attr("i")
selection
.attr("i",i = ++i%4)
.transition()
.duration(1000)
.attr("fill", function(d) { return d[i] })
.on("end", transition);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<svg width="500" height="300"></svg>
如果您的过渡仅在顺序(起点)上有所不同,则可以对上述方法进行一些修改:
If you have transitions that differ only in order (start point), you can modify the above approach a bit:
var data = [50,75,100,125,150,175,200,225];
var colors = ["orange","purple","blue","yellow"];
var svg = d3.select("svg");
var circles = svg.selectAll()
.data(data)
.enter()
.append("circle")
.attr("r", 20)
.attr("cx", function(d) { return d; })
.attr("cy", 50)
.attr("fill", function(d,i) { return colors[i%4]; }) // set start fill
.attr("i", function(d,i) { return i%4; }) // record start position.
.each(transition);
function transition() {
var selection = d3.select(this);
var i = selection.attr("i");
i = ++i%colors.length;
selection.transition()
.duration(1000)
.attr("i",i)
.attr("fill", colors[i])
.on("end", transition);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<svg width="500" height="300"></svg>
第一个我使用颜色集作为基准,第二个我仅使用位置访问带有i
属性的颜色
First one I use color sets as the datum, second one I just use position accessing the color with the i
attribute
以上方法使用自定义属性,但我们也可以使用基准.这使我们在某些方面对D3有了更多的了解.
The above methods use a custom attribute, but we can use the datum too. This allows us a bit more D3 familiarity in some ways.
例如,我们可以有一个名为color和递增的属性,它可以在设置每个过渡时填充(再次假设我们有一个colors数组,并且每个圆都从它的不同点开始):
For example, we can have a property called color and increment that while setting the fill on each transition (again assuming we have a colors array and each circle starts at a different point on it):
function transition() {
d3.select(this).transition()
.duration(1000)
.attr("fill", function(d) { return colors[++d.color%colors.length]; })
.on("end", transition);
}
var data = d3.range(8).map(function(d) { return {x: d*25+50}; })
var colors = ["orange","purple","blue","yellow"];
var svg = d3.select("svg");
var circles = svg.selectAll()
.data(data)
.enter()
.append("circle")
.attr("r", 20)
.attr("cx", function(d) { return d.x; })
.attr("cy", 50)
.attr("fill", function(d,i) { return colors[i%4]; }) // set start fill
.each(function(d,i) { d.color = i%4; }) // record start position.
.each(transition);
function transition() {
d3.select(this).transition()
.duration(1000)
.attr("fill", function(d) { return colors[++d.color%colors.length]; })
.on("end", transition);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<svg width="500" height="300"></svg>
如果您希望过渡重复x次,甚至让所有末端都使用相同的颜色,我们也可以通过在基准面上添加新属性来跟踪已完成的循环来相当容易地做到这一点:
If you want the transitions to repeat x times, or even have all end on the same color, we can do that fairly easily too by adding a new property to the datum to track cycles completed:
var data = d3.range(8).map(function(d) { return {x: d*25+50}; })
var colors = ["orange","purple","blue","yellow"];
var svg = d3.select("svg");
var circles = svg.selectAll()
.data(data)
.enter()
.append("circle")
.attr("r", 20)
.attr("cx", function(d) { return d.x; })
.attr("cy", 50)
.attr("fill", function(d,i) { return colors[i%4]; }) // set start fill
.each(function(d,i) { d.color = d.start = i%4; }) // record start position.
.each(transition);
var n = 8; // n cycles
function transition() {
d3.select(this).transition()
.duration(1000)
.attr("fill", function(d) { return colors[++d.color%colors.length]; })
.on("end", function(d) { if(d.color - d.start < n) transition.apply(this); else return null; });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<svg width="500" height="300"></svg>
有很多方法可以破坏性地修改基准面(或部分基准面),例如在只能运行一次的过渡周期中使用shift:
There are lazier ways that destructively modify the datum (or portions of it), such as using shift in this transition cycle that can only run once:
var data = [
["orange","purple","blue","yellow"],
["blue","yellow","orange","purple"]
];
var svg = d3.select("svg");
var circles = svg.selectAll()
.data(data)
.enter()
.append("circle")
.attr("r", 20)
.attr("cx", function(d,i) { return i * 50 + 50; })
.attr("cy", 50)
.attr("fill", function(d) { return d.shift(); })
.each(transition);
function transition() {
var selection = d3.select(this);
if(selection.datum().length) {
selection.transition()
.duration(1000)
.attr("fill", function(d) { return d.shift() })
.on("end", transition);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<svg width="500" height="300"></svg>
您可能会看到我的代码片段都不使用子选择器:可以通过自定义属性,基准属性或更简单地避免这种情况,可以在过渡本身中使用.attr("fill",function(d,i){
来区分奇数和偶数元素.我对那些选择器没有什么反对,只是需要进行其他选择.
You might see that none of my snippets use child selectors: this can be avoided by custom attributes, datum properties, or more simply, using .attr("fill",function(d,i){
in the transition itself to differentiate odd and even elements. I have nothing against those selectors though, it just requires additional selections to be made.
这篇关于一种在D3中编码链接转换的紧凑方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!