Improves drag-and-drop event handling
Enhances the drag-and-drop experience for event elements by introducing snapping to a configurable time interval and fading out the original element upon successful drop. This change allows users to configure the snap interval in minutes, making it easier to align events to specific time slots. It also adds visual feedback by making the original event transparent during the drag and fading it out on drop, providing a clearer indication of the event's movement.
This commit is contained in:
parent
906616fe7b
commit
457e222262
1 changed files with 75 additions and 11 deletions
|
|
@ -8,11 +8,54 @@ export class ColumnDetector {
|
||||||
private lastMousePosition = { x: 0, y: 0 };
|
private lastMousePosition = { x: 0, y: 0 };
|
||||||
private lastLoggedPosition = { x: 0, y: 0 };
|
private lastLoggedPosition = { x: 0, y: 0 };
|
||||||
private draggedClone: HTMLElement | null = null;
|
private draggedClone: HTMLElement | null = null;
|
||||||
|
private originalEvent: HTMLElement | null = null;
|
||||||
private mouseOffset = { x: 0, y: 0 };
|
private mouseOffset = { x: 0, y: 0 };
|
||||||
|
|
||||||
|
// Konfiguration for snap interval
|
||||||
|
private snapIntervalMinutes = 15; // 15 minutter
|
||||||
|
private hourHeightPx = 60; // Fra CSS --hour-height
|
||||||
|
private get snapDistancePx(): number {
|
||||||
|
return (this.snapIntervalMinutes / 60) * this.hourHeightPx; // 15/60 * 60 = 15px
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Konfigurer snap interval
|
||||||
|
*/
|
||||||
|
public setSnapInterval(minutes: number): void {
|
||||||
|
this.snapIntervalMinutes = minutes;
|
||||||
|
console.log(`Snap interval set to ${minutes} minutes (${this.snapDistancePx}px)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fade out og fjern element fra DOM
|
||||||
|
*/
|
||||||
|
private fadeOutAndRemove(element: HTMLElement): void {
|
||||||
|
element.style.transition = 'opacity 0.3s ease-out';
|
||||||
|
element.style.opacity = '0';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
element.remove();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fjern "clone-" prefix fra event ID og gendan pointer events
|
||||||
|
*/
|
||||||
|
private removeClonePrefix(clone: HTMLElement): void {
|
||||||
|
const cloneId = clone.dataset.eventId;
|
||||||
|
if (cloneId && cloneId.startsWith('clone-')) {
|
||||||
|
const originalId = cloneId.replace('clone-', '');
|
||||||
|
clone.dataset.eventId = originalId;
|
||||||
|
console.log(`Removed clone prefix: ${cloneId} -> ${originalId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gendan pointer events så klonen kan dragges igen
|
||||||
|
clone.style.pointerEvents = '';
|
||||||
|
}
|
||||||
|
|
||||||
private init(): void {
|
private init(): void {
|
||||||
// Lyt til mouse move på hele body
|
// Lyt til mouse move på hele body
|
||||||
|
|
@ -27,19 +70,20 @@ export class ColumnDetector {
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleMouseMove(event: MouseEvent): void {
|
private handleMouseMove(event: MouseEvent): void {
|
||||||
// Hvis musen er holdt nede, tjek for 25px vertikal bevægelse
|
// Hvis musen er holdt nede, tjek for snap interval vertikal bevægelse
|
||||||
if (this.isMouseDown) {
|
if (this.isMouseDown) {
|
||||||
const deltaY = Math.abs(event.clientY - this.lastLoggedPosition.y);
|
const deltaY = Math.abs(event.clientY - this.lastLoggedPosition.y);
|
||||||
|
|
||||||
if (deltaY >= 25) {
|
if (deltaY >= this.snapDistancePx) {
|
||||||
console.log('Mouse dragged 25px vertically:', {
|
console.log(`Mouse dragged ${this.snapIntervalMinutes} minutes (${this.snapDistancePx}px) vertically:`, {
|
||||||
from: this.lastLoggedPosition,
|
from: this.lastLoggedPosition,
|
||||||
to: { x: event.clientX, y: event.clientY },
|
to: { x: event.clientX, y: event.clientY },
|
||||||
verticalDistance: Math.round(deltaY)
|
verticalDistance: Math.round(deltaY),
|
||||||
|
snapInterval: `${this.snapIntervalMinutes} minutes`
|
||||||
});
|
});
|
||||||
this.lastLoggedPosition = { x: event.clientX, y: event.clientY };
|
this.lastLoggedPosition = { x: event.clientX, y: event.clientY };
|
||||||
|
|
||||||
// Opdater klonens Y-position ved 25px snap (relativt til kolonne)
|
// Opdater klonens Y-position ved snap interval (relativt til kolonne)
|
||||||
if (this.draggedClone && this.draggedClone.parentElement) {
|
if (this.draggedClone && this.draggedClone.parentElement) {
|
||||||
const columnRect = this.draggedClone.parentElement.getBoundingClientRect();
|
const columnRect = this.draggedClone.parentElement.getBoundingClientRect();
|
||||||
const relativeY = event.clientY - columnRect.top - this.mouseOffset.y;
|
const relativeY = event.clientY - columnRect.top - this.mouseOffset.y;
|
||||||
|
|
@ -149,7 +193,12 @@ export class ColumnDetector {
|
||||||
|
|
||||||
// Hvis vi fandt et event, lav en clone
|
// Hvis vi fandt et event, lav en clone
|
||||||
if (eventElement) {
|
if (eventElement) {
|
||||||
|
// Gem reference til original event
|
||||||
|
this.originalEvent = eventElement;
|
||||||
this.cloneEvent(eventElement, event);
|
this.cloneEvent(eventElement, event);
|
||||||
|
// Sæt originalen til gennemsigtig og forhindre text selection mens der trækkes
|
||||||
|
eventElement.style.opacity = '0.6';
|
||||||
|
eventElement.style.userSelect = 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -208,12 +257,27 @@ export class ColumnDetector {
|
||||||
this.isMouseDown = false;
|
this.isMouseDown = false;
|
||||||
console.log('Mouse up at:', { x: event.clientX, y: event.clientY });
|
console.log('Mouse up at:', { x: event.clientX, y: event.clientY });
|
||||||
|
|
||||||
// Ryd op - fjern klonen (DISABLED FOR DEBUGGING)
|
// Drop operationen: fade out original og remove clone suffix
|
||||||
// if (this.draggedClone) {
|
if (this.originalEvent && this.draggedClone) {
|
||||||
// this.draggedClone.remove();
|
// Fade out og fjern originalen
|
||||||
// this.draggedClone = null;
|
this.fadeOutAndRemove(this.originalEvent);
|
||||||
// console.log('Removed clone');
|
|
||||||
// }
|
// Fjern clone suffix fra klonen
|
||||||
|
this.removeClonePrefix(this.draggedClone);
|
||||||
|
|
||||||
|
// Ryd op
|
||||||
|
this.originalEvent = null;
|
||||||
|
this.draggedClone = null;
|
||||||
|
|
||||||
|
console.log('Drop completed: original faded out and removed, clone became permanent');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup hvis ingen drop (ingen clone var aktiv)
|
||||||
|
if (this.originalEvent && !this.draggedClone) {
|
||||||
|
this.originalEvent.style.opacity = '';
|
||||||
|
this.originalEvent.style.userSelect = '';
|
||||||
|
this.originalEvent = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue