The following code can give you some ideas to get the result that you want. It works with draggable elements of different sizes. Function targets are used to set the target points and lines.
You can test it in this jsfiddle.
var AXIS_RANGE = 12;
var CORNER_RANGE = 14;
var CORNER_EXCLUDE_AXIS = 8;
var AXIS_EXTRA_RANGE = -6;
var myItems = [];
var currentElement = null;
var offX1, offY1, offX2, offY2;
function getPosition(element) {
return {
x: parseFloat(element.getAttribute('data-x')) || 0,
y: parseFloat(element.getAttribute('data-y')) || 0
};
}
function isBetween(value, min, length) {
return min - AXIS_EXTRA_RANGE < value && value < (min + length) + AXIS_EXTRA_RANGE;
}
function getDistance(value1, value2) {
return Math.abs(value1 - value2);
}
function getSnapCoords(element, axis) {
var result = {
isOK: false
};
if (currentElement && currentElement !== element) {
var pos = getPosition(element);
var cur = getPosition(currentElement);
var distX1a = getDistance(pos.x, cur.x);
var distX1b = getDistance(pos.x, cur.x + currentElement.offsetWidth);
var distX2a = getDistance(pos.x + element.offsetWidth, cur.x);
var distX2b = getDistance(pos.x + element.offsetWidth, cur.x + currentElement.offsetWidth);
var distY1a = getDistance(pos.y, cur.y);
var distY1b = getDistance(pos.y, cur.y + currentElement.offsetHeight);
var distY2a = getDistance(pos.y + element.offsetHeight, cur.y);
var distY2b = getDistance(pos.y + element.offsetHeight, cur.y + currentElement.offsetHeight);
var distXa = Math.min(distX1a, distX2a);
var distXb = Math.min(distX1b, distX2b);
var distYa = Math.min(distY1a, distY2a);
var distYb = Math.min(distY1b, distY2b);
if (distXa < distXb) {
result.offX = offX1;
} else {
result.offX = offX2
}
if (distYa < distYb) {
result.offY = offY1;
} else {
result.offY = offY2
}
var distX1 = Math.min(distX1a, distX1b);
var distX2 = Math.min(distX2a, distX2b);
var distY1 = Math.min(distY1a, distY1b);
var distY2 = Math.min(distY2a, distY2b);
var distX = Math.min(distX1, distX2);
var distY = Math.min(distY1, distY2);
var dist = Math.max(distX, distY);
var acceptAxis = dist > CORNER_EXCLUDE_AXIS;
result.x = distX1 < distX2 ? pos.x : pos.x + element.offsetWidth;
result.y = distY1 < distY2 ? pos.y : pos.y + element.offsetHeight;
var inRangeX1 = isBetween(pos.x, cur.x, currentElement.offsetWidth);
var inRangeX2 = isBetween(cur.x, pos.x, element.offsetWidth);
var inRangeY1 = isBetween(pos.y, cur.y, currentElement.offsetHeight);
var inRangeY2 = isBetween(cur.y, pos.y, element.offsetHeight);
switch (axis) {
case "x":
result.isOK = acceptAxis && (inRangeY1 || inRangeY2);
break;
case "y":
result.isOK = acceptAxis && (inRangeX1 || inRangeX2);
break;
default:
result.isOK = true;
break;
}
}
return result;
}
$('.draggable').each(function() {
var pos = getPosition(this);
this.style.transform = 'translate(' + pos.x + 'px, ' + pos.y + 'px)';
myItems.push(getPosition(this));
});
interact('.draggable').draggable({
onstart: function(event) {
currentElement = event.target;
var pos = getPosition(currentElement);
offX1 = event.clientX - pos.x;
offY1 = event.clientY - pos.y;
offX2 = event.clientX - currentElement.offsetWidth - pos.x;
offY2 = event.clientY - currentElement.offsetHeight - pos.y;
},
onmove: dragMoveListener,
snap: {
targets:
(function() {
var snapPoints = [];
$('.draggable').each(function() {
(function(element) {
// Slide along the X axis
snapPoints.push(
function(x, y) {
var data = getSnapCoords(element, "x");
if (data.isOK) {
return {
x: data.x + data.offX,
range: AXIS_RANGE
};
}
});
// Slide along the Y axis
snapPoints.push(
function(x, y) {
var data = getSnapCoords(element, "y");
if (data.isOK) {
return {
y: data.y + data.offY,
range: AXIS_RANGE
};
}
});
// Snap to corner
snapPoints.push(
function(x, y) {
var data = getSnapCoords(element);
if (data.isOK) {
return {
x: data.x + data.offX,
y: data.y + data.offY,
range: CORNER_RANGE
};
}
});
})(this);
});
return snapPoints;
})()
},
onend: function(event) {
$('.draggable').each(function() {
currentElement = null;
myItems.push(getPosition(this));
});
}
});
function dragMoveListener(event) {
var target = event.target;
var oldPos = getPosition(target);
var x = oldPos.x + event.dx;
var y = oldPos.y + event.dy;
// keep the dragged position in the data-x/data-y attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
$('#position').text('x: ' + x + ' - y: ' + y);
var result = $.grep(myItems, function(e) {
if (e.x == parseInt(target.getAttribute('data-x')) || e.y == parseInt(target.getAttribute('data-y')))
return 1;
});
if (result.length >= 1)
target.style.backgroundColor = '#CCC';
else
target.style.backgroundColor = '#FFF';
}