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`; } }