UNPKG

@milpan/svelte-gantt

Version:

Interactive JavaScript Gantt chart/resource booking component

174 lines (173 loc) 5.75 kB
import { isLeftClick, addEventListenerOnce, getRelativePos } from '../../utils/dom'; import { MIN_DRAG_Y, MIN_DRAG_X } from '../constants'; function getAccessor(accessor) { if (accessor instanceof Function) { return () => accessor(); } else { return () => accessor; } } /** * Applies dragging interaction to gantt elements */ export function useDraggable(node, options) { const onMousedown = createDraggable(options); node.addEventListener('pointerdown', onMousedown); return { destroy() { node.removeEventListener('pointerdown', onMousedown, false); } }; } /** * Applies dragging interaction to gantt elements */ export function createDraggable(options) { let mouseStartPosX; let mouseStartPosY; let mouseStartRight; let direction; let dragging = false; let resizing = false; let initialX; let initialY; let triggered = false; const dragAllowed = getAccessor(options.dragAllowed); const resizeAllowed = getAccessor(options.resizeAllowed); function onMousedown(event) { if (!isLeftClick(event)) { return; } event.stopPropagation(); event.preventDefault(); const canDrag = dragAllowed(); const canResize = resizeAllowed(); if (!canDrag && !canResize) { return; } const x = options.getX(event); const y = options.getY(event); const width = options.getWidth(); initialX = event.clientX; initialY = event.clientY; mouseStartRight = x + width; mouseStartPosX = getRelativePos(options.container, event).x - x; mouseStartPosY = getRelativePos(options.container, event).y - y; if (canResize && mouseStartPosX <= options.resizeHandleWidth) { direction = 'left'; resizing = true; } if (canResize && mouseStartPosX >= width - options.resizeHandleWidth) { direction = 'right'; resizing = true; } if (canDrag && !resizing) { dragging = true; } if ((dragging || resizing) && options.onDown) { options.onDown({ mouseEvent: event, x, width, y, resizing: resizing, dragging: dragging }); } window.addEventListener('pointermove', onMousemove, false); addEventListenerOnce(window, 'pointerup', onMouseup); } ; function onMousemove(event) { if (!triggered) { if (Math.abs(event.clientX - initialX) > MIN_DRAG_X || Math.abs(event.clientY - initialY) > MIN_DRAG_Y) { triggered = true; } else { return; } } event.preventDefault(); if (resizing) { const mousePos = getRelativePos(options.container, event); const x = options.getX(event); const width = options.getWidth(); let resultX; let resultWidth; if (direction === 'left') { if (mouseStartRight - mousePos.x <= 0) { direction = 'right'; resultX = mouseStartRight; resultWidth = mouseStartRight - mousePos.x; mouseStartRight = mouseStartRight + width; } else { resultX = mousePos.x; resultWidth = mouseStartRight - mousePos.x; } } else if (direction === 'right') { //resize right if (mousePos.x - x <= 0) { direction = 'left'; resultX = mousePos.x; resultWidth = mousePos.x - x; mouseStartRight = x; } else { resultX = x; resultWidth = mousePos.x - x; } } if (options.onResize) { options.onResize({ x: resultX, width: resultWidth, event }); } } // mouseup if (dragging && options.onDrag) { const mousePos = getRelativePos(options.container, event); options.onDrag({ x: mousePos.x - mouseStartPosX, y: mousePos.y - mouseStartPosY, event }); } } ; function onMouseup(event) { const x = options.getX(event); const y = options.getY(event); const width = options.getWidth(); options.onMouseUp && options.onMouseUp(); // there is an issue here maybe, we update task according to the mousemove event, but we ignore the mouseup event and use the previously commited x, y and width // you know those issues when task gets rounded incorrectly on resize? could be the cause // ....or not really, this issue results in task resizing when task is merely dragged if (triggered && options.onDrop) { options.onDrop({ mouseEvent: event, x, y, width, dragging: dragging, resizing: resizing }); } mouseStartPosX = null; mouseStartPosY = null; mouseStartRight = null; dragging = false; resizing = false; initialX = null; initialY = null; triggered = false; window.removeEventListener('pointermove', onMousemove, false); } ; return onMousedown; }