Skip to content

Commit

Permalink
feat(core/Canvas): make truely multi-root aware
Browse files Browse the repository at this point in the history
This adds the capability to add multiple root elements to the Canvas. 
As a side-effect, it drops our leaky plane abstraction from the public 
API.

The following `Canvas` APIs make the magic happen:

* `Canvas#addRootElement` - add a root element without showing it

* `Canvas#removeRootElement` - remove a root element

* `Canvas#setRootElement` - set to a specific root element; for 
  backwards compatibility the add-during-set semantic is kept

* `Canvas#getRootElements` - returns a list of root elements that can 
  be switched to

Under the hood we continue to rely on root element specific layers.
However, we clean these layers up once the root element is removed.

Closes #600


BREAKING CHANGES:

* All plane related APIs got removed, use the newly introduced
  `(add|set)RootElement` APIs to accomplish the same thing.
* INTERNAL: Every root element gets it's own layer now; there is no 
  magic re-use of the BASE_LAYER happening anymore.
* `setRootElement` does not have single root semantics anymore. As such, 
  it does not blow up if a non-existing root is being passed; rather, it 
  adds that new root and shows it.
* `setRootElement` has on `override` semantics anymore. To replace the 
  current root, set a new root and remove the old one.
  • Loading branch information
nikku committed Dec 10, 2021
1 parent 195c8d0 commit b789c45
Show file tree
Hide file tree
Showing 8 changed files with 414 additions and 1,024 deletions.
414 changes: 150 additions & 264 deletions lib/core/Canvas.js

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions lib/features/overlays/Overlays.js
Original file line number Diff line number Diff line change
Expand Up @@ -457,12 +457,12 @@ Overlays.prototype._addOverlay = function(overlay) {
domClasses(htmlContainer).add('djs-overlay-' + overlay.type);
}

var plane = this._canvas.findPlane(element);
var activePlane = this._canvas.getActivePlane();
overlay.plane = plane;
if (plane !== activePlane) {
setVisible(htmlContainer, false);
}
var elementRoot = this._canvas.findRoot(element);
var activeRoot = this._canvas.getRootElement();

overlay.rootElement = elementRoot;

setVisible(htmlContainer, elementRoot === activeRoot);

overlay.htmlContainer = htmlContainer;

Expand All @@ -478,14 +478,14 @@ Overlays.prototype._addOverlay = function(overlay) {

Overlays.prototype._updateOverlayVisibilty = function(overlay, viewbox) {
var show = overlay.show,
plane = overlay.plane,
rootElement = overlay.rootElement,
minZoom = show && show.minZoom,
maxZoom = show && show.maxZoom,
htmlContainer = overlay.htmlContainer,
activePlane = this._canvas.getActivePlane(),
activeRootElement = this._canvas.getRootElement(),
visible = true;

if (plane !== activePlane) {
if (rootElement !== activeRootElement) {
visible = false;
} else if (show) {
if (
Expand Down Expand Up @@ -621,9 +621,9 @@ Overlays.prototype._init = function() {
});


eventBus.on('plane.set', function(e) {
eventBus.on('root.set', function(event) {
forEach(self._overlays, function(el) {
setVisible(el.htmlContainer, el.plane === e.plane);
setVisible(el.htmlContainer, el.rootElement === event.element);
});
});

Expand Down
25 changes: 17 additions & 8 deletions lib/features/planes/PlanesBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,38 @@ import inherits from 'inherits';

import CommandInterceptor from '../../command/CommandInterceptor';

export default function PlanesBehaviour(canvas, eventBus, injector) {

/**
* A modeling behavior that ensures we change the planes
* as we undo and redo commands.
*
* @param {Canvas} canvas
* @param {EventBus} eventBus
* @param {didi.Injector} injector
*/
export default function PlanesBehavior(canvas, eventBus, injector) {

injector.invoke(CommandInterceptor, this);

this.executed(function(event) {
var context = event.context;

if (context.plane) {
canvas.setActivePlane(context.plane);
if (context.rootElement) {
canvas.setRootElement(context.rootElement);
} else {
context.plane = canvas.getActivePlane();
context.rootElement = canvas.getRootElement();
}
});

this.revert(function(event) {
var context = event.context;

if (context.plane) {
canvas.setActivePlane(context.plane);
if (context.rootElement) {
canvas.setRootElement(context.rootElement);
}
});
}

inherits(PlanesBehaviour, CommandInterceptor);
inherits(PlanesBehavior, CommandInterceptor);

PlanesBehaviour.$inject = [ 'canvas', 'eventBus', 'injector'];
PlanesBehavior.$inject = [ 'canvas', 'eventBus', 'injector'];
8 changes: 5 additions & 3 deletions lib/features/selection/Selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function Selection(eventBus, canvas) {
self.deselect(element);
});

eventBus.on([ 'diagram.clear', 'plane.set' ], function(e) {
eventBus.on([ 'diagram.clear', 'root.set' ], function(e) {
self.select(null);
});
}
Expand Down Expand Up @@ -79,10 +79,12 @@ Selection.prototype.select = function(elements, add) {

var canvas = this._canvas;

var rootElement = canvas.getRootElement();

elements = elements.filter(function(element) {
var plane = canvas.findPlane(element);
var elementRoot = canvas.findRoot(element);

return plane === canvas.getActivePlane();
return rootElement === elementRoot;
});

// selection may be cleared by passing an empty array or null
Expand Down
Loading

0 comments on commit b789c45

Please sign in to comment.