js 拖放并对齐

问题描述 投票:0回答:1

在此示例中,工作场所由 26 张桌子组成。当员工从顶部框拖出时,我希望他捕捉到红点,并且只能放在红点上。有人可以帮忙吗,谢谢...

const workplace = document.getElementById('workplace');
const employeesContainer = document.getElementById('employees-container');
// Layout based on the provided configuration
const columnWidth = 225;
const rowHeight = 125;

// Greate Office Tables
function createTable(x, y, number) {
  const table = document.createElement('div');
  table.className = 'table';
  table.setAttribute('draggable', false);
  table.style.left = `${x}px`;
  table.style.top = `${y}px`;
  table.textContent = number;

  if (number % 2 === 0) {
    const dots = ['right'];
    dots.forEach((position) => {
      const dot = document.createElement('div');
      dot.className = 'drop-dot';
      dot.dataset.position = position;
      table.appendChild(dot);
    });
  } else {
    const dots = ['left'];
    dots.forEach((position) => {
      const dot = document.createElement('div');
      dot.className = 'drop-dot';
      dot.dataset.position = position;
      table.appendChild(dot);
    });
  }


  workplace.appendChild(table);
}

//Create Employees
function createEmployee(x, y, firstName, lastName, initials) {
  const employee = document.createElement('span');
  employee.className = 'employee';
  employee.style.left = `${x}px`;
  employee.style.top = `${y}px`;
  employee.textContent = initials;
  employee.draggable = true;
  // Add drag start event listener
  employee.addEventListener('dragstart', (event) => {
    event.dataTransfer.setData('text/plain', 'employee'); // Custom data for identification
    employee.classList.add('dragging');
  });

  workplace.appendChild(employee);
}

// Create Employee Avatar
function createEmployeeBox(firstName, lastName) {
  const employeeBox = document.createElement('div');
  employeeBox.className = 'employee-box';
  const initials = `${firstName.charAt(0).toUpperCase()}${lastName.charAt(0).toUpperCase()}`;
  employeeBox.textContent = initials;
  employeeBox.draggable = true;
  employeeBox.dataset.initials = initials; // Add custom data attribute

  // Add drag start event listener
  employeeBox.addEventListener('dragstart', (event) => {
    event.dataTransfer.setData('text/plain', 'employee-box'); // Custom data for identification
    employeeBox.classList.add('dragging');
  });

  employeesContainer.appendChild(employeeBox);
}


// First row
for (let i = 0; i < 10; i += 2) {
  createTable(i * (columnWidth / 3), 0, i + 1);
  createTable((i + 1) * (columnWidth / 3) - 20, 0, i + 2); // Adjusted spacing
}
// Second row
for (let i = 4; i < 10; i += 2) {
  createTable(i * (columnWidth / 3), rowHeight, i + 7);
  createTable((i + 1) * (columnWidth / 3) - 20, rowHeight, i + 8); // Adjusted spacing
}
// Third row (same as the first)
for (let i = 0; i < 10; i += 2) {
  createTable(i * (columnWidth / 3), 2 * rowHeight, i + 17);
  createTable((i + 1) * (columnWidth / 3) - 20, 2 * rowHeight, i + 18); // Adjusted spacing
}



// Add employees
createEmployeeBox('sofia', 'Dhomas');
createEmployeeBox('Cofia', 'Whomas');
createEmployeeBox('Mofia', 'Lhomas');
createEmployeeBox('Cofia', 'Nhomas');

function createEmployee(x, y, firstName, lastName, initials) {
  const employee = document.createElement('span');
  employee.className = 'employee';
  employee.style.left = `${x}px`;
  employee.style.top = `${y}px`;
  employee.textContent = initials;
  employee.draggable = true;
  // Add drag start event listener
  employee.addEventListener('dragstart', (event) => {
    event.dataTransfer.setData('text/plain', 'employee'); // Custom data for identification
    employee.classList.add('dragging');
  });
  workplace.appendChild(employee);
}


// Event listeners for drag-and-drop
workplace.addEventListener('dragover', (event) => {
  event.preventDefault();
});

workplace.addEventListener('drop', (event) => {
  event.preventDefault();
  const dataType = event.dataTransfer.getData('text/plain');
  const offsetX = event.clientX - workplace.getBoundingClientRect().left;
  const offsetY = event.clientY - workplace.getBoundingClientRect().top;
  if (dataType === 'employee') {
    const employee = document.querySelector('.employee.dragging');
    if (employee) {
      console.log('employee')
      const nearestTable = findNearestTable(offsetX, offsetY);
      if (nearestTable) {
        console.log('nearestTable')
        const tableRect = nearestTable.getBoundingClientRect();
        const snappedX = tableRect.left + tableRect.width / 2 - employee.clientWidth / 2;
        const snappedY = tableRect.top + tableRect.height / 2 - employee.clientHeight / 2;
        // Remove the corresponding employee box
        const initials = employee.textContent;
        const employeeBox = document.querySelector(`.employee-box[data-initials='${initials}']`);
        if (employeeBox) {
          employeesContainer.removeChild(employeeBox);
        }
        employee.style.left = `${snappedX}px`;
        employee.style.top = `${snappedY}px`;
        employee.classList.remove('dragging');
      }

      // Move employee to new position
      //employee.style.left = `${offsetX - 12.5}px`; // Adjust for centering
      //employee.style.top = `${offsetY - 12.5}px`; // Adjust for centering

    }
  } else if (dataType === 'employee-box') {
    console.log('employee-box')
    // Remove the dragged employee box
    const nearestTable = findNearestTable(offsetX, offsetY);
    if (nearestTable) {
      console.log('nearestTable');
    }

    const employeeBox = document.querySelector('.employee-box.dragging');
    if (employeeBox) {
      employeesContainer.removeChild(employeeBox);
    }
    // Create new employee at the dropped position
    const initials = employeeBox.textContent;
    createEmployee(offsetX - 12.5, offsetY - 12.5, 'New', 'Employee', initials);
  }
}); // Orginal


// Double-click to return employee to the employee box
workplace.addEventListener('dblclick', (event) => {
  if (event.target.classList.contains('employee')) {
    const employee = event.target;
    const initials = employee.textContent;

    // Remove the employee from the workplace
    workplace.removeChild(employee);

    // Create a new employee box with the correct initials
    createEmployeeBox(initials.charAt(0), initials.charAt(1));
  }
});


// FN
// Function to find the nearest table
function findNearestTable(x, y) {
  const tables = document.querySelectorAll('.table');
  let nearestTable = null;
  let minDistance = Infinity;

  tables.forEach((table) => {
    const tableRect = table.getBoundingClientRect();
    console.log(tableRect)
    const distance = Math.sqrt((x - tableRect.left - tableRect.width / 2) ** 2 +
      (y - tableRect.top - tableRect.height / 2) ** 2);

    if (distance < minDistance) {
      console.log('tableRect')
      minDistance = distance;
      nearestTable = table;
    }
  });

  return nearestTable;
}
body {
  font-family: "Public Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
  font-size: 0.9375rem;
  font-wiight: 400;
  line-height: 1.47;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.workplace {
  position: relative;
  width: 740px;
  height: 375px;
  border: 2px solid #cfd3ec;
  margin: 20px;
  background-color: #434968;
  border-radius: 0.5rem;
}

.table {
  position: absolute;
  width: 40px;
  height: 80px;
  background-color: #424659;
  border: 2px solid #cfd3ec;
  border-radius: 0.2rem;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 20px;
  color: #cfd3ec;
}

.table.highlighted-table {
  border: 2px solid yellow;
  /* Change the color as needed */
}

.employee {
  position: absolute;
  width: 25px;
  height: 25px;
  border: 1px solid black;
  border-radius: 50%;
  background-color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  cursor: move;
  user-select: none;
}

.employees-container {
  display: flex;
  width: 740px;
  height: 100px;
  background-color: #434968;
  border: 2px solid #cfd3ec;
  border-radius: 0.3rem;
  box-sizing: border-box;
  align-items: center;
  margin-top: 20px;
  flex-wrap: wrap;
}

.employee-box {
  width: 25px;
  height: 25px;
  border: 1px solid #cfd3ec;
  border-radius: 50%;
  background-color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  cursor: move;
  user-select: none;
  margin: .5rem;
}

.drop-dot {
  position: absolute;
  width: 10px;
  height: 10px;
  background-color: red;
  border-radius: 50%;
  cursor: pointer;
}

.drop-dot[data-position="left"] {
  top: 50%;
  left: -5px;
  transform: translateY(-50%);
}

.drop-dot[data-position="right"] {
  top: 50%;
  right: -5px;
  transform: translateY(-50%);
}
<div class="employees-container" id="employees-container"></div>
<div class="workplace" id="workplace"></div>

javascript jquery drag-and-drop draggable
1个回答
0
投票

在拖拽开始时,您需要有关被拖拽的员工的信息。在拖动时,您可以通过设置类名来更改“放置区域”的样式。在放置事件中,拖动的元素必须移动/附加到新的放置区域。然后必须对拖动的元素进行样式设置,使其就位。

already
对象用于测试员工是否已经在餐桌上。

const workplace = document.getElementById('workplace');
const employeesContainer = document.getElementById('employees-container');

employeesContainer.addEventListener('dragstart', e => {
  e.dataTransfer.setData('text/plain', e.target.dataset.initials);
});

workplace.addEventListener('dragstart', e => {
  e.dataTransfer.setData('text/plain', e.target.dataset.initials);
});

workplace.addEventListener('dragover', e => {
  e.preventDefault();
  workplace.querySelectorAll('.drop-dot').forEach(dot => dot.classList.remove('over'));
  let table = e.target.closest('.table');
  if (table) {
    let already = table.querySelector('.employee-box');
    let dot = table.querySelector('.drop-dot');
    if (dot && !already) {
      dot.classList.add('over');
    }
  }
});

workplace.addEventListener('drop', e => {
  e.preventDefault();
  let table = e.target.closest('.table');
  if (table) {
    let already = table.querySelector('.employee-box');
    if (!already) {
      let dot = table.querySelector('.drop-dot');
      let initials = e.dataTransfer.getData('text/plain');
      let employee = document.querySelector(`div[data-initials="${initials}"]`);
      employee.classList.add(dot.dataset.position);
      table.appendChild(employee);
    }
  }
  workplace.querySelectorAll('.drop-dot').forEach(dot => dot.classList.remove('over'));
});
body {
  font-family: "Public Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
  font-size: 0.9375rem;
  font-wiight: 400;
  line-height: 1.47;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.workplace {
  position: relative;
  width: 740px;
  height: 375px;
  border: 2px solid #cfd3ec;
  margin: 20px;
  background-color: #434968;
  border-radius: 0.5rem;
}

.table {
  position: absolute;
  width: 40px;
  height: 80px;
  background-color: #424659;
  border: 2px solid #cfd3ec;
  border-radius: 0.2rem;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 20px;
  color: #cfd3ec;
}

.table.highlighted-table {
  border: 2px solid yellow;
  /* Change the color as needed */
}

.employee {
  position: absolute;
  width: 25px;
  height: 25px;
  border: 1px solid black;
  border-radius: 50%;
  background-color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  cursor: move;
  user-select: none;
}

.employees-container {
  display: flex;
  width: 740px;
  height: 100px;
  background-color: #434968;
  border: 2px solid #cfd3ec;
  border-radius: 0.3rem;
  box-sizing: border-box;
  align-items: center;
  margin-top: 20px;
  flex-wrap: wrap;
}

.employee-box {
  width: 25px;
  height: 25px;
  border: 1px solid #cfd3ec;
  border-radius: 50%;
  background-color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  cursor: move;
  user-select: none;
  margin: .5rem;
}

.drop-dot {
  position: absolute;
  width: 10px;
  height: 10px;
  background-color: red;
  border-radius: 50%;
  cursor: pointer;
}

.drop-dot.over {
  width: 30px;
  height: 30px;
}

.drop-dot[data-position="left"] {
  top: 50%;
  left: -5px;
  transform: translateY(-50%);
}

.drop-dot[data-position="right"] {
  top: 50%;
  right: -5px;
  transform: translateY(-50%);
}

.table .employee-box.right {
  position: absolute;
  right: -25px;
}

.table .employee-box.left {
  position: absolute;
  left: -25px;
}
<div class="employees-container" id="employees-container">
  <div class="employee-box" draggable="true" data-initials="SD">SD</div>
  <div class="employee-box" draggable="true" data-initials="CW">CW</div>
  <div class="employee-box" draggable="true" data-initials="ML">ML</div>
  <div class="employee-box" draggable="true" data-initials="CN">CN</div>
</div>
<div class="workplace" id="workplace">
  <div class="table" style="left: 0px; top: 0px;">1
    <div class="drop-dot" data-position="left"></div>
  </div>
  <div class="table" style="left: 55px; top: 0px;">2
    <div class="drop-dot" data-position="right"></div>
  </div>
  <div class="table" style="left: 150px; top: 0px;">3
    <div class="drop-dot" data-position="left"></div>
  </div>
  <div class="table" style="left: 205px; top: 0px;">4
    <div class="drop-dot" data-position="right"></div>
  </div>
  <div class="table" style="left: 300px; top: 0px;">5
    <div class="drop-dot" data-position="left"></div>
  </div>
  <div class="table" style="left: 355px; top: 0px;">6
    <div class="drop-dot" data-position="right"></div>
  </div>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.