passing mouse events to lower layers in svg

13,413 views
Skip to first unread message

Kyle Foreman

unread,
Feb 5, 2012, 8:54:28 AM2/5/12
to d3...@googlegroups.com
I'd like to have an svg path which is visible, but still have mouse events passed to other paths/shapes/etc underneath. So I'd like to have the mouse interaction treat the element as though its visibility is set to "hidden", but still actually render the element for display. Is this possible? 

For instance, imagine a map which is made up of a bunch of paths, each of which has its own mouseover attributes. Then you want to overlay a path which partially occludes portions of several of the map's paths. The only way I've been able to get the mouseover correct in that situation is to draw a transparent copy of the map on top of the overlay, but I'm hoping to find a way that doesn't require duplicate rendering.

Thanks
Kyle

Laurian Gridinoc

unread,
Feb 5, 2012, 9:00:15 AM2/5/12
to d3...@googlegroups.com
Test if the pointer-events CSS property will allow you this, it works with html dom elements, I guess it should work in svg too:

Laurian

Kyle Foreman

unread,
Feb 5, 2012, 9:08:11 AM2/5/12
to d3...@googlegroups.com
Works perfect, thanks Laurian!

EightBitBoy

unread,
Apr 23, 2012, 9:29:41 AM4/23/12
to d3...@googlegroups.com
Works like a charm!

Frank Guerino

unread,
Apr 23, 2012, 9:37:13 AM4/23/12
to d3...@googlegroups.com
Hi,

Can you please elaborate on what you mean by "lower layers"?  Is this a concept we should understand for D3?

Thanks,

Frank


On Mon, Apr 23, 2012 at 9:29 AM, EightBitBoy <haert...@gmail.com> wrote:
Works like a charm!

Kyle Foreman

unread,
Apr 23, 2012, 9:50:08 AM4/23/12
to d3...@googlegroups.com
I mean layering objects (paths, rectangles, text, etc) on top of each other on an svg.

Frank Guerino

unread,
Apr 23, 2012, 12:43:50 PM4/23/12
to d3...@googlegroups.com
Thanks.  Does anyone know if there are any best practices for how to do so and/or tutorials on how to change the scope of objects (for things like moving them forward or backward)?

Kyle Foreman

unread,
Apr 23, 2012, 1:22:12 PM4/23/12
to d3...@googlegroups.com
Well, SVG does not have a z-index that you can alter, so it's all based on element ordering in the DOM. So, the simplest way is adding elements to the DOM starting with the lowest (I.e. background) layer. E.g.:

svg = d3.select('body').append('svg')
svg.append('rect').attr('id', 'layer1')
svg.append('circle').attr('id', 'layer2')

Or if you need to do things more dynamically insert() allows you to add elements places other than the end. E.g.:

svg = d3.select('body').append('svg')
svg.append('circle').attr('id', 'layer2')
svg.insert('rect', '#layer2').attr('id', 'layer1')

Frank Guerino

unread,
Apr 23, 2012, 6:09:51 PM4/23/12
to d3...@googlegroups.com
Thanks Kyle.  Is there ever a need to "re-order" the scope of the elements and, if so, what's the best way to do so?
Message has been deleted

EightBitBoy

unread,
Apr 23, 2012, 6:22:44 PM4/23/12
to d3...@googlegroups.com
A good example is a simple line chart with a couple of graphs in it. Imagine you want to highlight a graph on mouseover by changing its color or something like that. What you will notice is that the graph is being intersected by other graphs which were drawn after the highlighted graph, so this one graph lies beneath the other ones. Those intersections do not look very good and a possibility to get rid of them is simply to delete the graph you want to highligh and draw it again. Now it is on top of all graphs and there are not visible intersections.

Kyle Foreman

unread,
Apr 23, 2012, 6:29:44 PM4/23/12
to d3...@googlegroups.com, d3...@googlegroups.com
Hi Frank,
What do you mean by 'scope' in this case? Sometimes I'll reorder the elements within the DOM (so that one is drawn on top of another), but that's not scope in the object-oriented programming sense. 



On Apr 23, 2012, at 11:09 PM, Frank Guerino <fgue...@gmail.com> wrote:

Thanks Kyle.  Is there ever a need to "re-order" the scope of the elements and, if so, what's the best way to do so?
On Mon, Apr 23, 2012 at 1:22 PM, Kyle Foreman <kylef...@gmail.com> wrote:
Well, SVG does not have a z-index that you can alter, so it's all based on element ordering in the DOM. So, the simplest way is adding elements to the DOM starting with the lowest (I.e. background) layer. E.g.:

svg = d3.select('body').append('svg')
svg.append('rect').attr('id', 'layer1')
svg.append('circle').attr('id', 'layer2')

Or if you need to do things more dynamically insert() allows you to add elements places other,  than the end. E.g.:

Frank Guerino

unread,
Apr 23, 2012, 6:35:45 PM4/23/12
to d3...@googlegroups.com
Hi,

This description definitely makes sense.  So is the best way to achieve the correction to delete and redraw at the highest level of drawing scope?  If so, how do you "delete," as I don't think I've seen any D3 delete methods?

Thanks,

Frank

Mike Bostock

unread,
Apr 23, 2012, 7:01:15 PM4/23/12
to d3...@googlegroups.com
Here's an easy way to move an element to the front of its siblings:

d3.selection.prototype.moveToFront = function() {
return this.each(function() {
this.parentNode.appendChild(this);
});
};

Then you can say:

d3.select("p").moveToFront().style("color", "red");

Mike

Kyle Foreman

unread,
Apr 23, 2012, 7:06:39 PM4/23/12
to d3...@googlegroups.com
Mike's way is the best for moving an element. To answer your question about "deleting" (which you don't need to do in Mike's example), you can use the .remove() method.

Frank Guerino

unread,
Apr 23, 2012, 7:51:39 PM4/23/12
to d3...@googlegroups.com
Thanks Kyle.

Frank Guerino

unread,
Apr 23, 2012, 7:54:20 PM4/23/12
to d3...@googlegroups.com
Interesting.  So, in the case where you have multiple graphs on a page, would it be a best practice to always move the graph you want to highlight or manipulate to the forefront, using this code?

Kyle Foreman

unread,
Apr 24, 2012, 3:41:50 AM4/24/12
to d3...@googlegroups.com
Only if they're overlapping and the highlighting would be obscured if left in its current position in the DOM. 


Frank Guerino

unread,
Apr 24, 2012, 7:17:23 AM4/24/12
to d3...@googlegroups.com
Good info.  Thanks to everyone.

Shreeram Kushwaha

unread,
Jan 7, 2013, 2:35:51 PM1/7/13
to d3...@googlegroups.com, mbos...@cs.stanford.edu
Suppose I have rectangle elements each inside a <g> tag. And on mouseover I want to bring the rectangle in FRONT. Then how I have to call the moveToFront().

Chris Viau

unread,
Jan 7, 2013, 8:17:14 PM1/7/13
to d3...@googlegroups.com
By trying it. Here is an example of the same move to front technique: http://tributary.io/inlet/4477544/

Shreeram Kushwaha

unread,
Jan 8, 2013, 7:00:00 AM1/8/13
to d3...@googlegroups.com
I am not talking about dragging. I am talking about this type of move to front.


Considering the code in above link, what if every circle is in a group tag <g></g>, then how to bring it to the front.
Edited Code(Putting every circle in a <g> tag)

--

(*Shreeram Kushwaha* )
Final Year, Undergraduate
Computer Science and Engineering
NIT Rourkela,
Orissa,India

Sajjad Anwar

unread,
Jan 8, 2013, 7:07:24 AM1/8/13
to d3...@googlegroups.com


On Jan 8, 2013 1:05 AM, "Shreeram Kushwaha" <ram90...@gmail.com> wrote:
>
> Suppose I have rectangle elements each inside a <g> tag. And on mouseover I want to bring the rectangle in FRONT. Then how I have to call the moveToFront().
>

Have you tried using the .on()?
May be d3.selectAll("rect").on("mouseover", moveToFront)

Cheers,
Sajjad

(handheld)

Chris Viau

unread,
Jan 8, 2013, 8:08:03 AM1/8/13
to d3...@googlegroups.com

On Jan 8, 2013 4:00 AM, "Shreeram Kushwaha" <ram90...@gmail.com> wrote:

I am not talking about dragging. I am talking about this type of move to front.

I know. My example is about moving to front while dragging. This is the move to front part: this.parentNode.appendChild(this); You just have to apply it to the g element like this:

http://enjalot.com/inlet/4483672/

Shreeram Kushwaha

unread,
Jan 9, 2013, 7:59:13 AM1/9/13
to d3...@googlegroups.com
Thanksssss a ton!!!!

Shreeram Kushwaha

unread,
Jan 10, 2013, 12:46:56 PM1/10/13
to d3...@googlegroups.com
How to use the value of translate from a group tag.
Suppose I have two rectangles 
 
<g class = "node" transform=translate(1,1)>
<rect width="20" height="30  fill="#aaa" stroke="#000"></rect>
</g>
<g class = "node" transform=translate(100,100)>
<rect width="20" height="30  fill="#aaa" stroke="#000"></rect>
</g>

I want to connect this two rectangles using a path, for which i need the value of translate of the two <g> tags which will act as the starting and the end point.
But how to extract the value of translate??/??

Chris Viau

unread,
Jan 10, 2013, 4:51:19 PM1/10/13
to d3...@googlegroups.com
One way is to use d3.transform: d3.transform(g.attr('transform')).translate

Shreeram Kushwaha

unread,
Jan 16, 2013, 1:44:00 PM1/16/13
to d3...@googlegroups.com
<g id ="a" class = "node" transform=translate(1,1)>

<rect width="20" height="30"  fill="#aaa" stroke="#000"></rect>
</g>

@Chris: 
Suppose I have mouse over event on the <g> tag, n on mouse over I call a function moverg().
please tell me how to access the width of the rectangle in the moverg() function.


Chris Viau

unread,
Jan 16, 2013, 3:11:57 PM1/16/13
to d3...@googlegroups.com
d3.select('g').on('mouseover',  moverg);

function moverg(d, i){ 
    var rectW = d3.select(this).select('rect').attr('width');
Reply all
Reply to author
Forward
0 new messages