如何在D3中重用两个(或更多)链接转换序列 [英] how to reuse two (or more) sequences of chained transitions in D3
问题描述
我必须应用两个很长的链式转换序列,它们主要在转换顺序上有所不同,我正在寻找一种紧凑的编码方式.
I have to apply two very long sequences of chained transitions, which differ mainly on the order of transitions, and I'm looking for a compact way to code.
作为一个玩具示例,请考虑以下情况:顺序顺序应为a
,b
,c
,d
,e
,f
,g
,h
和e
,f
,g
,h
,a
,b
,c
,d
.我已经尝试使用下面的代码,但是它不起作用.请注意,过渡可能具有不同的属性(delay
,duration
,ease
等),并且它们可以应用于不同的属性(x
,y
,width
,height
或cx
,cy
,r
等)和样式.例如,过渡a
可以引用width
,过渡b
到height
,过渡c
到x
,过渡d
到y
,过渡e
到transform
属性,将f
转换为color
样式等.
As a toy example, consider the case where the sequence orders should be a
,b
,c
,d
,e
,f
,g
,h
and e
,f
,g
,h
,a
,b
,c
,d
. I've tried with the code below, but it doesn't work. Notice that the transitions could have different properties (delay
, duration
, ease
, and so on) and they could apply to different attributes (x
, y
, width
, height
or cx
, cy
, r
, and so on) and styles. For example, transition a
could refer to width
, transition b
to height
, transition c
to x
, transition d
to y
, transition e
to transform
attribute, transition f
to color
style, etcetera.
PS:此问题与我的上一个目标相同一个,但是在那里我使用了太多简单的编码案例,误导了答案.
P.S.: This question has the same aim of my previous one but there I used a too much simple coding case that misguided answers.
有没有办法以紧凑的方式编写代码?
Is there any way to code this in a compact way?
var t1 = d3
.transition() // transition "a" specifications
...
.transition() // transition "b" specifications
...
.transition() // transition "c" specifications
...
.transition() // transition "d" specifications
...
;
var t2 = d3
.transition() // transition "e" specifications
...
.transition() // transition "f" specifications
...
.transition() // transition "g" specifications
...
.transition() // transition "h" specifications
...
;
someelement1
.transition(t1).transition(t2);
someelement2
.transition(t2).transition(t1);
推荐答案
如注释中所述,回答此问题的原理与您先前的问题相同.在这种情况下,您会有一组不同的过渡,它们可能以不同键引用的任何顺序应用.让我们将它们存储在一个对象中:
As noted in the comments, the principles for answering this question are the same as your previous question. In this case, you have a set of different transitions that might be applied in any order referred to by different keys. Let's store them in an object:
var transitions = {
a: function(sel){ return sel.transition().duration(1000).delay(1000).attr('cy', 200) },
b: function(sel){ return sel.transition().duration(2000).delay(0).attr('r', 40) },
c: function(sel){ return sel.transition().duration(500).delay(1500).attr('fill', 'red') },
d: function(sel){ return sel.transition().duration(1500).delay(500).attr('opacity', 0.5) },
e: function(sel){ return sel.transition().duration(1000).delay(3000).attr('cy', 300) },
f: function(sel){ return sel.transition().duration(2000).delay(0).attr('r', 60) },
g: function(sel){ return sel.transition().duration(500).delay(1500).attr('fill', 'magenta') },
h: function(sel){ return sel.transition().duration(1500).delay(500).attr('opacity', 0.25) }
};
每个函数都使用一个d3.selection
对象,并对其应用特定的过渡参数和转换集.这些功能可能会很长而且很复杂.我很懒惰,几乎没有想象力,所以他们在这个版本中只做一次转换.
Each function takes a d3.selection
object and applies specific transition parameters and sets of transformations to it. These functions can be as long and complicated as you like. I am lazy with little imagination so they only do one transformation in this version.
这里已经有一些代码重复,因此让我们将选择内容转换为过渡内容,并使用this
而不是传递参数:
There's already a bit of code repetition here, so let's take out the conversion of the selection to a transition, and use this
instead of passing an argument:
var transitions = {
a: function(){ return this.duration(1000).delay(1000).attr('cy', 200) },
b: function(){ return this.duration(2000).delay(0).attr('r', 40) },
c: function(){ return this.duration(500).delay(1500).attr('fill', 'red') },
d: function(){ return this.duration(1500).delay(500).attr('opacity', 0.5) },
e: function(){ return this.duration(1000).delay(3000).attr('cy', 300) },
f: function(){ return this.duration(2000).delay(0).attr('r', 60) },
g: function(){ return this.duration(500).delay(1500).attr('fill', 'magenta') },
h: function(){ return this.duration(1500).delay(500).attr('opacity', 0.25) }
};
现在,我们可以通过调用类似的代码来执行这些转换
Now we can perform these transitions by calling code like
transitions['a'].call( selection.transition() )
transitions.f.call( d3.select('circle').transition() )
您要指定一个转换数组以应用于选择,类似这样:
You want to specify an array of transitions to apply to a selection, something like this:
apply_transitions( group.select(":nth-child(1)"), ['a','b','c','d'] );
apply_transitions( group.select(":nth-child(2)"), ['e','f','g','h'] );
这可以通过以下方式实现:
This could be implemented as follows:
/**
* apply a series of transitions to a selection
*
* @param selection - d3 selection
* @param tr_arr - array of transition identifiers, referring to functions in the `transitions` object
*/
function apply_transitions( selection, tr_arr ) {
// turn the current selection into a d3.transition
// call the transition function referred to by the first ID in the array
// with the d3.transition as the `this` context
// note that the function returns a transition object, so it can be chained
transitions[ tr_arr[0] ].call( selection.transition() )
// add a handler to be applied at the end of the transition
.on('end', function(){
// if there are more transitions to be applied, call
// apply_transitions again with tr_arr minus the first element
// note that the `this` context in the `on` function is a DOM element,
// so use `d3.select(this)` to turn it into a d3 selection
if ( tr_arr.length > 1 ) {
apply_transitions( d3.select(this), tr_arr.slice(1) );
}
})
}
实况示例:
var svg = d3.select('svg').attr('width', 500).attr('height', 500);
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');
apply_transitions( group.select(":nth-child(1)"), ['a','b','c','d'] );
apply_transitions( group.select(":nth-child(2)"), ['e','f','g','h'] );
function apply_transitions( selection, tr_arr ) {
var transitions = {
a: function(){ return this.duration(1000).delay(1000).attr('cy', 200) },
b: function(){ return this.duration(2000).delay(0).attr('r', 40) },
c: function(){ return this.duration(500).delay(1500).attr('fill', 'red') },
d: function(){ return this.duration(1500).delay(500).attr('opacity', 0.5) },
e: function(){ return this.duration(1000).delay(3000).attr('cy', 300) },
f: function(){ return this.duration(2000).delay(0).attr('r', 60) },
g: function(){ return this.duration(500).delay(1500).attr('fill', 'magenta') },
h: function(){ return this.duration(1500).delay(500).attr('opacity', 0.25) }
};
transitions[ tr_arr[0] ].call( selection.transition() )
.on('end', function(){
if ( tr_arr.length > 1 ) {
apply_transitions( d3.select(this), tr_arr.slice(1) );
}
})
}
<script src="http://d3js.org/d3.v5.js"></script>
<svg></svg>
这篇关于如何在D3中重用两个(或更多)链接转换序列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!