I'd like to show and hide a node in SVG when mouseover / mouseout, the issue is that my shape inside the node is a path with only 1.5px width so is not easy to hit that area in the mouseover event, that's definitely inconvenient to user experience.
I'd like to know if there's a way to make that hit area wider using an arbitrary width, but invisible to the user?
a snippet of my code:
link.enter()
.append('g').attr('class', 'link')
.append('line')
.attr('class', 'path')
.attr('marker-end', function(d, i) {
if (i === 2) {
return 'url(#arrow)';
} else {
return null;
}
}).on('mouseover', function(d) {
//alert(JSON.stringify(d));
alert('mouseover');
}).on('mouseout', function(d) {
alert('mouseout');
});
the css:
.node .path {
stroke: #878f8f;
stroke-width: 1.5px;
fill:none;
}
You can add another line
to the g
with transparent stroke and with large stroke-width, which will increase the hit area.
// Subscribe to mouse events on the entire g
gEnter = link.enter()
.append('g')
.attr('class', 'link')
.on('mouseover', function(d) {
//alert(JSON.stringify(d));
alert('mouseover');
}).on('mouseout', function(d) {
alert('mouseout');
});
// Instead of 1 line, append 2 lines inside the g, and make
// one of them transparent and "fat", which will enlarge the
// hit area
lines = gEnter
.selectAll('.path').data(['visible', 'invisible'])
lines.enter()
.append('line')
.attr('class', 'path')
.attr('marker-end', function(d, i, j) {
// j is the parent's i
if (j === 2) {
return 'url(#arrow)';
} else {
return null;
}
})
.attr({
// returning null from these functions simply defaults to whatever the
// .path class's CSS props are doing
'stroke-width': function(d, i) { return d == 'invisible' ? 10 : null },
'stroke': function(d, i) { return d == 'invisible' ? 'transparent' : null }
})
How are you defining link
here? I could not figure out your solution, but I followed the same idea of appending two lines (one visible and the other invisivle) to a parent g
element. I don't think it is too efficient, because I end up having to call for the line coordinates twice (once for the visible line and one for the invisible line). This is what I did:
//define the link element in a parent g
var link = svg.selectAll("g.link")
.data(json.links)
.enter().append("g")
.on("click", linkMouseClick)
.on("mouseover", linkMouseover);
//append a visible child line to parent g
var line = link.append("line")
.attr("class", "link")
.style("stroke-width", "2");
//append a second, fatter line to g and make it invisible
var fatline = link.append("line")
.attr("class", "link")
.attr("style", "stroke:transparent;stroke-width:10px");
//call for line coordinates for both lines
force.on("tick", function() {
line.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
fatline.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
});
It works, but if anyone can suggest improvements, that would be great, thanks!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With