Draggable Droppable and Resizable
by Andrew Warren
HTML
<div class="container-fluid">
<div class="row">
<div class="col-12">
<h5 class="text-center pt-2">Instructions:</h5>
<p class="text-center instructions">Click and drag to move</p>
<p class="text-center instructions">Click and drag red handle to resize</p>
<p class="text-center instructions">Click again when either action is finished</p>
</div>
<!-- Left Container -->
<div id="left-container" class="col-md-2 col-sm-3">
<h5 class="text-center pt-2">Draggable Elements</h5>
<div class="draggable el-1 r16-9" draggable="true">Item 1</div>
<div class="draggable el-2" draggable="true">Item 2</div>
<div class="draggable el-3" draggable="true">Item 3</div>
<div class="draggable el-4" draggable="true">Item 4</div>
</div>
<!-- Right Container -->
<div id="right-container" class="col-md-10 col-sm-9">
<h5 class="text-inline pt-2 inline">Design Area Drop Elements Here</h5>
</div>
</div>
</div>
CSS
#left-container {
background: #f8f9fa;
border-right: 1px solid #ddd;
height: 300px;
overflow-y: auto;
}
.draggable {
width: 80px;
height: 45px;
background: #4caf50;
color: #fff;
text-align: center;
line-height: 45px;
margin: 10px 0;
cursor: grab;
}
#right-container {
background: #eee;
height: 720px;
width: 1280px;
position: relative;
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: repeat(12, 1fr);
gap: 1px;
border: 1px solid #ddd;
}
.grid-cell {
background: #fff;
border: 1px solid #ddd;
}
.dropped {
position: absolute;
background: #2196f3;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #ddd;
box-sizing: border-box;
}
.resizable-handle {
position: absolute;
width: 10px;
height: 10px;
background: #ff5722;
bottom: -5px;
right: -5px;
cursor: se-resize;
}
.delete-button {
position: absolute;
top: -10px;
right: -10px;
background-color: #f00;
color: #fff;
border: none;
cursor: pointer;
width: 20px;
height: 20px;
font-size: 12px;
line-height: 20px;
border-radius: 50%;
}
.movable {
background-color: #9e9e9e !important;
cursor: grabbing;
}
.resizable {
background-color: #9e9e1e !important;
cursor: se-resize;
}
#right-container .dropped {
margin: 0;
}
JavaScript
const leftContainer = document.getElementById('left-container');
const rightContainer = document.getElementById('right-container');
// Dragging variables
let draggedElement = null;
let offsetX = 0;
let offsetY = 0;
// Custom intervals for resizing and dragging
const widthIntervals = [
106.667, 213.333, 320, 426.667, 533.333, 640,
746.667, 853.333, 960, 1066.667, 1173.333, 1280
]; // Custom width intervals
const heightIntervals = [
60, 120, 180, 240, 300, 360,
420, 480, 540, 600, 660, 720
]; // Custom height intervals
// Handle drag start
document.querySelectorAll('.draggable').forEach(draggable => {
draggable.addEventListener('dragstart', (e) => {
draggedElement = e.target.cloneNode(true);
draggedElement.classList.add('dropped');
offsetX = e.offsetX;
offsetY = e.offsetY;
});
});
// Handle drag over (allow drop)
rightContainer.addEventListener('dragover', (e) => {
e.preventDefault();
});
// Handle drop
rightContainer.addEventListener('drop', (e) => {
e.preventDefault();
if (!draggedElement) return;
// Calculate drop position (snap to grid)
const gridSize = rightContainer.offsetWidth / 12;
const x = Math.floor((e.offsetX - offsetX) / gridSize) * gridSize;
const y = Math.floor((e.offsetY - offsetY) / gridSize) * gridSize;
// Set position and append to grid
draggedElement.style.left = `${x}px`;
draggedElement.style.top = `${y}px`;
draggedElement.style.width = `${gridSize}px`;
draggedElement.style.height = `${gridSize * 9 / 16}px`; // 16:9 aspect ratio
draggedElement.style.position = 'absolute';
rightContainer.appendChild(draggedElement);
addResizeFunctionality(draggedElement);
addMoveFunctionality(draggedElement);
addDeleteFunctionality(draggedElement);
draggedElement = null;
});
// Add resizing functionality
// Add resizing functionality
function addResizeFunctionality(element) {
const handle = document.createElement('div');
handle.classList.add('resizable-handle');
...