Reputation: 140
On the page I have a number of rectangles with the same class, say class one
.
How do I apply a transition to all those rectangles so they move to a new position with a new class (maybe class two
), but keeping those old rectangles stationary in the same position?
Could someone please correct me if I have explained it incorrectly?
For example I have these rectangles with class "start"
d3.select("svg")
.selectAll("rect")
.data([10,20,30,40,50])
.enter()
.append("rect")
.attr("class", "start")
.attr("x", d => d)
.attr("y", 1)
.attr("width", 5)
.attr("height", 5);
These rectangles coordinates are (10, 1), (20, 1), (30, 1) ...
Then I move them
d3.selectAll("rect")
.transition()
.attr("y", (d, i) => i + 5 * 10);
They will appear at the new co-ordinates (10, 50), (20, 51), (30, 52) ...
How can I make it so that the original rectangles with class start
at (10, 1), (20, 1), (30, 1) ... are still there but have new rectangles at (10, 50), (20, 51), (30, 52) ... with class stop
?
Upvotes: 3
Views: 105
Reputation: 28673
There is no need to use each
and a function to clone.
rectangles.clone(false)
.transition()
.attr("class", "stop")
.attr("y", (d, i) => i + 5 * 10);
const svg = d3.select("svg");
const rectangles = d3.select("svg")
.selectAll(null)
.data([10, 20, 30, 40, 50])
.enter()
.append("rect")
.attr("class", "start")
.attr("x", d => d)
.attr("y", 1)
.attr("width", 5)
.attr("height", 5);
rectangles.clone(false)
.transition()
.attr("class", "stop")
.attr("y", (d, i) => i + 5 * 10);
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>
Upvotes: 0
Reputation: 102194
As already made clear in your edit, you don't want to apply the transition to the existing elements: you want to clone them and apply the transition to their clones (or clone them before applying the transition to the original ones, which is the same...).
That being said, D3 has a pretty handy method named clone
, which:
Inserts clones of the selected elements immediately following the selected elements and returns a selection of the newly added clones.
So, supposing that your selection is named rectangles
(advice: always name your selections), instead of doing this...
rectangles.transition()
.attr("class", "stop")
.attr("y", (d, i) => i + 5 * 10);
...clone them first:
rectangles.each(cloneNodes)
.transition()
.attr("class", "stop")
.attr("y", (d, i) => i + 5 * 10);
function cloneNodes() {
d3.select(this).clone(false);
}
Here is the demo:
const svg = d3.select("svg");
const rectangles = d3.select("svg")
.selectAll(null)
.data([10, 20, 30, 40, 50])
.enter()
.append("rect")
.attr("class", "start")
.attr("x", d => d)
.attr("y", 1)
.attr("width", 5)
.attr("height", 5);
rectangles.each(cloneNodes)
.transition()
.attr("class", "stop")
.attr("y", (d, i) => i + 5 * 10);
function cloneNodes() {
d3.select(this).clone(false);
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>
Upvotes: 1