UNPKG

@jbrowse/plugin-linear-genome-view

Version:

JBrowse 2 linear genome view

129 lines (128 loc) 4.1 kB
import { useEffect, useState } from 'react'; import { getRelativeX } from './util'; export function useRangeSelect(ref, model, shiftOnly) { const [startX, setStartX] = useState(); const [currentX, setCurrentX] = useState(); const [anchorPosition, setAnchorPosition] = useState(); const [guideX, setGuideX] = useState(); const mouseDragging = startX !== undefined && anchorPosition === undefined; useEffect(() => { function computeOffsets(offsetX) { if (startX === undefined) { return; } const leftPx = Math.min(startX, offsetX); const rightPx = Math.max(startX, offsetX); return { leftOffset: model.pxToBp(leftPx), rightOffset: model.pxToBp(rightPx), }; } function globalMouseMove(event) { if (ref.current && mouseDragging) { const relativeX = getRelativeX(event, ref.current); setCurrentX(relativeX); } } function globalMouseUp(event) { if (startX !== undefined && ref.current) { const { clientX, clientY } = event; const offsetX = getRelativeX(event, ref.current); setAnchorPosition({ offsetX, clientX, clientY, }); const args = computeOffsets(offsetX); if (args) { model.setOffsets(args.leftOffset, args.rightOffset); } setGuideX(undefined); } } if (mouseDragging) { window.addEventListener('mousemove', globalMouseMove); window.addEventListener('mouseup', globalMouseUp); return () => { window.removeEventListener('mousemove', globalMouseMove); window.removeEventListener('mouseup', globalMouseUp); }; } return () => { }; }, [startX, mouseDragging, model, ref]); useEffect(() => { if (!mouseDragging && currentX !== undefined && startX !== undefined && Math.abs(currentX - startX) <= 3) { handleClose(); } }, [mouseDragging, currentX, startX]); function mouseDown(event) { if (shiftOnly && !event.shiftKey) { return; } event.preventDefault(); event.stopPropagation(); const relativeX = getRelativeX(event, ref.current); setStartX(relativeX); setCurrentX(relativeX); } function mouseMove(event) { if (shiftOnly) { if (event.shiftKey) { setGuideX(getRelativeX(event, ref.current)); } else { setGuideX(undefined); } } else { setGuideX(getRelativeX(event, ref.current)); } } function mouseOut() { setGuideX(undefined); } function handleClose() { setAnchorPosition(undefined); setStartX(undefined); setCurrentX(undefined); } function handleMenuItemClick(_, callback) { callback(); handleClose(); } const open = Boolean(anchorPosition); if (startX === undefined) { return { open, guideX, mouseDown, mouseMove, mouseOut, handleMenuItemClick, }; } const right = anchorPosition ? anchorPosition.offsetX : currentX || 0; const left = Math.min(right, startX); const width = Math.abs(right - startX); const leftBpOffset = model.pxToBp(left); const rightBpOffset = model.pxToBp(left + width); const numOfBpSelected = Math.ceil(width * model.bpPerPx); return { open, rubberbandOn: true, mouseDown, mouseMove, mouseOut, handleClose, handleMenuItemClick, leftBpOffset, rightBpOffset, anchorPosition, numOfBpSelected, width, left, }; }