160 lines
5.1 KiB
TypeScript
160 lines
5.1 KiB
TypeScript
![]() |
export class DraggableResizableClass {
|
||
|
private container: HTMLElement;
|
||
|
private items: any[];
|
||
|
private containerRect: DOMRect;
|
||
|
|
||
|
constructor(container: HTMLElement, items: any[]) {
|
||
|
this.container = container;
|
||
|
this.items = items;
|
||
|
this.containerRect = this.container.getBoundingClientRect();
|
||
|
this.init();
|
||
|
}
|
||
|
|
||
|
private init() {
|
||
|
this.updateListeners();
|
||
|
}
|
||
|
|
||
|
public updateListeners() {
|
||
|
const elements = this.container.querySelectorAll(".draggable-resizable");
|
||
|
elements.forEach((el, index) => {
|
||
|
const handles = (el as HTMLElement).querySelectorAll(".resize-handle");
|
||
|
handles.forEach(handle => {
|
||
|
handle.addEventListener("mousedown", (e) => this.onResizeMouseDown(e, index, handle as HTMLElement));
|
||
|
});
|
||
|
(el as HTMLElement).addEventListener("mousedown", (e) => this.onMouseDown(e, index));
|
||
|
});
|
||
|
}
|
||
|
|
||
|
private onMouseDown(event: MouseEvent, index: number) {
|
||
|
if ((event.target as HTMLElement).classList.contains("resize-handle")) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const item = this.items[index];
|
||
|
const startX = event.clientX;
|
||
|
const startY = event.clientY;
|
||
|
const startLeft = item.x;
|
||
|
const startTop = item.y;
|
||
|
|
||
|
const onMouseMove = (e: MouseEvent) => {
|
||
|
const dx = e.clientX - startX;
|
||
|
const dy = e.clientY - startY;
|
||
|
|
||
|
item.x = Math.min(
|
||
|
Math.max(startLeft + dx, 0),
|
||
|
this.containerRect.width - item.w
|
||
|
);
|
||
|
item.y = Math.min(
|
||
|
Math.max(startTop + dy, 0),
|
||
|
this.containerRect.height - item.h
|
||
|
);
|
||
|
|
||
|
this.updateStyles(index);
|
||
|
};
|
||
|
|
||
|
const onMouseUp = () => {
|
||
|
document.removeEventListener("mousemove", onMouseMove);
|
||
|
document.removeEventListener("mouseup", onMouseUp);
|
||
|
};
|
||
|
|
||
|
document.addEventListener("mousemove", onMouseMove);
|
||
|
document.addEventListener("mouseup", onMouseUp);
|
||
|
}
|
||
|
|
||
|
private onResizeMouseDown(event: MouseEvent, index: number, handle: HTMLElement) {
|
||
|
event.stopPropagation(); // Prevent triggering drag event
|
||
|
|
||
|
const item = this.items[index];
|
||
|
const startX = event.clientX;
|
||
|
const startY = event.clientY;
|
||
|
const startWidth = item.w;
|
||
|
const startHeight = item.h;
|
||
|
const startLeft = item.x;
|
||
|
const startTop = item.y;
|
||
|
|
||
|
const handleClass = handle.classList[1]; // Get the class of the handle
|
||
|
|
||
|
const onMouseMove = (e: MouseEvent) => {
|
||
|
let newWidth = startWidth;
|
||
|
let newHeight = startHeight;
|
||
|
let newLeft = startLeft;
|
||
|
let newTop = startTop;
|
||
|
|
||
|
switch (handleClass) {
|
||
|
case 'top-left':
|
||
|
newWidth = Math.max(startWidth - (e.clientX - startX), 60);
|
||
|
newHeight = Math.max(startHeight - (e.clientY - startY), 30);
|
||
|
newLeft = startLeft + (startWidth - newWidth);
|
||
|
newTop = startTop + (startHeight - newHeight);
|
||
|
break;
|
||
|
|
||
|
case 'top-right':
|
||
|
newWidth = Math.max(startWidth + (e.clientX - startX), 60);
|
||
|
newHeight = Math.max(startHeight - (e.clientY - startY), 30);
|
||
|
newTop = startTop + (startHeight - newHeight);
|
||
|
break;
|
||
|
|
||
|
case 'bottom-left':
|
||
|
newWidth = Math.max(startWidth - (e.clientX - startX), 60);
|
||
|
newHeight = Math.max(startHeight + (e.clientY - startY), 30);
|
||
|
newLeft = startLeft + (startWidth - newWidth);
|
||
|
break;
|
||
|
|
||
|
case 'bottom-right':
|
||
|
newWidth = Math.max(startWidth + (e.clientX - startX), 60);
|
||
|
newHeight = Math.max(startHeight + (e.clientY - startY), 30);
|
||
|
break;
|
||
|
|
||
|
case 'top':
|
||
|
newHeight = Math.max(startHeight - (e.clientY - startY), 30);
|
||
|
newTop = startTop + (startHeight - newHeight);
|
||
|
break;
|
||
|
|
||
|
case 'right':
|
||
|
newWidth = Math.max(startWidth + (e.clientX - startX), 60);
|
||
|
break;
|
||
|
|
||
|
case 'bottom':
|
||
|
newHeight = Math.max(startHeight + (e.clientY - startY), 30);
|
||
|
break;
|
||
|
|
||
|
case 'left':
|
||
|
newWidth = Math.max(startWidth - (e.clientX - startX), 60);
|
||
|
newLeft = startLeft + (startWidth - newWidth);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Ensure resizing does not go outside container boundaries
|
||
|
newWidth = Math.min(Math.max(newWidth, 60), this.containerRect.width - newLeft);
|
||
|
newHeight = Math.min(Math.max(newHeight, 30), this.containerRect.height - newTop);
|
||
|
newLeft = Math.max(Math.min(newLeft, this.containerRect.width - newWidth), 0);
|
||
|
newTop = Math.max(Math.min(newTop, this.containerRect.height - newHeight), 0);
|
||
|
|
||
|
item.w = newWidth;
|
||
|
item.h = newHeight;
|
||
|
item.x = newLeft;
|
||
|
item.y = newTop;
|
||
|
|
||
|
this.updateStyles(index);
|
||
|
};
|
||
|
|
||
|
const onMouseUp = () => {
|
||
|
document.removeEventListener("mousemove", onMouseMove);
|
||
|
document.removeEventListener("mouseup", onMouseUp);
|
||
|
};
|
||
|
|
||
|
document.addEventListener("mousemove", onMouseMove);
|
||
|
document.addEventListener("mouseup", onMouseUp);
|
||
|
}
|
||
|
|
||
|
private updateStyles(index: number) {
|
||
|
const item = this.items[index];
|
||
|
const element = this.container.querySelectorAll(".draggable-resizable")[index] as HTMLElement;
|
||
|
|
||
|
element.style.left = `${item.x}px`;
|
||
|
element.style.top = `${item.y}px`;
|
||
|
element.style.width = `${item.w}px`;
|
||
|
element.style.height = `${item.h}px`;
|
||
|
}
|
||
|
}
|