JSFiddle - React, Tailwind, and code Playground
HTML
<div class='widget' id='a'>Drag A</div>
<div class='widget' id='b'>Drag B</div>
<div class='widget' id='c'>Drag C</div>
<div class='widget' id='d'>Drag D</div>
CSS
.widget {
position: absolute;
width: 80px;
height: 80px;
background: lightgrey;
margin: 5px;
padding: 10px;
text-align:center;
cursor:move;
}
#b {
top: 120px
}
#c {
left: 120px
}
#d {
top: 120px;
left:120px
}
.selected {
background-color: #4af;
}
JavaScript
var selectedWidgets, GRID = 10,
prevOffsetLeft = 0,
prevOffsetTop = 0;
var draggableOptions = {
grid: [GRID, GRID],
start: function (event, ui) {
// Get all selected widgets
selectedWidgets = $('.widget.selected').filter('[id!=' + $(this).attr('id') + ']');
},
drag: function (event, ui) {
var currentPos = $(this).position();
var originalPos = ui.originalPosition;
var offsetLeft = roundM(currentPos.left - originalPos.left, GRID);
var offsetTop = roundM(currentPos.top - originalPos.top, GRID);
if (offsetLeft !== prevOffsetLeft || offsetTop !== prevOffsetTop) {
console.log(offsetLeft, offsetTop);
moveSelectedWidgets(offsetLeft - prevOffsetLeft, offsetTop - prevOffsetTop);
prevOffsetLeft = offsetLeft;
prevOffsetTop = offsetTop;
}
},
stop: function (event, ui) {
prevOffsetLeft = 0;
prevOffsetTop = 0;
}
};
$('.widget').draggable(draggableOptions).click(function () {
$(this).toggleClass('selected');
});
function moveSelectedWidgets(offsetLeft, offsetTop) {
selectedWidgets.each(function () {
var $this = $(this);
var pos = $this.position();
var posLeft = pos.left;
var posTop = pos.top;
$this.css('left', posLeft + offsetLeft);
$this.css('top', posTop + offsetTop);
});
}
function roundM(number, multiple) {
return Math.round(number / multiple) * multiple;
}