Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy and Insert in d3 selection

In a d3 program I need to get a node (with d3.selection) and then I want to insert in the same svg.

I know there are some functions like append, and insert, but these functions are for new elements.

var node = d3.select("rect#someId"); //node with some attributes and listeners

Now my var node got the following attributes: {_groups, _parents}

var anotherNode = d3.select("anotherNode").insert(node); //It work but it would be great a similar function or a workaround

Note. I need to preserve the listeners of the node

like image 609
leumashz Avatar asked Sep 13 '16 19:09

leumashz


People also ask

What do the select () and selectAll () functions in d3 do?

select selects the first matching element whilst d3. selectAll selects all matching elements. Both functions take a string as its only argument. The string specifies which elements to select and is in the form of a CSS selector string (e.g. div.

What does d3 selectAll return?

selectAll() function in D3. js is used to select all the element that matches the specified selector string. Parameters: This function accepts single parameter HTML tag as a parameter. Return Value: This function returns the selected elements.

What is or are the main selection in d3?

Selection methods come in two forms: select and selectAll: the former selects only the first matching element, while the latter selects all matching elements in document order. The top-level selection methods, d3.


1 Answers

New answer

D3 v5.0 introduced selection.clone, which:

Inserts clones of the selected elements immediately following the selected elements and returns a selection of the newly added clones.

Here is a demo:

var copy = d3.select("#group").clone(true).attr("transform", "translate(120,100)");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="200" height="200">
	<g id="group">
		<rect x="10" y="10" width="50" height="20" fill="teal"></rect>
		<circle cx="35" cy="40" r="20" fill="red"></circle>
	</g>
</svg>

Note that, just as the solution in the original answer, selection.clone will not clone the listeners.


Original answer

Use this function to clone your selection:

function clone(selector) {
    var node = d3.select(selector).node();
    return d3.select(node.parentNode.insertBefore(node.cloneNode(true), node.nextSibling));
}

Then, you can call it with clone("#foo") (by ID) or clone(".foo") (by class).

Here is an example, where the group (one rect and one circle) with ID "group" is cloned (the translate is just to better see the clone):

function clone(selector) {
    var node = d3.select(selector).node();
    return d3.select(node.parentNode.insertBefore(node.cloneNode(true),
node.nextSibling));
}

var copy = clone("#group").attr("transform", "translate(120,100)");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="200" height="200">
	<g id="group">
		<rect x="10" y="10" width="50" height="20" fill="teal"></rect>
		<circle cx="35" cy="40" r="20" fill="red"></circle>
	</g>
</svg>

PS: This will not clone the listeners. Also, this function is not mine, it was written by Bostock.

like image 66
Gerardo Furtado Avatar answered Sep 20 '22 12:09

Gerardo Furtado