@jbrowse/plugin-linear-genome-view
Version:
JBrowse 2 linear genome view
129 lines (128 loc) • 4.1 kB
JavaScript
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,
};
}