Managing Layout Bubbling in a canvas

Context
We’re developing a proof of concept for a canvas layout system that includes multiple nested layers (areas, domains, subdomains, and activities) that need to be displayed on a fixed-size canvas (to ensure compatibility with printing).

Current Setup:

The canvas is structured as follows:

  • Areas (Group): Defined by specific location, width, and height values and serve as containers for child elements. These areas are created as “Auto” Groups with placeholders for child elements.
  • Domains (Group): Each area contains domains, which also act as groups with placeholders for their child elements (subdomains and activities).
  • Subdomains (Group): Subdomains contain activities in a placeholder.
  • Activities (Node): Lowest level of element.

So far, this layout lets us establish a hierarchy where each level is nested within a larger group, with placeholders keeping each level visually organized.

The Challenge:

Our goal is to enable users to move activities around and save their positions, so that the canvas can be saved and redrawn consistently later. However, we’re encountering an issue where moving an activity triggers layout re-validation up through all parent layers.

This causes layout changes at higher levels, which results in the entire layout “bubbling up” and adjusting due to placeholder revalidation. While it makes sense for a parent to check if a child is still within its placeholder, it feels like this behavior is too restrictive, and we’re essentially fighting against it.

Desired Solution:

We want to achieve a setup where:

  1. Fixed Areas
    The layout starts with fixed areas, rendering each domain within a structured grid. Users can then adjust the size and position of domains, with placeholders that automatically scale with the parent.

  2. Independent Child Movement in Placeholder
    Moving activities within a domain shouldn’t force a layout change in the parent. Instead, after releasing the mouse, the activity should snap back if it’s outside the boundaries, without altering the layout of the domain or any parent group.

Question for the Forum

Is there a way to disable this “bubbling up” of layout validation for parent elements when moving child activities? Or, is there a method to keep parent placeholders fixed, while allowing child elements to move freely within their designated area?

Any insights or suggestions would be greatly appreciated!

Yes, you can control when automatic layouts are invalidated. Read Layouts | GoJS

Basically you can either set Layout.isOngoing to false, or if you still want some automatic layouts to happen, you can set Part.layoutConditions on the Nodes.

The other thing to consider is whether you want the size of a group to be determined by the area covered by its members. If you do, it’s natural to use a Placeholder in your Group template; if you don’t, don’t use a Placeholder.

Normally if there is a Placeholder in a Group it will automatically increase (or decrease) in area as the user drags its member Nodes. If you don’t want that behavior, you can set Group.computesBoundsAfterDrag to true.

To keep member nodes within a given area, you can either customize the DraggingTool behavior by setting Part.dragComputation, Part | GoJS API. That documentation includes an example function that keeps nodes within the viewport, but the Swim Lanes sample, Collapsible, Resizable, Re-orderable Swim Lanes for Flow Diagram | GoJS Diagramming Library, uses a dragComputation named stayInGroup. You may need to customize it for your particular requirements.

Alternatively, instead of setting Part.dragComputation, you could implement a “SelectionMoved” DiagramEvent listener that checked each moved Node to see whether they were dropped where you don’t want them to be. If that is the case you could move them back.