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

V6: 🎉 Group Rewrite #7670

Closed
30 of 48 tasks
ShaMan123 opened this issue Feb 10, 2022 · 63 comments
Closed
30 of 48 tasks

V6: 🎉 Group Rewrite #7670

ShaMan123 opened this issue Feb 10, 2022 · 63 comments
Labels

Comments

@ShaMan123
Copy link
Contributor

ShaMan123 commented Feb 10, 2022

V6

Hi everyone,
fabric is moving forward!
We have 2 main goals for v6:

  1. js/ts migration which is covered here IMPORTANT: Migrating to modern javascript/typescript #7596
  2. Group rewrite 🎉

You can see #8316

Group Rewrite

This is a tracking issue for the group rewrite, read below for more detail including the current state of things and gist.
We aim to fix and support long desired features including:

  1. Nested selection - DONE
  2. Resizing and customized layout - DONE
  3. Transform and coordinate system (which is relative to the parent group) - DONE

Motivating Issues/Discussions

#7473 #7316 #6776 #7136 #7299 #7130 #7142 #7449 and anything with a group tag

How do you fit in?

  1. You can become an alpha tester (we aim to publish an alpha tag to npm regularly).
    IMPORTANT NOTICE: all changes made to the v6 branch are experimental and can be removed or changed without notice and without proper support (including supported features from v5). fabric might change drastically between commits. Meaning if you want in - it's on you.

You can join the effort by contributing

This description is updated continuously with relevant information
You don't need to scroll and read endless comments (unless you are a maintainer :))


Current State

Fixed logic across fabric for nested objects to be selectable.
Group has been completely rewritten and Layer has been introduced. As part of the rewrite group is now a layout engine, you can use it to customize layout of objects.
In general the rewrite allows any object to be selectable and interactive if it is referenced in the _objects array of it's parent and it references it's parent via the group property. If you build custom objects with nesting this is what you are looking for.

Usage

It is advised to use set on group/objects from now on (until #7596 is done, then it might change due to setters)
Changing subTargetCheck or interactive enables/disables crucial functionality so for these props it is not an advice but a MUST.

new fabric.Group(objects, {
  subTargetCheck: true,
  interactive: true   //  enables selecting subtargets
});

Progress

Experimental

Triggering Layout

#9148 extracts layout management to a standalone class

triggerLayout forces a group to recalculate its bounding box and reposition its objects.
You can define a layout strategy and assign it to the layout manager.
Read the code, it has comments explaining stuff and types that make it clear what you need to return from the method.
Look at the modified trigger, it is possible adding more triggers.
However I will promote an overall solution.
#7882 is a POC, follow the progress trigger

BREAKING

  • all awkward methods such as addWithUpdate are removed including toGroup/toActiveSelection
  • renamed object stacking methods on canvas (e.g. moveTo -> moveObjectTo)
  • strict object tree - EXTREMELY BREAKING because it steals under the radar
    • an object can have only one parent
    • no need to call remove before adding to another group, fabric handles it internally
    • no need (and discouraged) to use awkward active selection code for removing an object
    • canvas methods still need to enforce a strict check
  • if you hacked group prior to the rewrite you will probably need to rewrite your logic

Pitfalls

All object origin methods (e.g. translateToOriginPoint) are relative methods.
You should use them ONLY in the correct plane and with points that belong to the relative plane.
IMO it makes them worthless.
#8767 changes that.

BUGS

If you encounter bugs related to group or if you have a feature request please submit a relevant ticket.
Notice that bug reports of versions below v6 will be completely disregarded and closed. This was hard work, put effort into your repro so it is in v6.

Working Examples

Using v6! stale branch
- CodeSandbox or JSFiddle
- Layer or in JSFiddle

To Do

Look

Video is running in original speed
tiger

Cutting Edge

The blue circles are rendered by a textbox and because of the rewrite with a few lines of code I got this working
Pay no attention to caching of course

This is EXTREMELY exciting because it means that anyone could create custom objects subclassing whatever object they need and have nested selection work out of the box!

ezgif com-gif-maker (13)

@ShaMan123 ShaMan123 pinned this issue Feb 10, 2022
@ShaMan123 ShaMan123 changed the title V6: Group Rewrite V6: 🎉 Group Rewrite Feb 10, 2022
@ShaMan123 ShaMan123 changed the title V6: 🎉 Group Rewrite V6 🎉 Group Rewrite Feb 10, 2022
@ShaMan123 ShaMan123 changed the title V6 🎉 Group Rewrite V6: 🎉 Group Rewrite Feb 10, 2022
@ShaMan123 ShaMan123 linked a pull request Mar 6, 2022 that will close this issue
21 tasks
@stale stale bot added the stale Issue marked as stale by the stale bot label Mar 27, 2022
@ShaMan123 ShaMan123 removed the stale Issue marked as stale by the stale bot label Mar 28, 2022
@fabricjs fabricjs deleted a comment from stale bot Apr 3, 2022
@ShaMan123
Copy link
Contributor Author

First milestone #7858 🤟

@ShaMan123
Copy link
Contributor Author

ShaMan123 commented Apr 7, 2022

First milestone is merged!! 🥳🥳
Meaning that fabric.Group is now the new group.

@ShaMan123
Copy link
Contributor Author

updated description

@ShaMan123
Copy link
Contributor Author

ShaMan123 commented Apr 26, 2022

@ShaMan123
Copy link
Contributor Author

ShaMan123 commented Apr 30, 2022

Second milestone merged!
Most of the functionalities are now available in master!
Usage:

new fabric.Group(objects, {
  subTargetCheck: true,
  interactive: true   //  enables selecting subtargets
})

@ShaMan123
Copy link
Contributor Author

4th milestone merged!

@ShaMan123
Copy link
Contributor Author

ShaMan123 commented May 25, 2022

@asturur I think we can drop coords in favor of getCenterPoint + _getTransformedDimensions
What do you think?

@stale stale bot added the stale Issue marked as stale by the stale bot label Jun 12, 2022
@ShaMan123 ShaMan123 removed the stale Issue marked as stale by the stale bot label Jun 13, 2022
@fabricjs fabricjs deleted a comment from stale bot Jun 13, 2022
@ShaMan123 ShaMan123 added the v6 label Jun 13, 2022
@ShaMan123
Copy link
Contributor Author

Group layout now respects origin, skewing and angle.
Stay tuned for more!

@ShaMan123
Copy link
Contributor Author

Group is now in beta!

@ShaMan123
Copy link
Contributor Author

ShaMan123 commented Jun 16, 2022

Next Up

  • Active Selection fixes
  • Layer

@abdussami-tayyab
Copy link

Thanks @ShaMan123 , it is working for me with objectCaching: false on the Group object.

Sorry to pour here with questions, I realise you guys must be super-busy, but I also feel bringing up problems right now is best for all of us.
A question I have is, let's say there's a Group of Rect and a Circle, and these 2 conditions are true:

  1. Rect object is bigger than the Circle
  2. Circle is inside the Rect

Is it possible to select the Group? I am unable to do that, because the Rect covers the whole Group and when I select Rect, it makes the Rect interactive (and movable).

Are there a couple of event listeners that might help selecting the Group if Rect.size === Group.size?

@ShaMan123
Copy link
Contributor Author

Rect.selectable = false?

@abdussami-tayyab
Copy link

It will make the rect unselectable/non-interactive which is also something I don't want. I just tried this use-case in Canva, and in Canva if I create a rectangle of 50x50 and place a circle of 30x30 inside it, then group both of them. Then when I select the group to move, the whole group moves and I am not able to move the rectangle or circle although I can change their attributes.

I wonder what event listeners we can use, for example if a user moves a group without Shift key pressed, we deal with the group but if Shift key is pressed, we can select the individual object inside the group. If this is an advanced topic for us, we can have a look at it later, but important to at least think about it because we are sure this is not an unusual case.

@ShaMan123
Copy link
Contributor Author

Did you try toggling the selectable prop in correlation to the shift key?
You can also try to fiddle with onSelect, onDeselect and the related events

@abdussami-tayyab
Copy link

abdussami-tayyab commented May 19, 2023 via email

@abdussami-tayyab
Copy link

@ShaMan123 I tried setting the selectable attribute of objects inside a group, the problem with that now is that moving the group now does nothing because the underlying object which has selectable: false.

Is there any way we can set interactive only on IText objects and not on any other shape?

@abdussami-tayyab
Copy link

@asturur can you help with my comment above? If I can make some objects in a group interactive and some not, that would be golden for the project I'm working on. If this is not in the plan for now, that would work as well if I can get to know. Thanks for this great package!

cc: @ShaMan123

@ShaMan123
Copy link
Contributor Author

Open a dedicated discussion/issue
Provide a reproduction

@asturur
Copy link
Member

asturur commented May 29, 2023

@abdussami-tayyab link the open issue when you open it.
The interactive group feature wasn't planned with all those customization in mind, so some of them needs to be evaluated, thought, and built from scratch.

@abdussami-tayyab
Copy link

@asturur do we have a boilerplate JSFiddle or CodeSandbox that I can use to replicate my issue?
Sorry about commenting here, I understand it breaks the purpose of this thread. I'll delete once you tell me how I can add code to JSFiddle or CodeSandbox (or any other tool).

Thanks!

@StringKe
Copy link

Any update on the implementation of this DEMO in V6?

@ShaMan123
Copy link
Contributor Author

ShaMan123 commented Nov 27, 2023

Are you referring to toGroup/toActiveSelection?

toActiveSelection

canvas.getActiveSelection().add(...group.removeAll())
//or
canvas.setActiveObject(new ActiveSelection(group.removeAll())
// remove group

toGroup

new Group(canvas.getActiveObjects())

@StringKe
Copy link

StringKe commented Nov 27, 2023

Are you referring to toGroup/toActiveSelection?

toActiveSelection

canvas.getActiveSelection().add(...group.removeAll())
//or
canvas.setActiveObject(new ActiveSelection(group.removeAll())
// remove group

toGroup

new Group(canvas.getActiveObjects())

Thanks, your code is very clean, I used a lot of code to achieve a similar result.

@ShaMan123
Copy link
Contributor Author

Thanks, your code is very clean, I used a lot of code to achieve a similar result.

Yes, v6 is a major step forward for the repo and the group rewrite especially

@StringKe

This comment was marked as off-topic.

@abdussami-tayyab

This comment was marked as off-topic.

@StringKe

This comment was marked as off-topic.

@ShaMan123
Copy link
Contributor Author

ShaMan123 commented Nov 27, 2023

Guys I am hiding your last off topic comments
Be strict about the discussions and open a dedicated ticket or else everything becomes spam.
We have starter apps, read the README/CONTRIBUTING guides.

@ShaMan123
Copy link
Contributor Author

Group rewrite has completed a while back and the LayoutManager has been introduced.

#8034 hasn't been merged so look out when adding objects to a group that belonged to a canvas. Call Canvas#remove to be sure until that is fixed. The rest of the add operations should manage removing objects from previous group for you.

The parent ref has been introduced to complement the existing group ref.
Basically the group ref is what defines the plane the object is in while the parent ref describe where the object is in the object tree.
When selected as part of an ActiveSelection, a nested object (one under some group n levels) will have its group ref set to the active selection and its parent ref set to the group it came from.
When not selected both refs point to the group.
This is needed for a couple of things including the ability to move the object back to its parent after deselected and rendering it in the case of preserveObjectStacking.

There are pending issues with the transform system and the caching system that will cause bugs when using groups such as:
#8743 This bug is caused because fabric uses decomposed values instead of pure matrix multiplication.
Look out for bugs coming from a combination of shadows and caching/clipPaths.

I suggest anyone needing nested objects and groups to familiarize with sendPointToPlane, sendVectorToPlane and sendObjectToPlane. They do the heavy up lifting of the linear algebra for you. Once you understand how they work it becomes easy to do complex linear algebra in your code.
Be mindful of the plane you are working in, whether it is the viewport, the scene, the parent plane, the object plane, some other internal object plane (fabric defines many of these but none are easy to grasp, such as pathOffset) or weirder ones.
Doing so will save dev hours and make your logic robust for nesting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants