Reputation: 673
I have a D3 v4 force simulation with several nodes. Each node has a group. When I mouse over one of the elements of that group(an invisible circle) I want one of the other elements (the red circle on that specific node only which I gave an id of "backcircle") to do something. Currently this is what I have, but it does it to all nodes not just the one I'm hovering over's element.
this.node = this.d3Graph.selectAll(null)
.data(this.props.nodes)
.enter()
.append("g")
.attr("class", "nodes");
this.node.append("circle")
.attr("id", "backCircle")
.attr("r", 60)
.attr("fill", "red")
this.node.append("svg:image")
.attr("xlink:href", function(d) { return d.img })
.attr("height", 60)
.attr("width", 60)
.attr("x", -30)
.attr("y", -30)
this.node.append("circle")
.attr("r", 60)
.attr("fill", "transparent")
.on( 'mouseenter', function(d) {
d.r = 65;
this.node.select("#backCircle")
.transition()
.attr("r", 80);
}.bind(this))
Upvotes: 2
Views: 4412
Reputation: 102174
Before anything else, two important tips:
"transparent"
in an SVG.Back to your question:
There are several ways of selecting the circle element based on a sibling circle element. The first one is going up the DOM and down again, using this.parentNode
. The second one, if you know exactly the sequence of the siblings, is using previousSibling
.
In the following demos, I have 3 elements per group: a circle, a text and a rectangle. Hovering over the rectangle will select the circle.
First, the option with this.parentNode
. in your case:
d3.select(this.parentNode).select(".backCircle")
Hover over the squares:
var svg = d3.select("svg");
var data = [50, 150, 250];
var g = svg.selectAll(null)
.data(data)
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + d + ",75)"
});
g.append("circle")
.attr("class", "backCircle")
.attr("r", 40)
.attr("fill", "teal")
g.append("text")
.attr("font-size", 20)
.attr("text-anchor", "middle")
.text("FOO");
g.append("rect")
.attr("x", 20)
.attr("y", 20)
.attr("width", 20)
.attr("height", 20)
.style("fill", "firebrick")
.on("mouseenter", function() {
d3.select(this.parentNode).select(".backCircle")
.transition()
.attr("r", 50)
}).on("mouseleave", function() {
d3.select(this.parentNode).select(".backCircle")
.transition()
.attr("r", 40)
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Then, the option with previousSibling
(here, you don't even need to set a class). In your case:
d3.select(this.previousSibling.previousSibling)
Hover over the squares:
var svg = d3.select("svg");
var data = [50, 150, 250];
var g = svg.selectAll(null)
.data(data)
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + d + ",75)"
});
g.append("circle")
.attr("r", 40)
.attr("fill", "teal")
g.append("text")
.attr("font-size", 20)
.attr("text-anchor", "middle")
.text("FOO");
g.append("rect")
.attr("x", 20)
.attr("y", 20)
.attr("width", 20)
.attr("height", 20)
.style("fill", "firebrick")
.on("mouseenter", function() {
d3.select(this.previousSibling.previousSibling)
.transition()
.attr("r", 50)
}).on("mouseleave", function() {
d3.select(this.previousSibling.previousSibling)
.transition()
.attr("r", 40)
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
PS: Have in mind that, since I'm not using an object, there is no need for bind(this)
in my snippets.
Upvotes: 2
Reputation: 20821
I think you need to select the node that is firing the mouseenter event from within its handler.
this.node.append("circle")
.attr("r", 60)
.attr("fill", "transparent")
.on( 'mouseenter', function(d) {
var mouseenterNode = d3.select(this)
mouseenterNode.attr("r", 65);
mouseenterNode.select("#backCircle")
.transition()
.attr("r", 80);
}.bind(this))
Upvotes: 2