Skip to main content

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 since 1.14.7 we've also offered the Surface Drop Manager, which wraps the DropManager at a slightly higher level, offering very straightforward methods to:

  • drag and drop a node onto the canvas or onto another node
  • 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.

Creating a Surface Drop Manager#

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

import { createSurfaceManager } from "@jsplumbtoolkit/drop"
createSurfaceManager({    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> {    /**     * The surface to attach to.     */    surface:Surface    /**     * The element containing things that will be dragged.     */    source:Element    /**     * A CSS selector identifying children of `source` that are draggable     */    selector:string    /**     * Optional function to generate an initial payload from an element that has started to be dragged.     */    dataGenerator?:DataGeneratorFunction<T>    /**     * Optional function to determine the type of the data object being dragged from an element that has started to be dragged.     */    typeGenerator?:TypeGeneratorFunction<T>    /**     * Optional function to use to determine if the element being dragged represents a group. If you do not provide this,      * the default behaviour is to check for the presence of a `data-jtk-is-group` attribute on the element, with a value of `true`.     */    groupIdentifier?:GroupIdentifierFunction<T>
    /**     * If true, the surface will be instructed to magnetize after dropping a new element.     */    magnetize?:boolean
    /**     * Defaults to true. Allows items to be dropped onto edges in the canvas.     */    allowDropOnEdge?:boolean    /**     * Defaults to true. Allows items to be dropped onto groups in the canvas.     */    allowDropOnGroup?:boolean    /**     * Defaults to false. Allows items to be dropped onto nodes in the canvas. If this is true and an element is dropped onto a node, the     * result is the same as if the element has been dropped onto whitespace.     */    allowDropOnNode?:boolean    /**     * Defaults to true. Allows items to be dropped onto whitespace.     */    allowDropOnCanvas?:boolean
    /**     * Optional selector specifying what parts of the surface's canvas should be considered whitespace. If you're using a decorator,     * for instance, you might want to add a selector for that decorator's elements so that items can be dropped onto them.     */    canvasSelector?:string
    /**     * Defaults to false. By default this class will conform to any grid in place in the surface to which it is attached when dragging items around.     */    ignoreGrid?:boolean}
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.

Providing data for a dragged element#

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.

Specifying a dragged element's type#

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.

Distinguishing between a node and a group#

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.

Magnetizing the UI when dropping on an edge#

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.


Use the setEnabled(enabled:boolean) method on a SurfaceDropManager to enable/disable it.

Library Integrations#

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