-
-
Save leonardssh/e62d9c6108a59d65ef3fd49da2f686f9 to your computer and use it in GitHub Desktop.
custom alt:V drag & drop implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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