const MIN_SPACE = 2; const RESET_OFFSET = 2; const MAX_PRESS = 250; // The max length of drag time for it to count as a click import { INNER_RADIUS } from "../constants"; export function applyDrag(host: HTMLElement, click: (() => void) | null): void { host.onmousedown = function (event) { // Record the start of the drag const start = new Date().getTime(); //console.log(host.getBoundingClientRect()) const { clientX, pageX, clientY } = event; const viewHeight = event.view?.innerHeight || clientY; const viewWidth = event.view?.innerWidth || clientX; // Get the drag handle of the element. const drag = host.shadowRoot?.querySelector("#drag"); const dragWidth = drag?.getBoundingClientRect().width || 25; const dragHeight = drag?.getBoundingClientRect().height || 25; const dragY = drag?.getBoundingClientRect().y || 0; const dragX = drag?.getBoundingClientRect().x || 0; // cleanup function of mouseup event host.onmouseup = function () { document.removeEventListener('mousemove', onMouseMove); host.onmouseup = null; }; // TODO: Make this more robust and scalable. // Only allow dragging from the drag handle portion // of the element if (clientY < dragY || clientY > dragY + dragHeight || clientX < dragX || clientX > dragX + dragWidth) { return; } if (new Date().getTime() - start > MAX_PRESS && click) moveAt(pageX + dragWidth / 2, clientY - getDiff()); // moves the host at (pageX, pageY) coordinates function moveAt(pageX: number, pageY: number) { host.style.left = pageX + 'px'; host.style.top = pageY + 'px'; } // Finish the drag at a given position function finishMove(x: number, y: number) { document.removeEventListener('mousemove', onMouseMove); host.onmouseup = null; moveAt(x, y); } // Boundary checking function onMouseMove(event: MouseEvent) { const { x, y } = host.getBoundingClientRect(); const xOffset = dragWidth / 2; if (x - INNER_RADIUS < MIN_SPACE) { // Left border finishMove(INNER_RADIUS + MIN_SPACE + RESET_OFFSET, event.clientY - getDiff()); } else if (viewWidth - x < MIN_SPACE) { // Right Border finishMove(viewWidth - MIN_SPACE - RESET_OFFSET - INNER_RADIUS, event.clientY - getDiff()); } else if (y - INNER_RADIUS / 2 < MIN_SPACE) { // Top Border finishMove(event.pageX + xOffset, INNER_RADIUS / 2 + MIN_SPACE + RESET_OFFSET); } else if (viewHeight - (y + INNER_RADIUS / 2) < MIN_SPACE) { // Bottom Border finishMove(event.pageX + xOffset, viewHeight - INNER_RADIUS / 2 - MIN_SPACE - RESET_OFFSET); } else { moveAt(event.pageX + dragWidth / 2, event.clientY - getDiff()); } } // Function to get the distance between the center of the host and the // center of the drag handle function getDiff() { const dragY = drag?.getBoundingClientRect().y || 0; const hostY = host?.getBoundingClientRect().y || 0; return dragY - hostY + dragHeight / 2; } // move the host element on the mousemove event document.addEventListener('mousemove', onMouseMove); // cleanup function of mouseup event host.onmouseup = function () { // See if it counts as a click if (new Date().getTime() - start < MAX_PRESS && click) click(); document.removeEventListener('mousemove', onMouseMove); host.onmouseup = null; }; }; // Override the default browser drag utilities. host.ondragstart = function () { return false; }; }