Reputation: 373
This question is about transitions with d3.js, e.g. the change of the x attribute of a rectangle.
If you want the change to occur immediately you may set delay = duration = 0
as in
svg.selectAll("rect")
.transition()
.delay(delay)
.duration(duration)
.attr("x", 0)
but this may be too expensive (assuming that transitions are more CPU consumpting than immediate changes). So how can I add the transition conditionally, behaving like
if (delay == 0 && duration == 0) {
svg.selectAll("rect")
.attr("x", 0)
} else {
svg.selectAll("rect")
.transition()
.delay(delay)
.duration(duration)
.attr("x", 0)
}
but less redundant and more compact, somehow like x = condition ? 0 : 1
?
Upvotes: 4
Views: 714
Reputation: 102219
This is a very strange situation, and I cannot think about a use case where it would be useful. That being said, here is one out of many possible solutions: extend the D3 selection prototype.
In my approach, we'll extend the prototype to return the exact same selection in case of both delay
and duration
are zero, or return a transition selection based on the current selection if they're not zero:
d3.selection.prototype.conditionalTransition =
function(cond1, cond2) {
return cond1 && cond2 ? this.transition().duration(duration).delay(delay) : this;
};
Then, you just continue the chain of attr()
methods:
d3.selectAll("rect")
.conditionalTransition(delay, duration)
.attr("x", 200);
Finally, pay attention to the fact that regular selections and transition selections have different methods with the same name, like selection.on()
and transition.on()
.
Here is the first demo. All the rects are in x = 10
. The selection is turned into a transition selection:
d3.selection.prototype.conditionalTransition =
function(cond1, cond2) {
return cond1 && cond2 ? this.transition().duration(duration).delay(delay) : this;
};
const rect = d3.selectAll("rect");
const delay = 100,
duration = 1000;
rect.conditionalTransition(delay, duration)
.attr("x", 200)
function transitioning(sel) {
return sel.transition()
.delay(delay)
.duration(duration);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
<rect x="10" y="10" width="50" height="20" fill="teal"></rect>
<rect x="10" y="40" width="50" height="20" fill="teal"></rect>
<rect x="10" y="70" width="50" height="20" fill="teal"></rect>
<rect x="10" y="100" width="50" height="20" fill="teal"></rect>
</svg>
And here is the same code, with both delay
and duration
equal to zero. As you can see the rectangles are already in the final position, there is no transition:
d3.selection.prototype.conditionalTransition =
function(cond1, cond2) {
return cond1 && cond2 ? this.transition().duration(duration).delay(delay) : this;
};
const rect = d3.selectAll("rect");
const delay = 0,
duration = 0;
rect.conditionalTransition(delay, duration)
.attr("x", 200)
function transitioning(sel) {
return sel.transition()
.delay(delay)
.duration(duration);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
<rect x="10" y="10" width="50" height="20" fill="teal"></rect>
<rect x="10" y="40" width="50" height="20" fill="teal"></rect>
<rect x="10" y="70" width="50" height="20" fill="teal"></rect>
<rect x="10" y="100" width="50" height="20" fill="teal"></rect>
</svg>
Upvotes: 6