Sooner or later when working with D3 you'll find yourself in a situation where you need to change how elements overlap each other. Most people (including myself) will first try setting the CSS property
z-index, but it turns out unfortunately SVG elements don't respect this property.
The order in which SVG elements are drawn determines the order in which they appear (an element drawn last will appear "over" any other elements it overlaps). The draw order of SVG elements follows a simple rule: elements that appear first are drawn first.
For example, take the following code snippet:
The resulting HTML looks something like:
<svg> <circle fill="green" r=50 cx=75 cy=100></circle> <rect fill="blue" width=80 height=80 x=85 y=60></rect> </svg>
The green circle appears before the blue square, so it is drawn first and appears below.
If we wanted to make the blue square appear on top, we could just reverse the order that the elements are created in the code. This works fine for this simple example, but when the code gets more complicated (and especially if we're working with abstractions we've written) we want to control draw order without having to change the order of our code.
To this end, we can use D3's
Which results in the HTML:
<svg> <rect fill="blue" width=80 height=80 x=85 y=60></rect> <circle fill="green" r=50 cx=75 cy=100></circle> </svg>
The green circle now appears after the blue square in the HTML, which means it appears on top of the square in the rendered SVG.
We can further illustrate this by calling
raise() on element mouseover (try hovering over the shapes below).
SVG groups are often used to organize elements in a chart. We can use groups as another way to control draw ordering. In the below example the green circle appears above the blue square despite the fact that is appears before the square in the code.
This is because we've added the circle to
group2 and the square to
group1 appears before
group2. Take a look at the HTML:
<svg> <g class="group1"> <rect fill="blue" width=80 height=80 x=85 y=60></rect> </g> <g class="group2"> <circle fill="green" r=50 cx=75 cy=100></circle> </g> </svg>
Now however we'll have a problem if we try to bind
raise() to element mouseover. Notice in the below example that hovering over the shapes does nothing:
This is because
raise only changes the order of the element within its parent group. In this example each group only has one element, making
raise a no-op.
To make this work we could bind
raise to the parent group mouseover, but this might be a little weird because the group doesn't necessarily have the same shape as the child element. A clean way to do it would be to have a function that raises the parent group on element mouseover. All we need to change then is our mouseover callback from
Hopefully these examples help clear up how SVG draw order works! Keeping these simple rules in mind can help you exert finer control over the details when working with complicated visualizations.