Reputation: 203
I have a visualization that is essentially a series of stacked bar charts, each of which contains several panels. For example, here are three such bar charts, each with four panels.
I have managed to implement pan/zoom functionality that is coordinated across the charts. This is what it looks like if I zoom into the third panel from the last image, for example. The zoom behavior is called from an invisible rectangle that is placed over each chart.
My problem is that I want to enable tooltip functionality based on the location of the user's cursor within a plot. Since the zoom-rectangles are placed on top of the charts, however, no mouse events are registered for any SVG elements in the actual charts themselves.
Des anyone know a way around this?
Upvotes: 10
Views: 4082
Reputation: 323
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
Upvotes: 0
Reputation: 2401
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.
Upvotes: 7
Reputation: 19
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.
Upvotes: 1
Reputation: 498
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.
Upvotes: 0