Skip to content

Instantly share code, notes, and snippets.

@yannbcf
Created December 13, 2021 06:47
Show Gist options
  • Save yannbcf/48e61bc6900c20d7489e984911355026 to your computer and use it in GitHub Desktop.
Save yannbcf/48e61bc6900c20d7489e984911355026 to your computer and use it in GitHub Desktop.
custom alt:V drag & drop implementation
<script setup lang="ts">
import { InventoryManager } from './inventoryManager';
import { onMounted, onUnmounted } from 'vue';
import { Container } from 'typedi';
onMounted(() => {
const inventoryManager = Container.get(InventoryManager);
const container = document.querySelector('.container');
if (!inventoryManager || !container) return;
container.addEventListener('mousedown', inventoryManager.onMouseDown);
container.addEventListener('mouseup', inventoryManager.onMouseUp);
});
onUnmounted(() => {
const inventoryManager = Container.get(InventoryManager);
const container = document.querySelector('.container');
if (!inventoryManager || !container) return;
container.removeEventListener('mousedown', inventoryManager.onMouseDown);
container.removeEventListener('mouseup', inventoryManager.onMouseUp);
});
</script>
import { Service } from 'typedi';
@Service()
export class InventoryManager {
private _currentHoveredSlot: HTMLElement | null = null;
private _baseSlot: HTMLElement | null = null;
private _draggedItem: HTMLElement | null = null;
private _shiftX = 0;
private _shiftY = 0;
private areRectIntersecting(rect1: DOMRect, rect2: DOMRect) {
const RATIO = 1.075;
return !(
rect2.left * RATIO >= rect1.right ||
rect2.right <= rect1.left * RATIO ||
rect2.top * RATIO >= rect1.bottom ||
rect2.bottom <= rect1.top * RATIO
);
}
private moveElementAt(element: HTMLElement, x: number, y: number): void {
element.style.left = x - this._shiftX + 'px';
element.style.top = y - this._shiftY + 'px';
}
private onMouseMove = (ev: MouseEvent): void => {
if (!this._draggedItem) return;
this.moveElementAt(this._draggedItem, ev.pageX, ev.pageY);
this.processSlots();
}
private processSlots(resetClasses = false): void {
const slots = document.querySelectorAll('.slot');
for (let i = 0; i < slots.length; i++) {
const slot = slots[i] as HTMLElement;
if (resetClasses) {
slot.classList.remove('not-valid');
slot.classList.remove('valid');
continue;
}
if (this.areRectIntersecting(slot.getBoundingClientRect(), this._draggedItem.getBoundingClientRect())) {
slot.classList.add(slot.hasChildNodes() ? 'not-valid' : 'valid');
this._currentHoveredSlot = slot;
}
else {
slot.classList.remove('not-valid');
slot.classList.remove('valid');
if (this._currentHoveredSlot === slot)
this._currentHoveredSlot = null;
}
}
}
public onMouseDown = (ev: MouseEvent): void => {
const target = ev.target;
if (!target || !(target instanceof HTMLDivElement)) return;
if (!target.classList.contains('item')) return;
this._shiftX = ev.clientX - target.getBoundingClientRect().left;
this._shiftY = ev.clientY - target.getBoundingClientRect().top;
this._baseSlot = target.parentElement;
this._draggedItem = target;
document.querySelector('.container').append(target);
target.classList.add('moving');
this.moveElementAt(target, ev.pageX, ev.pageY);
document.addEventListener('mousemove', this.onMouseMove);
}
public onMouseUp = (): void => {
if (!this._draggedItem) return;
document.removeEventListener('mousemove', this.onMouseMove);
if (this._currentHoveredSlot && !this._currentHoveredSlot.hasChildNodes()) {
this._currentHoveredSlot.append(this._draggedItem);
this._currentHoveredSlot = null;
}
else
this._baseSlot.append(this._draggedItem);
this._draggedItem.classList.remove('moving');
this._draggedItem = null;
this.processSlots(true);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment