JSFiddle - React, Tailwind, and code Playground

by AsciiSmoke

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Draggable and Resizable Grid</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div id="grid-container">
        <div class="grid-item player" draggable="true">Player</div>
        <div class="grid-item interaction" draggable="true">Interaction</div>
        <div class="grid-item about" draggable="true">About</div>
    </div>

    <script src="script.js"></script>
</body>
</html>

CSS

#grid-container {
    display: grid;
    grid-template-columns: repeat(6, minmax(150px, 1fr)); /* Each column is at least 150px wide */
    grid-template-rows: repeat(8, minmax(100px, 1fr));    /* Each row is at least 100px tall */
    gap: 10px;
    width: 100%;
    height: 100vh; /* Make the grid fill the viewport */
    position: relative; /* Required for absolute positioning */
    border: 1px solid #ccc;
}

.grid-item {
    background-color: #eee;
    border: 1px solid #999;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: move;
    resize: both; /* Make items resizable */
    overflow: auto; /* Ensure resizable works */
    position: absolute; /* Use absolute positioning to move items within the grid */
}

/* Optional styling for visual appeal */
.grid-item.player {
    background-color: lightblue;
}

.grid-item.interaction {
    background-color: lightgreen;
}

.grid-item.about {
    background-color: lightcoral;
}

JavaScript

// Draggable and resizable implementation

let draggedElement = null;
let gridContainer = document.getElementById('grid-container');

// Function to snap the element to the grid
function snapToGrid(element) {
    const gridCellWidth = gridContainer.offsetWidth / 6;
    const gridCellHeight = gridContainer.offsetHeight / 8;
    
    let top = parseFloat(element.style.top);
    let left = parseFloat(element.style.left);

    // Calculate the nearest grid position
    const snappedTop = Math.round(top / gridCellHeight) * gridCellHeight;
    const snappedLeft = Math.round(left / gridCellWidth) * gridCellWidth;

    // Snap the element to the grid
    element.style.top = `${snappedTop}px`;
    element.style.left = `${snappedLeft}px`;
}

// Event listeners for dragging
document.querySelectorAll('.grid-item').forEach(item => {
    item.addEventListener('dragstart', function (event) {
        draggedElement = event.target;
        draggedElement.style.zIndex = 1000; // Bring the dragged element to front
    });

    item.addEventListener('dragend', function (event) {
        draggedElement.style.zIndex = ''; // Reset z-index after dragging
        snapToGrid(draggedElement); // Snap the element to the grid
        checkForOverlap(); // Ensure no overlap
    });

    // Enable resizing the elements up to the grid constraints
    item.addEventListener('resize', function () {
        let maxWidth = gridContainer.offsetWidth;
        let maxHeight = gridContainer.offsetHeight;

        // Constrain the resize to 6 columns and 8 rows
        const gridCellWidth = maxWidth / 6;
        const gridCellHeight = maxHeight / 8;

        const width = Math.min(this.offsetWidth, gridCellWidth * 6); // Max 6 columns wide
        const height = Math.min(this.offsetHeight, gridCellHeight * 8); // Max 8 rows tall

        this.style.width = `${width}px`;
        this.style.height = `${height}px`;
    });
});

// Function to check for overlap and adjust positions
function...