Created
December 13, 2021 06:47
-
-
Save yannbcf/48e61bc6900c20d7489e984911355026 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