glsp
glsp copied to clipboard
Ensure rendering control shapes on top ("z-index")
SVG uses a "painters model" to determine the z-index of elements. That is, elements that are below in the document will be drawn on top of the already drawn elements (painting over already painted top down). Now in Sprotty and GLSP, we often use additional SVG elements for rendering control shapes (e.g. resize handles, issue markers) and add those as part of the elements they concern. Now, however, elements that are below these other elements that contain control shapes will have a higher z-index, which leads to weird cases as a user would expect those control shapes and visual feedback of e.g. currently moved elements, to be always on top.
Examples:
Due to the painters model, setting a z-index via CSS won't work.
We either need to ensure adding those elements at the end of the document, which would require to move them out of the element they are concerned with. This would add overhead, however, as we'd then programmatically need to move the "control shapes" along with their "main element".
Alternatively, we could render them in a separate SVG element (ie an actual HTML <svg>) on top -- sort of like a feedback/control layer. This <svg> could get a higher z-index and thus is ensured to be rendered on top. However, we would need to sync viewport changes of the diagram <svg> to ensure the feedback/control layer elements stay on the right position.
WDYT?
After considering this a bit, I think the simplest way is to introduce a new SModelExtension
named something like AttachableDecoration
which has the property decoratedElement: SModelElement
. As they reference the element to be decorated, they don't need to be added as children of the decorated element but can be placed as children of the SModelRoot
and thereby control their z-index by putting them as last children.
To place them relative to the decorated elements, we could just add an IVNodePostprocessor
that -- if the element is an AttachableDecoration
-- fetches its decorated element, retrieves the decorated element's diagram position and adds a transform the VNode
of the decoration, similar to the Sprotty DecorationPlacer
. This way the decoration is moved alongside and placed relative to the decorated element.
This should work fine for resize handles and issue markers.
There is two more case, I can think of, which is (1) feedback edges and (2) moving elements.
- Feedback edges don't have a z-index problem, because the feedback edges are new elements that are added to the root, which makes them appear always on top. The same is true for the marquee rectangle. Both have no z-index problem.
- Moved elements however can have a z-index problem, because they are just moved, so if they happen to be a child of a container and moved to another container that has a higher z-index as the previous container, the moved element is rendered below the new container. I wonder whether we shouldn't follow the same approach as with edges for element moves: i.e. just adding a feedback element as a child of the root (and set the original moved element as invisible). Code-wise something similar has been done here: https://www.eclipse.org/glsp/gallery/#constrainedlayout (creating a ghost element that is completely detached from the GModel structure, added as the last direct child of the root thus always on top).
WDYT @tortmayr @martin-fleck-at @CamilleLetavernier?
If Feedback/Handle visuals are part of the standard tree (Although closer to the root element, rather than nested inside of the tree structure), do we have a risk of elements "fighting" for z-index?
IIRC, Sprotty automatically reorders elements inside of the root (Especially, selected elements are placed on top, by moving them also to the end of their parent element - which may be the ModelRoot, I think). Could this conflict with Feedback z-index?
Yeah, you are right. Sprotty indeed moves the selected child to the end of the parent's containment list on selection. That could indeed conflict with my proposed approach. Within one "layer" we'll always have this problem. But I guess at least across "layers" (the control shapes / feedback layer vs the normal layer), we should at least ensure that the z-index is as expected.
https://github.com/eclipse/sprotty/issues/307