UI / Surface Drop Manager

Surface Drop Manager

A common use case in the sorts of applications for which the Toolkit is useful is the requirement to be able to drag and drop new nodes/groups onto the workspace. From in version 1.13.1 we introduced a more flexible approach to achieving the same goal - the Drop Manager, and in 1.14.7 we've introduced the Surface Drop Manager, which wraps the Drop Manager at a slightly higher level, offering very straightforward methods to:

  • drag and drop a node onto the canvas
  • drag and drop a group onto the canvas
  • drag and drop a node onto a group on the canvas
  • drag and drop a node or group onto an edge on the canvas, automatically splitting the given edge and inserting the new node/group between the original source and target.

These, whilst all achievable with the Drop Manager, required a certain amount of lower level code to accomplish, and we saw enough different people implement these functionalities that we thought it made sense to wrap them in something we distribute with the Toolkit.

At the bare minimum, you need to provide these parameters when you create an instance of the Surface Drop Manager:

new SurfaceDropManager({
    source:nodePalette,
    selector:"[data-node-type]",
    surface:renderer,
    dataGenerator: function (el) {
        return {
            name:el.getAttribute("data-node-type"),
            type:el.getAttribute("data-node-type")
        };
    }
});
  • source The element containing other elements that are draggable
  • selector a CSS3 selector identifying elements within source that are draggable
  • surface The Surface to attach to
  • dataGenerator a function that can return an appropriate data object representing some element that is being dragged.

The full set of options available are:

export interface SurfaceDropManagerOptions<T> {
    surface:Surface;
    source:HTMLElement;
    selector:string;
    dataGenerator?:DataGeneratorFunction<T>;
    typeGenerator?:TypeGeneratorFunction<T>;
    groupIdentifier?:GroupIdentifierFunction<T>;

    magnetize?:boolean;

    allowDropOnEdge?:boolean;
    allowDropOnGroup?:boolean;
    allowDropOnCanvas?:boolean;
    
    canvasSelector?:string;
}

export type DataGeneratorFunction<T> = (el:HTMLElement) => T;
export type TypeGeneratorFunction<T> = (d:T) => string;
export type GroupIdentifierFunction<T> = (d:T, el:HTMLElement) => boolean;

By default, the Surface Drop Manager is configured to allow nodes/groups to be dropped onto the canvas or an existing edge, and for nodes to be dropped on groups. You can control this via the appropriate allowDropOn*** flags.

canvasSelector is an optional value you can supply to assist the Surface Drop Manager in figuring out what parts of your UI constitute background. This is discussed in the underlying drop manager documentation.


The dataGenerator function is used to get a suitable piece of backing data for some element that is being dragged. In the example above (which comes from the Database Visualiser demo), we provide a data object with name and type properties. The default mechanism used by the Toolkit for determining the type of some object is to test the type member. Providing type as we have here allows the Toolkit to determine which template to use to render the node, how it will behave, etc.


As mentioned, the Toolkit's default mechanism for determining the type of some object is to look at its type member. If you wish, you can provide your own typeGenerator function for the Surface Drop Manager to use.


By default, the Toolkit will look for a jtk-is-group attribute on a dragged element. If the value of this attribute is "true", the Toolkit will assume the element represents a group. You can provide your own groupIdentifier if you wish; the signature is as shown above.


By default, the Toolkit will "magnetize" the UI when a node or group is inserted between two existing nodes/groups. You can switch this off by setting magnetize:false.


A wrapper for the Surface Drop Manager is available for the Angular, Vue and React integrations.