Skip to content
This repository has been archived by the owner on May 8, 2022. It is now read-only.
Simon Porritt edited this page Mar 11, 2017 · 12 revisions

Katavorio is a lightweight drag/drop handler, supporting containment, multiple element drag, custom css classes, drop filters, drag filters, drag clones, drag handles, constraining movement to a grid, and zooming.

Currently, Katavorio does not work "out of the box" - it was developed as part of jsPlumb 1.6.0, to support a "no dependency" version (all previous versions of jsPlumb required either jQuery, MooTools or YUI, to provide a bunch of functionality such as CSS manipulation, getting/setting element positions, supporting drag/drop etc). So, rather than re-write simple methods such as addClass, removeClass, getPosition etc, Katavorio expects those methods to be provided in the constructor's options object.

All is not lost, though, as this project also contains DefaultKatavorioHelper - the set of missing methods.

Usage

First you need to instantiate an instance of Katavorio:

var k = new Katavorio({  options });

CSS

Katavorio attaches various CSS classes to elements, both at initialisation time, and on a few events during the drag/drop lifecycle:

class default> description
draggable katavorio-draggable Draggable elements
droppable katavorio-droppable droppable elements
drag katavorio-drag elements currently being dragged
selected katavorio-drag-selected elements in current drag selection
active katavorio-drag-active droppables that are targets of a currently dragged element
hover katavorio-drag-hover droppables over which a matching drag element is hovering
noSelect katavorio-drag-no-select added to the body to provide a hook to suppress text selection

You can override any or all of these events by providing a JS object with the key css to the Katavorio constructor:

var k = new Katavorio({
    ...,
    css:{
        drag:"CurrentlyBeingDraggedClass",
        hover:"SomeoneIsHoveringOnMeClass"
    },
    ...
});
Overridding Drag CSS on a per-element basis

You can also override the class that is set on an element currently being dragged when you make the call to draggable:

var k = new Katavorio( ...options... );
k.draggable(someElement, {
    dragClass:"CustomDragClass"
});
Overridding Drop CSS on a per-element basis

Similiarly, you can override the hover/active classes that are set on a droppable element:

var k = new Katavorio( ...options... );
k.droppable(someElement, {
    activeClass:"CustomActiveClass",
    hoverClass:"CustomHoverClass AndAnotherClass Etc"
});

Note that in all cases, Katavorio supports multiple CSS classes, via a whitespace-separated string.

Drag and Drop Scope

Katavorio supports multiple scopes for each Drag and Drop. By default, a Katavorio instance will set a single scope on each Drag and Drop. The default value for this is katavorio-drag-scope. You can override it on a per-instance level by providing a scope in the constructor params:

var k = new Katavorio({
  ...
  scope:"MyScope",
  ...
});

Parent Constrain

To constrain the movement of some draggable element to its parent, set constrain:true in the draggable call:

var k = new Katavorio({...options...});
k.draggable(someElement, {
    constrain:true
});

Grid Movement

To constrain the allowed placements of a draggable to a grid, provide a grid in the draggable call:

var k = new Katavorio({...options...});
k.draggable(someElement, {
   grid:[30, 30]
});

AdHoc Grid Snap

You can snap all draggables to a grid at any point in time by calling the snapToGrid method. If you provided a grid for each draggable then by default the values from that grid will be used; alternatively you can override the values and provide your own. Failing both of these cases, defaults of 50px in each axis will be used:

Using the Katavorio instance configured above, this command will cause the elements to snap to a 30x30 grid:

k.snapToGrid();

This will override the default grid and specify 10x10:

k.snapToGrid(10, 10);

Drag with a clone

If you want to drag a clone of your element, set clone:true on the draggable call:

var k = new Katavorio({...options...});
k.draggable(someElement, {
   clone:true
});

Filtering by element

You can provide a filter parameter to the draggable method - a string selector defining an element or set of elements from which dragging is not enabled:

var k = new Katavorio({ ...options... });
k.draggable(someElement, {
  filter:"button"
});

Here we have told Katavorio to make someElement draggable, but not to start a drag if the mouse is on any child elements that are buttons.

Valid values for the filter argument are any valid CSS selectors.

Filter Exclude vs Include

By default, Katavorio uses a supplied filter to exclude elements from initiating a drag. However, there are limitations with CSS3 filters, for instance the :not selector only supports what are called "simple selectors", meaning they contain a single term, such as :not(.someClass) or :not(button). :not(.someClass > div), though, contains more than one term and isn't supported.

To cater for limitations such as this, you can set filterExclude:false on your draggable call, and then the supplied filter is assumed to refer to elements that should initiate a drag. An example:

k.draggable(someElement, {
  filter:":not(.someClass > div)"
};

The above will not work, per the explanation given in the preceding paragraph. The intention is to tell Katavorio that if the mouse is not down on an immediate child of an element having class someClass, then drag should not begin. Using filterExclude:false we can rewrite this as follows:

k.draggable(someElement, {
  filter:".someClass > div",
  filterExclude:false
};

Drag Handles

Katavorio also lets you provide a handle parameter, which is treated as a filter with filterExclude:false. So, this example from above:

k.draggable(someElement, {
  filter:".someClass > div",
  filterExclude:false
};

can be achieved like this:

k.draggable(someElement, {
  handle:".someClass > div"
};

Note: You cannot combine filter and handle. If handle is provided then it will be used and filter will be ignored. Also, remember that providing handle means filterExclude is implicitly set to false.

Right mouse button

By default, Katavorio does not respond to the right mouse button. You can override this behaviour by providing a rightButtonCanDrag parameter to the Katavorio constructor:

var k = new Katavorio({
  rightButtonCanDrag:true
});

Note that due to the right mouse button generally being assigned to the context menu in browsers, you will need to attach some event handler that independently prevents the default behaviour of the right click event.

Consuming filtered events

If you set a filter, you can also tell Katavorio to consume any events that were filtered (otherwise they bubble up through the DOM).

var k = new Katavorio({ ...options... });
k.draggable(someElement, {
  filter:"button",
  consumeFilteredEvents:true
});

This causes Katavorio to call preventDefault() and stopPropagation() on events that were filtered (or to set the event's returnValue to false in IE < 9).

Zoom

Katavorio takes zoom into account when dragging elements. This is not handled by attempting to infer what, if any, CSS3 transform is affecting some dragged object. Rather, you handle this manually by calling the setZoom method to tell Katavorio that there is a scale transform in effect.

setZoom takes decimal values where 1.0 means 100%.

Ignoring Zoom

It may be the case that you wish to configure some element to be draggable and have it not be subject to the current zoom transformation. To do this, you can set ignoreZoom:true on the draggable call:

var k = new Katavorio({ ...options... });
...
...
k.draggable(someElement, {
  filter:"button",
  ignoreZoom:true
});

Lifecycle Events

Draggables

Katavorio publishes events at three times during the drag lifecycle. You bind to them in the draggable call:

var k = new Katavorio({ options });
k.draggable(someElement, {
  start:function(params) {
    
  },
  drag:function(params) {
    
  },
  stop:function(params) {
    
  }
})

The contents of params are as follows:

  • drag The associated Drag instance
  • e The associated MouseEvent
  • el The element that is being dragged.
  • pos [x,y] location of the element. Only supplied by the drag event.
### Drop Precedence

Katavorio allows for drops to occur on multiple elements: any element whose bounding box contains the location of the mouseup event is a candidate. A given Drop can claim the event for itself by returning true from the drop callback:

katavorioInstance.droppable(someElement, {
  drop:function() {
     // do some codes
     return true;
  }
});

This is only guaranteed to work, though, if some other Drop does not first claim the event. The order of the list of candidate droppables corresponds with the order in which the related elements were made droppable, so you can control it that way, if you're up for a bit of admin. Another thing you can do is to give Katavorio a hint on how to order the candidate droppables when a drop event occurs. Consider this HTML:

<div id="parent">
  <h1>Foo</h1>
  <div id="child"> ... </div>
</div>

We're going to make both of these elements into droppables. If a drop event occurs over the #child element, we always want the #child droppable to get the event, never the parent. But of course an event that occurs over the child also occurs over the parent. As mentioned above, we could control this by configuring the child as a droppable before the parent. But in the real world it isn't always possible to control things like that. So in this case (and showing parent being configured first), we could use rank:

katavorioInstance.droppable(parent, {
  drop:function() {
    ...
    return true;
  },
  rank:1
});

katavorioInstance.droppable(child, {
  drop:function() {
    ...
    return true;
  },
  rank:10
});

With this arrangement you will ensure the #child element always overrides the #parent element when responding to a drop event over the child. The default value for rank is zero, and negative numbers are supported, so in this example we could have left rank off of the #child droppable and just set it to some negative value for the #parent droppable.