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');
 ...