the problem is that my form inside t...">

Mouse manipulation "hit area" in d3.js

I would like to show and hide a node in SVG when mouseover / mouse> the problem is that my form inside the node is a path only 1.5px wide, so it is not easy to hit that area on a mouseover event, which is definitely awkward for users.

I would like to know if there is a way to make this remote area wider using an arbitrary width but invisible to the user?

snippet of 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');
    });

      

css:

.node .path {
  stroke: #878f8f;
  stroke-width: 1.5px;
  fill:none;
}

      

+3


source to share


2 answers


You can add line

in g

a transparent stroke and high stroke width, which will increase the area of contact.



// 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 i
        if (j === 2) {
            return 'url(#arrow)';
        } else {
            return null;
        }
    })
    .attr({
        // returning null from these functions simply defaults to whatever the
        // .path class CSS props are doing
        'stroke-width': function(d, i) { return d == 'invisible' ? 10 : null },
        'stroke': function(d, i) { return d == 'invisible' ? 'transparent' : null }
    })

      

+6


source


How do you define link

here? I couldn't understand your solution, but I stuck with the same idea of ​​adding two lines (one visible and the other invisivle) to the parent element g

. I don't think this is too efficient because I have to call 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; }); 

 });

      



This works, but if anyone can suggest improvements that would be great, thanks!

+1


source







All Articles