Odo Draggable
A class for versatile, performant draggability.
Support
IE9+.
Dependencies
Odo Pointer, Odo Device, Odo Helpers, Tiny Emitter.
Odo Pointer also expects Object.assign
from ES6 to be available.
X Axis
Setup
var x = new OdoDraggable(document.getElementById('draggable-x'), {
axis: 'x'
});
Position
Set the position of the draggable element. The parameters are percentages, so 50
equates to 50%
.
// Set to 50%
x.setPosition(50, 50);
// Set to 0
x.setPosition(0, 0);
The position of the draggable element can be retrieved with getPosition
. Optionally specify the first parameter as true
to get the percentage coordinates instead of pixels.
x.setPosition(50, 50);
// Get pixels
x.getPosition(); // Coordinate {x: 480, y: 0}
// Get percentages
x.getPosition(true);// Coordinate {x: 50, y: 0}
Limits
You can also sets limits
on the draggable instance, which restricts it to given boundaries. The only parameter is a Rect
. Rect
s have a left
, top
, width
, and height
and can be accessed from the math
property of OdoHelpers
.
In this example, the draggable stops at the edges of the .container
element. Since the draggable is centered within the container and the draggable starts at 0, 0
, the left
limit needs to be negative half the leftover space. The minimum x position is the left
value. The maximum x is the left + width
. The width in this case, is the leftover space (20% because draggable is 80%). The y axis works the same way, but in this example, the top
and height
parameters don't matter because this draggable is restricted to the x
axis.
var math = OdoHelpers.math;
var draggableWidth = x.element.offsetWidth;
var containerWidth = container.offsetWidth;
var left = (containerWidth - draggableWidth) / -2;
var top = 0;
var width = containerWidth - draggableWidth;
var height = 0;
var rect = new OdoHelpers.Rect(left, top, width, height);
x.setLimits(rect);
Y Axis
Heads up! Any draggable element on the Y axis requires its parent to have a height to work with the fallback left
and top
positioning.
Setup
var y = new OdoDraggable(document.getElementById('draggable-y'), {
axis: 'y'
});
Disabling
The draggable instance can be disabled (and re-enabled). The carousel, for example, disables dragging while its animating.
// Disable draggable
y.isEnabled = false;
// Enable draggable.
y.isEnabled = true;
Both Axis
Just like the Y axis note above, the element which contains the draggable element must have a height, otherwise the top
percentage value is not relative to anything and is calculated as zero.
Setup
var xy = new OdoDraggable(document.getElementById('draggable-xy'), {
axis: 'xy'
});
Friction
You can make a draggable instance act like it is resisting the user's touch by setting a friction value. A value of 1
represents no friction; 100% of the user's movements are translated into movement of the draggable instance. Use a value less than 1, like 0.4
, and the draggable element does not move completely in sync with your pointing device.
// Give it friction, like the edge slide of a carousel.
xy.friction = 0.4;
// Remove friction.
xy.friction = 1;
Throwable
Give it a toss.
By default, draggable instances are not throwable. Use the isThrowable
option to enable it. You must also set a boundary for the throwable element, otherwise you can throw it off the screen!
// Create new draggable
var throwable = new OdoDraggable(document.getElementById('draggable-throw-me'), {
axis: 'xy',
isThrowable: true
});
var element = throwable.element;
var parent = element.parentNode;
var draggableWidth = element.offsetWidth;
var draggableHeight = element.offsetHeight;
var containerWidth = parent.offsetWidth;
var containerHeight = parent.offsetHeight;
var left = 0;
var top = 0;
var width = containerWidth - draggableWidth;
var height = containerHeight - draggableHeight;
var rect = new OdoHelpers.Rect(left, top, width, height);
// Set a boundary for the draggable so that it won't be thrown outside of its parent.
throwable.setLimits(rect);
More like a carousel
This example uses the same markup and css as the Odo Carousel, except the .carousel-element
's width is set to fit the exact amount of slides (width is 500%
instead of 2000%
).
Here we follow the same steps. Set the isThrowable
option and then set limits.
var freescroll = new OdoDraggable(document.getElementById('draggable-carousel'), {
axis: 'x',
isThrowable: true
});
var element = freescroll.element;
var parent = element.parentNode;
var draggableWidth = element.offsetWidth;
var containerWidth = parent.offsetWidth;
var left = -draggableWidth + containerWidth;
var top = 0;
var width = -left;
var height = 0;
var rect = new OdoHelpers.Rect(left, top, width, height);
freescroll.setLimits(rect);
Events
Draggable emits three events: START
, MOVE
, and END
.
instance.on(OdoDraggable.EventType.START, function(pointerEvent) {
console.log('drag started', pointerEvent);
});
instance.on(OdoDraggable.EventType.MOVE, function (pointerEvent) {
console.log('drag move:', pointerEvent);
});
instance.on(OdoDraggable.EventType.END, function (pointerEvent) {
console.log('drag ended:', pointerEvent);
});
PointerEvent
Here is the data contained within a drag end event from the first draggable on this page. There are a few simple properties here that have already determined the drag movement compared to its axis.
{
axisDirection: "left",
currentVelocity: {
x: 1.88,
y: 0.14
}
delta: {
x: -32,
y: 0
},
deltaTime: 203,
didMoveOnAxis: true,
direction: "left", // OdoPointer.Direction.LEFT
distance: 32,
end: {
x: -32,
y: 0
},
isDirectionOnAxis: true,
position: {
percent: {
x: -3.2160804020100504,
y: 0
},
pixel: {
x: -32,
y: 0
},
},
start: {
x: 0,
y: 0
},
target: div,
type: "ododraggable:end", // OdoDraggable.EventType.END
velocity: {
x: 0.15763546798029557,
y: 0
}
}
Disposal
To properly destroy a draggable instance, you must call the dispose
method. This removes event listeners, nullifies DOM references, and performs other clean up.
xy.dispose();
Options
OdoDraggable.Defaults = {
// Draggable axis.
axis: OdoPointer.Axis.X,
// Amplifies throw velocity by this value. Higher values make the throwable
// travel farther and faster.
amplifier: 24,
// Once the velocity has gone below this threshold, throwing stops.
velocityStop: 0.08,
// On each throw frame, the velocity is multiplied by this friction value.
// It must be less than 1. Higher values let the throwable slide farther and longer.
throwFriction: 0.94,
// Whether the draggable will keep its movement momentum after the user releases.
isThrowable: false
}