-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
58 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,54 @@ | ||
import { LayoutManager } from './LayoutManager'; | ||
import type { RegistrationContext, StrictLayoutContext } from './types'; | ||
import type { FabricObject } from '../shapes/Object/FabricObject'; | ||
import type { Group } from '../shapes/Group'; | ||
|
||
/** | ||
* Today the LayoutManager class also takes care of subscribing event handlers | ||
* to update the group layout when the group is interactive and a transform is applied | ||
* to a child object. | ||
* The ActiveSelection is never interactive, but it could contain obejcts from | ||
* The ActiveSelection is never interactive, but it could contain objects from | ||
* groups that are. | ||
* The standard LayoutManager would subscribe the children of the activeSelection to | ||
* perform layout changes to the activeselection itself, what we need instead is that | ||
* perform layout changes to the active selection itself, what we need instead is that | ||
* the transformation applied to the active selection will trigger changes to the | ||
* original group of the children ( the one referenced under the parent property ) | ||
* This subclass of the LayoutManager has a single duty to fill the gap of this difference. | ||
* This subclass of the LayoutManager has a single duty to fill the gap of this difference.` | ||
*/ | ||
export class ActiveSelectionLayoutManager extends LayoutManager { | ||
/** | ||
* Subscribe an object to transform events that will trigger a layout change on the parent | ||
* This is important only for interactive groups. | ||
* @param object | ||
* @param context | ||
*/ | ||
protected subscribe( | ||
object: FabricObject, | ||
subscribeTargets( | ||
context: RegistrationContext & Partial<StrictLayoutContext> | ||
) { | ||
const { parent, group: activeSelection } = object; | ||
if (!parent || !activeSelection || activeSelection === parent) { | ||
// nothing to do here | ||
return; | ||
} | ||
this.unsubscribe(object, context); | ||
const disposers = this.attachHandlers(activeSelection, { | ||
target: parent, | ||
targets: context.targets, | ||
): void { | ||
const activeSelection = context.target; | ||
const parents = context.targets.reduce((parents, target) => { | ||
target.parent && parents.add(target.parent); | ||
return parents; | ||
}, new Set<Group>()); | ||
parents.forEach((parent) => { | ||
parent.layoutManager.subscribeTargets({ | ||
target: parent, | ||
targets: [activeSelection], | ||
}); | ||
}); | ||
// the _subscriptions Map is using the parent as a key. | ||
// This will ensure that a single set of events is kept for each unique parent | ||
this._subscriptions.set(parent, disposers); | ||
} | ||
|
||
/** | ||
* unsubscribe object layout triggers | ||
* unsubscribe from parent only if all its children were deselected | ||
*/ | ||
protected unsubscribe( | ||
object: FabricObject, | ||
context?: RegistrationContext & Partial<StrictLayoutContext> | ||
) { | ||
const { parent } = object; | ||
if (parent) { | ||
(this._subscriptions.get(parent) || []).forEach((d) => d()); | ||
this._subscriptions.delete(parent); | ||
} | ||
unsubscribeTargets( | ||
context: RegistrationContext & Partial<StrictLayoutContext> | ||
): void { | ||
const activeSelection = context.target; | ||
const selectedObjects = activeSelection.getObjects(); | ||
const parents = context.targets.reduce((parents, target) => { | ||
target.parent && parents.add(target.parent); | ||
return parents; | ||
}, new Set<Group>()); | ||
parents.forEach((parent) => { | ||
!selectedObjects.some((object) => object.parent === parent) && | ||
parent.layoutManager.unsubscribeTargets({ | ||
target: parent, | ||
targets: [activeSelection], | ||
}); | ||
}); | ||
} | ||
} |