@jbrowse/plugin-linear-genome-view
Version:
JBrowse 2 linear genome view
169 lines (168 loc) • 6.65 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useEffect, useState } from 'react';
import { Menu } from '@jbrowse/core/ui';
import { makeStyles } from '@jbrowse/core/util/tss-react';
import { observer } from 'mobx-react';
const useStyles = makeStyles()(theme => ({
refLabel: {
fontSize: 11,
position: 'absolute',
left: 2,
top: -1,
fontWeight: 'bold',
lineHeight: 'normal',
zIndex: 1,
background: theme.palette.background.paper,
cursor: 'pointer',
overflow: 'hidden',
whiteSpace: 'nowrap',
'&:hover': {
background: theme.palette.grey[300],
},
},
b0: {
left: 0,
zIndex: 100,
},
}));
const ScalebarRefNameLabels = observer(function ScalebarRefNameLabels({ model, }) {
const { classes, cx } = useStyles();
const { staticBlocks, offsetPx, scalebarDisplayPrefix } = model;
const [menuState, setMenuState] = useState();
useEffect(() => {
model.setIsScalebarRefNameMenuOpen(!!menuState);
}, [model, menuState]);
let lastLeftBlock = staticBlocks.blocks.findIndex(b => b.type === 'ContentBlock');
if (lastLeftBlock < 0) {
lastLeftBlock = 0;
}
staticBlocks.forEach((block, i) => {
if (block.type === 'ContentBlock' && block.offsetPx - offsetPx < 0) {
lastLeftBlock = i;
}
});
const val = scalebarDisplayPrefix();
const b0 = staticBlocks.blocks[0];
const regionEndPx = new Map();
for (const block of staticBlocks.blocks) {
if (block.type === 'ContentBlock' && block.regionNumber !== undefined) {
const endPx = block.offsetPx + block.widthPx;
const current = regionEndPx.get(block.regionNumber);
if (current === undefined || endPx > current) {
regionEndPx.set(block.regionNumber, endPx);
}
}
}
return (_jsxs(_Fragment, { children: [b0?.type !== 'ContentBlock' && val ? (_jsx("span", { className: cx(classes.b0, classes.refLabel), children: val })) : null, staticBlocks.map((block, index) => {
const { offsetPx: blockOffsetPx, isLeftEndOfDisplayedRegion, key, type, refName, regionNumber, } = block;
const last = index === lastLeftBlock;
const regEndPx = regionNumber !== undefined ? regionEndPx.get(regionNumber) : undefined;
const labelStartPx = last ? offsetPx : blockOffsetPx;
const maxWidth = regEndPx !== undefined ? regEndPx - labelStartPx - 2 : undefined;
const minLabelWidth = 20;
const hasEnoughSpace = maxWidth === undefined || maxWidth >= minLabelWidth;
return type === 'ContentBlock' &&
(isLeftEndOfDisplayedRegion || last) &&
hasEnoughSpace ? (_jsxs("span", { style: {
left: last
? Math.max(0, -offsetPx)
: blockOffsetPx - offsetPx - 1,
paddingLeft: last ? 0 : 1,
maxWidth: maxWidth !== undefined && maxWidth > 0 ? maxWidth : undefined,
}, className: classes.refLabel, "data-testid": `refLabel-${refName}`, onMouseDown: () => {
model.setScalebarRefNameClickPending(true);
}, onClick: event => {
model.setScalebarRefNameClickPending(false);
setMenuState({
anchorEl: event.currentTarget,
refName,
regionNumber: regionNumber,
});
}, children: [last && val ? `${val}:` : '', refName] }, `refLabel-${key}-${index}`)) : null;
}), menuState ? (_jsx(RefNameMenu, { model: model, menuState: menuState, onClose: () => {
setMenuState(undefined);
} })) : null] }));
});
function RefNameMenu({ model, menuState, onClose, }) {
const { displayedRegions } = model;
const { refName, regionNumber } = menuState;
const numRegions = displayedRegions.length;
function moveRegion(fromIndex, toIndex) {
const regions = [...displayedRegions];
const [removed] = regions.splice(fromIndex, 1);
regions.splice(toIndex, 0, removed);
model.setDisplayedRegions(regions);
}
function removeRegion(index) {
const regions = displayedRegions.filter((_, i) => i !== index);
model.setDisplayedRegions(regions);
}
const actionItems = [
...(regionNumber > 0
? [
{
label: 'Move left',
onClick: () => {
moveRegion(regionNumber, regionNumber - 1);
},
},
]
: []),
...(regionNumber < numRegions - 1
? [
{
label: 'Move right',
onClick: () => {
moveRegion(regionNumber, regionNumber + 1);
},
},
]
: []),
...(numRegions > 2 && regionNumber > 0
? [
{
label: 'Move to far left',
onClick: () => {
moveRegion(regionNumber, 0);
},
},
]
: []),
...(numRegions > 2 && regionNumber < numRegions - 1
? [
{
label: 'Move to far right',
onClick: () => {
moveRegion(regionNumber, numRegions - 1);
},
},
]
: []),
{
label: 'Remove this region from view',
onClick: () => {
removeRegion(regionNumber);
},
},
];
return (_jsx(Menu, { anchorEl: menuState.anchorEl, open: true, onClose: onClose, onMenuItemClick: (_, callback) => {
callback();
onClose();
}, menuItems: [
{
label: `Focus on ${refName}`,
onClick: () => {
model.navTo({ refName });
},
},
...(numRegions > 1
? [
{
label: 'Actions',
subMenu: actionItems,
},
]
: []),
] }));
}
export default ScalebarRefNameLabels;