Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Grouping] Should group positions be always calculated from leaf element positions? #27444

Closed
w33ble opened this issue Dec 18, 2018 · 4 comments
Assignees
Labels
discuss Team:Presentation Presentation Team for Dashboard, Input Controls, and Canvas v6.7.0

Comments

@w33ble
Copy link
Contributor

w33ble commented Dec 18, 2018

Kibana version: 6.6+

Describe the bug:

As mentioned in #25854, the group position is a calculated value and should not be part of the redux state.

Screenshots (if relevant):

screenshot 2018-12-18 14 50 43

@w33ble w33ble added bug Fixes for quality problems that affect the customer experience Team:Presentation Presentation Team for Dashboard, Input Controls, and Canvas v6.6.0 labels Dec 18, 2018
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-canvas

@monfera
Copy link
Contributor

monfera commented Dec 19, 2018

This comment enlists the operations and their special cases to help us decide if omitting group positions is beneficial or even feasible. Please add a comment with the advantages of not storing group positions, or alternatives in the representation I might have overlooked. It got long but I'll talk about the layout engine on Jan 10 and would raise pain points and contentious issues to loop in everyone's insight, there's plenty of room for improvement across the board.

tl;dr to me it looks necessary, or at least now practical to persist group positions, besides of course the amount of work involved in eliminating them :-)

group-rotate

Original calculation of group position

It is true that group position (now represented as a tuple of location, size and angle) is initially derived from its parts, as the user merely selects the parts and groups them, without supplying further information.

Grouping with axis aligned bounding box (AABB)

The current grouping merely wraps the parts in an AABB which can be calculated from the leftmost, rightmost, topmost etc. vertices of the parts.

Group rotation

The initially axis aligned group can then be rotated, with the result that the global position of parts will be similarly impacted (angle will not be zero in general).

Rotated parts

Parts can be in arbitrary orientations: 0 degree, multiples of 90 degrees, and anything in general. Some groups will have parts with diverse orientations (eg. orienting objects around a circle), and some groups will have parts with uniform, but non-zero angled orientations (eg. shapes rotated 45 degrees).

Group position reconstruction if parts are not rotated and the group isn't rotated either

In this case, we can reestablish the group by simply forming the AABB around the parts. It'll work even if the group was repositioned or resized since its formation.

Future: grouping with oriented bounding box (OBB)

Currently, the sequence of

  • grouping a bunch of straight elements
  • rotating the group
  • ungrouping
  • reselecting the elements and regrouping

will yield a distinct group, which is axis aligned (relative to global ie. canvas projection) and whose parts are slanted relative to it.
In the future, we'd recognize the shared orientation of elements, eg. all of them 20 degrees, and form an OBB around them. This has the benefit that everything can be reoriented to 0 degrees, angular snapping becomes useful again (eg. snapping to 0 or 45 degrees), and edge snapping too. Ie. we'd step up from Google Slides level to Adobe Illustrator level. It's simple to implement and avoids the weird situation.

Group position reconstruction if some parts and/or the group are rotated

In this case, the position of the parts does not provide sufficient information to reconstruct the position of the group, see the gif on top (parts end up unrotated but the group is rotated). Even if no parts are rotated, the group could've been formed when they were rotated, and then the entire group was rotated so the net effect is restoration of 0 degree parts, but the group isn't AABB. It's a special case but users may create arbitrary arrangements.

Future: other affine transforms

We currently expose translation and rotation only (the resize is something else). The plan is to eventually have: scaling (we have working code but not included now), flip/mirror, shear, 3D transforms and maybe even perspective projection. Even now we can't reconstruct the group, and with these, a reconstructed group will be farther and farther away from the user intent.

Why do we care about how the group originated?

Watching the gif, does it matter to the user if we omit some aspects of grouping info and we always use eg. an AABB? These are supports for preserving grouping info:

  • it's how we remain faithful to user intent; users won't see their groups in changed orientations just because of a page reload
  • moreover, it's not just page reload: whenever a Redux action is issued, ie. the user does anything, the group boxes would magically and suddenly orient to AABB, even after a group rotation(*)
  • there can be multiple levels of groupings, each with distinct orientation, eventually scaling etc.
  • grouping is more than just a set of elements, we allow copy-pasting them and reorienting the new copies in arbitrary angles, so they have an element-nature
  • going forward with the templates, ie. their positioning will be just as important as that of elements now
  • from a user viewpoint and implementationally, there's strong overlap if not identity between elements and groups - for example, maybe in the future, a user can import an SVG as an element, and break it up to its constituent parts so they can be separately styled, moved, animated etc ie. what used to be an element is now a group, but nothing fundamentally changed
  • we had discussions about data driven positioning, not just tweening / rotating and visual gimmicks PowerPoint style, but think of a car race slide, showing the race course and stylized cars, with real time positioning of the cars along the track, or just a pipeline+layout driven novel chart implementation :-)

(*) While Google Sheets does preserve position info with(persistent) groups, their transient groups actually do this constant re-AABB. It feels unfinished, and the elements can't even be snap-oriented back to a sensible angle eg. 0 or 45 after the first rotation.
googleslides

OK assuming that preserving group position is important, is there another way?>

We could, for example, retain and retrace the steps that lead to the current constellation, but it may not be scaleable. To limit the O(n) complexity, sometimes the line would have to be drawn, ie. at that point the state would still need to reflect the cumulative effects of what impacted the position (in short, retain the position). Yet it's an interesting if tangential discussion on its own, because retaining last N user ops would have other benefits:

  • faster undo/redo
  • maybe fun effect for the user to timelapse play how they built their slide, what iterations they went through
  • even now, we sometimes decompose the localTransformMatrix to a translation component and a composite (now: rotation) component; better numerical accuracy and a wider array of affine transforms would benefit from storing historical steps
    So, historical operations may arrive in the future, but likely with limits in steps retained, so there'd still be a need for the collapsed position

What about integer pixel level accuracy?

Originally the layout transforms simply used floating points. A report from @rashidkpc showed that on some screens, font rendering is inferior if an element is not snapped to an integral pixel. So now we round. In the future it could/should get more intricate: once there's even a little bit of rotation (except maybe multiples of 90deg) is done, whether we snap to pixel or not won't matter. Ie. we'd snap to pixel only for axis aligned elements (with the generally working assumption that texts are axis aligned within the element).


In summary, the question is more about how we define grouping (is a group an object that has orientation etc. as in comparable software, or is it merely a set of its leaf elements, like maybe layers or tags in other software, and a visual bounding box is an incidental embellishment?), than about representing it in Redux, because sticking with the common meaning of grouping, it feels necessary to retain group position info.

@monfera monfera added discuss and removed bug Fixes for quality problems that affect the customer experience labels Dec 19, 2018
@monfera monfera changed the title [Grouping] Group position should not be stored in state [Grouping] Should group positions be always calculated from leaf element positions? Dec 19, 2018
@monfera monfera self-assigned this Dec 19, 2018
@w33ble
Copy link
Contributor Author

w33ble commented Dec 20, 2018

@monfera thanks for the description, and the images. After watching the first gif, reading what you wrote, and going back to that first gif, I think I get it.

If I follow this correctly, the bounding box is sized relative to the elements in the group, and that's the box that's being stored in state. If we don't save that information, we can't re-create the container if it's modified (as demonstrated by the second gif, repeated below here).

not so good

tl;dr While that value is calculated, it's not calculated every time, so we do need to store it.

to me it looks necessary, or at least now practical to persist group positions

I'd have to agree. @clintandrewhall you care to weigh in here?

@monfera
Copy link
Contributor

monfera commented Feb 12, 2019

Closing this discussion item, as the observation initiated a discussion but didn't lead to a change request. It can be reopened if there's more to add.

@monfera monfera closed this as completed Feb 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discuss Team:Presentation Presentation Team for Dashboard, Input Controls, and Canvas v6.7.0
Projects
None yet
Development

No branches or pull requests

4 participants