D3: How to handle zooming and tooltips in a single chart?

删除回忆录丶 提交于 2019-12-05 06:10:53

I was following Mike Bostock's example, and like you placing a rect across my whole chart and then calling the zoom behaviour on that, and like you found that it was consuming all the pointer events.

I found an example here that seemed to be achieving what I wanted, and I found that if I scrap the rect and just call the zoom behaviour on the svg element directly, I still get pointer events for the child elements.

I'm a noob here, I don't really understand why this works. I also guess this might have its own ramifications e.g. I guess this stops you limiting the area of your graphic in which mouse events cause a zoom. You may notice that the example I linked creates a sub-svg; I don't know, but perhaps this is to solve that problem.

You can probably put the mouseevent on the same rectangle you are using for detecting your zoom. Hard to say for sure without a code sample, but I would expect you can do something along these lines:

 svg.select("rect.overlay")
     .on("mouseover.tooltip", function() { tooltip.style("display", null); })
     .on("mouseout.tooltip", function() { tooltip.style("display", "none"); })
     .on("mousemove.tooltip", mousemoveFunc);

Adding the ".tooltip" to the event adds a namespace to the event, so if you end up having any collision with your zoom listeners, you can add a namespace to them too.

In your css put the style ponter-events:none for your zooming rectangles. That way the cursor events will be sensed by the elements blow.

I know this is way too late, but I've just figured out a workaround. For me the crucial thing is order of adding bits to the svg.

svg1.append("rect")//put the rectangle for zoom events on the bottom
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.call(d3.zoom()
    .scaleExtent([0.5, 10])
    .on("zoom", zoomed));

var g = svg1.append("g"); //add g element for visualisation (above the rectangle).

function zoomed() { //zoom around the g's (g has to be before this, but after the rectangle)
g.attr("transform", d3.event.transform)  
}

Then a little bit later on add my force elements to the g

 var nodes = g.append("g")
    .attr("class", "nodes")
    .selectAll("circles")
    .attr('id', function(d) {
        return d.n_id
    })

etc. Slight issue here is I can't actually zoom with my mouse over the circles, but I have loads of white space. I'm going to try and allow propagation of zoom events, or call zoom events from the circles

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!