@jbrowse/plugin-linear-genome-view 5.0.0-beta.1 → 5.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/FeatureTrack/configSchema.d.ts +142 -50
- package/esm/LaunchLinearGenomeView/index.js +2 -13
- package/esm/LinearGenomeView/afterAttach.d.ts +5 -5
- package/esm/LinearGenomeView/afterAttach.js +73 -59
- package/esm/LinearGenomeView/components/CenterLine.js +5 -3
- package/esm/LinearGenomeView/components/CrisprGuidePanel.js +3 -5
- package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +3 -2
- package/esm/LinearGenomeView/components/ExportSvgDialog.js +6 -2
- package/esm/LinearGenomeView/components/GetSequenceDialog.js +2 -2
- package/esm/LinearGenomeView/components/Header.js +11 -1
- package/esm/LinearGenomeView/components/HeaderClearHighlightButton.js +2 -2
- package/esm/LinearGenomeView/components/HeaderPanControls.js +2 -1
- package/esm/LinearGenomeView/components/HeaderZoomControls.js +4 -34
- package/esm/LinearGenomeView/components/Highlight.js +7 -7
- package/esm/LinearGenomeView/components/HighlightBand.js +2 -2
- package/esm/LinearGenomeView/components/HighlightChip.d.ts +1 -2
- package/esm/LinearGenomeView/components/HighlightChip.js +5 -7
- package/esm/LinearGenomeView/components/HoverPositionHighlight.js +3 -3
- package/esm/LinearGenomeView/components/ImportForm.js +2 -2
- package/esm/LinearGenomeView/components/LinearGenomeView.js +3 -3
- package/esm/LinearGenomeView/components/LinearGenomeViewContainer.js +3 -4
- package/esm/LinearGenomeView/components/MiniControls.js +3 -2
- package/esm/LinearGenomeView/components/OverviewHighlight.js +3 -3
- package/esm/LinearGenomeView/components/OverviewHighlightBand.js +2 -3
- package/esm/LinearGenomeView/components/OverviewRubberband.js +20 -45
- package/esm/LinearGenomeView/components/OverviewScalebar.js +4 -5
- package/esm/LinearGenomeView/components/OverviewScalebarPolygon.js +5 -3
- package/esm/LinearGenomeView/components/PaddingBlocks.d.ts +1 -1
- package/esm/LinearGenomeView/components/PaddingBlocks.js +14 -9
- package/esm/LinearGenomeView/components/RangeSelectOverlay.js +5 -6
- package/esm/LinearGenomeView/components/ResizeAllTracksHandle.d.ts +5 -0
- package/esm/LinearGenomeView/components/ResizeAllTracksHandle.js +71 -0
- package/esm/LinearGenomeView/components/Rubberband.d.ts +1 -2
- package/esm/LinearGenomeView/components/Rubberband.js +3 -2
- package/esm/LinearGenomeView/components/SVGHighlightBand.js +2 -3
- package/esm/LinearGenomeView/components/Scalebar.d.ts +2 -6
- package/esm/LinearGenomeView/components/Scalebar.js +8 -5
- package/esm/LinearGenomeView/components/ScalebarRefNameLabels.js +49 -34
- package/esm/LinearGenomeView/components/SearchBox.js +8 -7
- package/esm/LinearGenomeView/components/SearchResultsDialog.d.ts +2 -1
- package/esm/LinearGenomeView/components/SearchResultsDialog.js +2 -2
- package/esm/LinearGenomeView/components/SearchResultsTable.d.ts +2 -1
- package/esm/LinearGenomeView/components/SearchResultsTable.js +12 -29
- package/esm/LinearGenomeView/components/SequenceSearchDialog.d.ts +2 -4
- package/esm/LinearGenomeView/components/TrackContainer.js +63 -9
- package/esm/LinearGenomeView/components/TrackLabel.js +10 -3
- package/esm/LinearGenomeView/components/TrackLabelButtons.js +2 -2
- package/esm/LinearGenomeView/components/TrackLabelDragHandle.js +2 -2
- package/esm/LinearGenomeView/components/TrackLabelMenu.js +3 -2
- package/esm/LinearGenomeView/components/TrackRenderingContainer.d.ts +4 -1
- package/esm/LinearGenomeView/components/TrackRenderingContainer.js +11 -23
- package/esm/LinearGenomeView/components/TracksContainer.js +10 -22
- package/esm/LinearGenomeView/components/VerticalGuide.d.ts +1 -2
- package/esm/LinearGenomeView/components/VerticalGuide.js +3 -16
- package/esm/LinearGenomeView/components/ZoomButton.js +6 -1
- package/esm/LinearGenomeView/components/ZoomTransform.js +4 -0
- package/esm/LinearGenomeView/components/fetchSequence.d.ts +1 -2
- package/esm/LinearGenomeView/components/recentLocationsMenu.js +10 -0
- package/esm/LinearGenomeView/components/searchModes.d.ts +1 -1
- package/esm/LinearGenomeView/components/searchModes.js +1 -1
- package/esm/LinearGenomeView/components/useRangeSelect.d.ts +0 -3
- package/esm/LinearGenomeView/components/useRangeSelect.js +20 -59
- package/esm/LinearGenomeView/components/useSideScroll.d.ts +16 -2
- package/esm/LinearGenomeView/components/useSideScroll.js +153 -103
- package/esm/LinearGenomeView/components/util.d.ts +4 -0
- package/esm/LinearGenomeView/components/util.js +4 -2
- package/esm/LinearGenomeView/consts.d.ts +2 -0
- package/esm/LinearGenomeView/consts.js +3 -1
- package/esm/LinearGenomeView/containingLgv.d.ts +21 -0
- package/esm/LinearGenomeView/containingLgv.js +23 -0
- package/esm/LinearGenomeView/headerFit.d.ts +4 -2
- package/esm/LinearGenomeView/headerFit.js +20 -7
- package/esm/LinearGenomeView/index.d.ts +1 -5
- package/esm/LinearGenomeView/index.js +10 -7
- package/esm/LinearGenomeView/keyboardHandler.d.ts +2 -0
- package/esm/LinearGenomeView/keyboardHandler.js +15 -1
- package/esm/LinearGenomeView/launchKeys.d.ts +2 -0
- package/esm/LinearGenomeView/launchKeys.js +27 -0
- package/esm/LinearGenomeView/lazyDialogs.d.ts +2 -4
- package/esm/LinearGenomeView/lazyDialogs.js +1 -0
- package/esm/LinearGenomeView/linkedViewSync.d.ts +3 -11
- package/esm/LinearGenomeView/linkedViewSync.js +27 -43
- package/esm/LinearGenomeView/menuItems.d.ts +16 -18
- package/esm/LinearGenomeView/menuItems.js +242 -151
- package/esm/LinearGenomeView/model.d.ts +2009 -200
- package/esm/LinearGenomeView/model.js +545 -395
- package/esm/LinearGenomeView/sharedScaleContainer.d.ts +1 -1
- package/esm/LinearGenomeView/showRegionsWithUndo.js +7 -1
- package/esm/LinearGenomeView/stickyChrome.d.ts +5 -9
- package/esm/LinearGenomeView/stickyChrome.js +5 -9
- package/esm/LinearGenomeView/svgcomponents/SVGGridlines.js +4 -4
- package/esm/LinearGenomeView/svgcomponents/SVGHeader.d.ts +4 -1
- package/esm/LinearGenomeView/svgcomponents/SVGHeader.js +8 -21
- package/esm/LinearGenomeView/svgcomponents/SVGHighlights.js +8 -8
- package/esm/LinearGenomeView/svgcomponents/SVGHighlightsOverlay.js +3 -3
- package/esm/LinearGenomeView/svgcomponents/SVGLinearGenomeView.js +7 -11
- package/esm/LinearGenomeView/svgcomponents/SVGRegionSeparators.js +2 -5
- package/esm/LinearGenomeView/svgcomponents/SVGRowHeader.js +5 -6
- package/esm/LinearGenomeView/svgcomponents/SVGRuler.js +9 -10
- package/esm/LinearGenomeView/svgcomponents/SVGScalebar.js +3 -3
- package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.d.ts +27 -0
- package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.js +12 -0
- package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.js +15 -6
- package/esm/LinearGenomeView/svgcomponents/SVGTracks.d.ts +4 -4
- package/esm/LinearGenomeView/svgcomponents/SVGTracks.js +6 -5
- package/esm/LinearGenomeView/svgcomponents/SVGView.d.ts +1 -1
- package/esm/LinearGenomeView/svgcomponents/SVGView.js +1 -1
- package/esm/LinearGenomeView/svgcomponents/figureContract.js +14 -14
- package/esm/LinearGenomeView/svgcomponents/renderViewTracks.js +1 -1
- package/esm/LinearGenomeView/svgcomponents/useViewSvgFigure.js +50 -68
- package/esm/LinearGenomeView/svgcomponents/util.d.ts +9 -5
- package/esm/LinearGenomeView/svgcomponents/util.js +26 -21
- package/esm/LinearGenomeView/types.d.ts +8 -11
- package/esm/LinearGenomeView/util.d.ts +60 -45
- package/esm/LinearGenomeView/util.js +131 -160
- package/esm/MultiLevelRubberband/MultiLevelRubberband.js +7 -4
- package/esm/MultiLevelRubberband/index.d.ts +2 -0
- package/esm/MultiLevelRubberband/index.js +2 -0
- package/esm/MultiLevelRubberband/menuItems.d.ts +34 -0
- package/esm/MultiLevelRubberband/menuItems.js +52 -0
- package/esm/MultiLevelRubberband/rowLabel.d.ts +22 -0
- package/esm/MultiLevelRubberband/rowLabel.js +27 -0
- package/esm/MultiLevelRubberband/types.d.ts +1 -0
- package/esm/MultiLevelRubberband/useRangeSelect.d.ts +2 -1
- package/esm/MultiLevelRubberband/useRangeSelect.js +31 -47
- package/esm/displayKitTests/perRegionTestEnv.d.ts +214 -86
- package/esm/displayKitTests/perRegionTestEnv.js +30 -29
- package/esm/index.d.ts +15 -85
- package/esm/index.js +13 -36
- package/esm/searchUtils.d.ts +18 -9
- package/esm/searchUtils.js +85 -69
- package/esm/shared/RubberbandSpan.js +2 -1
- package/esm/shared/coordLabels.d.ts +7 -0
- package/esm/shared/coordLabels.js +15 -1
- package/esm/shared/useWindowDrag.d.ts +18 -0
- package/esm/shared/useWindowDrag.js +45 -0
- package/package.json +10 -10
- package/esm/LinearGenomeView/FloatingSvgOverlay.d.ts +0 -5
- package/esm/LinearGenomeView/FloatingSvgOverlay.js +0 -25
- package/esm/LinearGenomeView/initKeys.d.ts +0 -13
- package/esm/LinearGenomeView/initKeys.js +0 -104
- package/esm/MultiLevelRubberband/VerticalGuide.d.ts +0 -6
- package/esm/MultiLevelRubberband/VerticalGuide.js +0 -21
- package/esm/lazyPluginExports.d.ts +0 -23
- package/esm/lazyPluginExports.js +0 -36
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { getContainingView } from '@jbrowse/core/util';
|
|
3
2
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
4
3
|
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
|
5
4
|
import ArrowRightIcon from '@mui/icons-material/ArrowRight';
|
|
6
5
|
import CloseIcon from '@mui/icons-material/Close';
|
|
7
6
|
import { IconButton } from '@mui/material';
|
|
8
7
|
import { observer } from 'mobx-react';
|
|
8
|
+
import { containingLgv } from '../../LinearGenomeView/containingLgv.js';
|
|
9
9
|
const useStyles = makeStyles()({
|
|
10
10
|
iconButton: {
|
|
11
11
|
padding: 0,
|
|
@@ -21,7 +21,7 @@ const useStyles = makeStyles()({
|
|
|
21
21
|
// write it.
|
|
22
22
|
export const TrackLabelCloseButton = observer(function TrackLabelCloseButton({ track, }) {
|
|
23
23
|
const { classes } = useStyles();
|
|
24
|
-
const view =
|
|
24
|
+
const view = containingLgv(track);
|
|
25
25
|
return (_jsx(IconButton, { onClick: () => view.hideTrack(track.trackId), className: classes.iconButton, title: "close this track", "data-testid": `track-close-${track.trackId}`, children: _jsx(CloseIcon, { fontSize: "small" }) }));
|
|
26
26
|
});
|
|
27
27
|
export const TrackLabelMinimizeButton = observer(function TrackLabelMinimizeButton({ track }) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { getContainingView } from '@jbrowse/core/util';
|
|
3
2
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
4
3
|
import DragIcon from '@mui/icons-material/DragIndicator';
|
|
5
4
|
import { observer } from 'mobx-react';
|
|
5
|
+
import { containingLgv } from '../../LinearGenomeView/containingLgv.js';
|
|
6
6
|
const useStyles = makeStyles()({
|
|
7
7
|
dragHandle: {
|
|
8
8
|
cursor: 'grab',
|
|
@@ -15,7 +15,7 @@ const useStyles = makeStyles()({
|
|
|
15
15
|
});
|
|
16
16
|
const TrackLabelDragHandle = observer(function TrackLabelDragHandle({ track, }) {
|
|
17
17
|
const { classes } = useStyles();
|
|
18
|
-
const view =
|
|
18
|
+
const view = containingLgv(track);
|
|
19
19
|
const trackId = track.trackId;
|
|
20
20
|
return (_jsx("span", { draggable: true, className: classes.dragHandle, onDragStart: event => {
|
|
21
21
|
const target = event.currentTarget;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
|
|
3
|
-
import {
|
|
3
|
+
import { getSession } from '@jbrowse/core/util';
|
|
4
4
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
5
5
|
import LowPriorityIcon from '@mui/icons-material/LowPriority';
|
|
6
6
|
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
|
7
7
|
import { observer } from 'mobx-react';
|
|
8
|
+
import { containingLgv } from '../../LinearGenomeView/containingLgv.js';
|
|
8
9
|
import { getTrackOrderSubMenu } from './trackLabelMenuItems.js';
|
|
9
10
|
// IconButton's default 5px padding made this the tallest thing in the label
|
|
10
11
|
// (27px), so it, not the text or the other controls, set the label height and
|
|
@@ -17,7 +18,7 @@ const useStyles = makeStyles()({
|
|
|
17
18
|
});
|
|
18
19
|
const TrackLabelMenu = observer(function TrackLabelMenu({ track, }) {
|
|
19
20
|
const { classes } = useStyles();
|
|
20
|
-
const view =
|
|
21
|
+
const view = containingLgv(track);
|
|
21
22
|
const session = getSession(track);
|
|
22
23
|
function getMenuItems() {
|
|
23
24
|
const orderSubMenu = getTrackOrderSubMenu({ view, track });
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { LinearGenomeViewModel } from '../index.ts';
|
|
2
2
|
import type { BaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models';
|
|
3
|
+
import type { LinearDisplayModel } from '@jbrowse/display-kit/types';
|
|
3
4
|
type LGV = LinearGenomeViewModel;
|
|
4
|
-
declare const TrackRenderingContainer: ({ model, track, }: {
|
|
5
|
+
declare const TrackRenderingContainer: ({ model, track, display, ref, }: {
|
|
5
6
|
model: LGV;
|
|
6
7
|
track: BaseTrackModel;
|
|
8
|
+
display: LinearDisplayModel;
|
|
9
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
7
10
|
}) => import("react").JSX.Element;
|
|
8
11
|
export default TrackRenderingContainer;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Suspense
|
|
2
|
+
import { Suspense } from 'react';
|
|
3
3
|
import { LoadingOverlay } from '@jbrowse/core/ui';
|
|
4
|
-
import { getSession } from '@jbrowse/core/util';
|
|
4
|
+
import { coarseStripHTML, getSession } from '@jbrowse/core/util';
|
|
5
5
|
import { getTrackName } from '@jbrowse/core/util/tracks';
|
|
6
6
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
7
|
+
import { TrackOverlayPortal } from '@jbrowse/display-ui';
|
|
7
8
|
import { observer } from 'mobx-react';
|
|
8
|
-
import {
|
|
9
|
+
import { TRACK_OUTLINE_BORDER } from '../consts.js';
|
|
9
10
|
const useStyles = makeStyles()({
|
|
10
11
|
// aligns with block boundaries. check for example the breakpoint split view
|
|
11
12
|
// demo to see if features align if wanting to change things. the -1 left
|
|
@@ -68,32 +69,19 @@ const useStyles = makeStyles()({
|
|
|
68
69
|
// nothing. `figure` names the box and keeps what is inside it reachable. Revisit
|
|
69
70
|
// if inline interactive chrome ever goes away.
|
|
70
71
|
const TrackDisplayRegion = observer(function TrackDisplayRegion({ model, track, children, ...divProps }) {
|
|
71
|
-
const trackName = getTrackName(track.configuration, getSession(track));
|
|
72
|
+
const trackName = coarseStripHTML(getTrackName(track.configuration, getSession(track)));
|
|
72
73
|
const loc = model.coarseVisibleLocStrings;
|
|
73
74
|
return (_jsx("div", { ...divProps, role: "figure", "aria-label": loc ? `${trackName} track, showing ${loc}` : `${trackName} track`, children: children }));
|
|
74
75
|
});
|
|
75
|
-
const TrackRenderingContainer = observer(function TrackRenderingContainer({ model, track, }) {
|
|
76
|
+
const TrackRenderingContainer = observer(function TrackRenderingContainer({ model, track, display, ref, }) {
|
|
76
77
|
const { classes } = useStyles();
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const display = track.activeDisplay;
|
|
80
|
-
const { height, RenderingComponent, DisplayBlurb } = display;
|
|
81
|
-
const { trackRefs, showTrackOutlines } = model;
|
|
78
|
+
const { RenderingComponent, DisplayBlurb } = display;
|
|
79
|
+
const { showTrackOutlines } = model;
|
|
82
80
|
const trackId = track.trackId;
|
|
83
81
|
const minimized = track.minimized;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (el) {
|
|
88
|
-
trackRefs[trackId] = el;
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
delete trackRefs[trackId];
|
|
92
|
-
}
|
|
93
|
-
}, [trackRefs, trackId]);
|
|
94
|
-
return (_jsx("div", { className: classes.trackRenderingContainer, style: {
|
|
95
|
-
height: minimized ? MINIMIZED_TRACK_HEIGHT : height,
|
|
96
|
-
}, "data-testid": `trackRenderingContainer-${model.id}-${trackId}`, children: !minimized ? (_jsxs(_Fragment, { children: [_jsx(TrackDisplayRegion, { model: model, track: track, ref: setRef, className: classes.renderingComponentContainer, style: { left: showTrackOutlines ? -1 : 0 }, children: _jsx(Suspense, { fallback: _jsx(LoadingOverlay, { isVisible: true, immediate: true }), children: _jsx(RenderingComponent, { model: display, onHorizontalScroll: model.horizontalScroll }) }) }), DisplayBlurb ? (_jsx("div", { style: {
|
|
82
|
+
return (_jsx("div", { ref: ref, className: classes.trackRenderingContainer, style: {
|
|
83
|
+
height: model.trackHeight(track),
|
|
84
|
+
}, "data-testid": `trackRenderingContainer-${model.id}-${trackId}`, children: !minimized ? (_jsxs(_Fragment, { children: [_jsx(TrackDisplayRegion, { model: model, track: track, className: classes.renderingComponentContainer, style: { left: showTrackOutlines ? -TRACK_OUTLINE_BORDER : 0 }, children: _jsx(Suspense, { fallback: _jsx(TrackOverlayPortal, { children: _jsx(LoadingOverlay, { isVisible: true, immediate: true }) }), children: _jsx(RenderingComponent, { model: display, onHorizontalScroll: model.horizontalScroll }) }) }), DisplayBlurb ? (_jsx("div", { style: {
|
|
97
85
|
position: 'absolute',
|
|
98
86
|
left: 0,
|
|
99
87
|
top: display.height - 20,
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Suspense, lazy, useRef } from 'react';
|
|
3
3
|
import { PluggableElements } from '@jbrowse/core/ui';
|
|
4
|
-
import {
|
|
5
|
-
import { useMouseTracking } from '@jbrowse/core/ui/useMouseTracking';
|
|
4
|
+
import { useStyleTheme } from '@jbrowse/core/ui/PaletteContext';
|
|
6
5
|
import { getEnv, getSession } from '@jbrowse/core/util';
|
|
7
6
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
8
|
-
import { useTheme } from '@mui/material';
|
|
9
7
|
import { observer } from 'mobx-react';
|
|
10
8
|
import { SCALE_BAR_HEIGHT } from '../consts.js';
|
|
11
9
|
import Gridlines from './Gridlines.js';
|
|
@@ -13,7 +11,6 @@ import OverviewHighlightBand from './OverviewHighlightBand.js';
|
|
|
13
11
|
import PaddingBlocks from './PaddingBlocks.js';
|
|
14
12
|
import RangeSelectOverlay from './RangeSelectOverlay.js';
|
|
15
13
|
import Rubberband from './Rubberband.js';
|
|
16
|
-
import Scalebar from './Scalebar.js';
|
|
17
14
|
import VerticalGuide from './VerticalGuide.js';
|
|
18
15
|
import { useRangeSelect } from './useRangeSelect.js';
|
|
19
16
|
import { useSideScroll } from './useSideScroll.js';
|
|
@@ -24,6 +21,9 @@ const useStyles = makeStyles()({
|
|
|
24
21
|
tracksContainer: {
|
|
25
22
|
position: 'relative',
|
|
26
23
|
contain: 'layout style',
|
|
24
|
+
// horizontal drags and pinches are the view's; vertical scroll stays the
|
|
25
|
+
// page's
|
|
26
|
+
touchAction: 'pan-y',
|
|
27
27
|
},
|
|
28
28
|
scalebarHighlights: {
|
|
29
29
|
position: 'absolute',
|
|
@@ -39,40 +39,28 @@ const useStyles = makeStyles()({
|
|
|
39
39
|
const TracksContainer = observer(function TracksContainer({ children, model, }) {
|
|
40
40
|
const { classes } = useStyles();
|
|
41
41
|
const { pluginManager } = getEnv(model);
|
|
42
|
-
const
|
|
42
|
+
const sideScroll = useSideScroll(model);
|
|
43
43
|
const { showGridlines, showCenterLine } = model;
|
|
44
44
|
const ref = useRef(null);
|
|
45
45
|
// shift-drag range select over the whole tracks area. This is intentionally
|
|
46
46
|
// a separate range-select instance from the one inside <Rubberband> (the
|
|
47
47
|
// scalebar control); don't dedupe them — they cover different regions.
|
|
48
48
|
const range = useRangeSelect(ref, model, true);
|
|
49
|
-
|
|
50
|
-
// read it, and a position in state here would re-render the whole tracks area
|
|
51
|
-
// every frame the pointer moves over it
|
|
52
|
-
const { mouseTracker, handleMouseMove, handleMouseLeave } = useMouseTracking();
|
|
53
|
-
return (_jsx("div", { ref: ref, "data-testid": "tracksContainer", className: classes.tracksContainer, onMouseDown: event => {
|
|
54
|
-
sideScrollMouseDown(event);
|
|
55
|
-
range.mouseDown(event);
|
|
56
|
-
}, onMouseMove: event => {
|
|
57
|
-
handleMouseMove(event);
|
|
49
|
+
return (_jsxs("div", { ref: ref, "data-testid": "tracksContainer", className: classes.tracksContainer, onPointerDown: sideScroll.pointerDown, onClickCapture: sideScroll.clickCapture, onMouseDown: range.mouseDown, onMouseMove: event => {
|
|
58
50
|
range.mouseMove(event);
|
|
59
51
|
}, onMouseLeave: () => {
|
|
60
|
-
handleMouseLeave();
|
|
61
52
|
range.mouseOut();
|
|
62
|
-
},
|
|
63
|
-
height: SCALE_BAR_HEIGHT,
|
|
64
|
-
boxSizing: 'border-box',
|
|
65
|
-
} }) }), _jsx(ScalebarHighlightGroup, { model: model }), _jsx(HighlightGroup, { model: model }), _jsx(PluggableElements, { pluginManager: pluginManager, name: "LinearGenomeView-TracksContainerComponent", props: { model } }), children] }) }));
|
|
53
|
+
}, children: [showGridlines ? (_jsxs(_Fragment, { children: [_jsx(Gridlines, { model: model }), _jsx(PaddingBlocks, { model: model })] })) : null, _jsx(Suspense, { fallback: null, children: showCenterLine ? _jsx(CenterLine, { model: model }) : null }), _jsx(RangeSelectOverlay, { model: model, range: range }), model.volatileGuides.map((guide, idx) => (_jsx(VerticalGuide, { model: model, coordX: guide.xPos }, idx))), _jsx(Rubberband, { model: model }), _jsx(ScalebarHighlightGroup, { model: model }), _jsx(HighlightGroup, { model: model }), _jsx(PluggableElements, { pluginManager: pluginManager, name: "LinearGenomeView-TracksContainerComponent", props: { model } }), children] }));
|
|
66
54
|
});
|
|
67
55
|
const HighlightGroup = observer(function HighlightGroup({ model, }) {
|
|
68
|
-
return getSession(model).highlightsVisible && model.
|
|
56
|
+
return getSession(model).highlightsVisible && model.highlights.length ? (_jsx(Suspense, { fallback: null, children: model.highlights.map((highlight, idx) => (_jsx(Highlight, { model: model, highlight: highlight }, highlightKey(highlight, idx)))) })) : null;
|
|
69
57
|
});
|
|
70
58
|
const ScalebarHighlightGroup = observer(function ScalebarHighlightGroup({ model, }) {
|
|
71
|
-
const theme =
|
|
59
|
+
const theme = useStyleTheme();
|
|
72
60
|
const { pluginManager } = getEnv(model);
|
|
73
61
|
const { classes } = useStyles();
|
|
74
62
|
const viewBands = getSession(model).highlightsVisible
|
|
75
|
-
? model.
|
|
63
|
+
? model.highlights.map((h, idx) => {
|
|
76
64
|
const coords = model.getHighlightCoords(h);
|
|
77
65
|
return coords ? (_jsx(OverviewHighlightBand, { coords: coords, background: getHighlightColor(h, theme).toRgbString() }, highlightKey(h, idx))) : null;
|
|
78
66
|
})
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { LinearGenomeViewModel } from '../index.ts';
|
|
2
|
-
type LGV = LinearGenomeViewModel;
|
|
3
2
|
declare const VerticalGuide: ({ model, coordX, }: {
|
|
4
|
-
model:
|
|
3
|
+
model: LinearGenomeViewModel;
|
|
5
4
|
coordX: number;
|
|
6
5
|
}) => import("react").JSX.Element;
|
|
7
6
|
export default VerticalGuide;
|
|
@@ -1,24 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { stringify } from '@jbrowse/core/util';
|
|
3
|
-
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
4
3
|
import { observer } from 'mobx-react';
|
|
5
|
-
import {
|
|
4
|
+
import { VerticalGuideLine } from '../../shared/coordLabels.js';
|
|
6
5
|
import { stickyChromeTops } from '../stickyChrome.js';
|
|
7
|
-
const useStyles = makeStyles()({
|
|
8
|
-
guide: {
|
|
9
|
-
pointerEvents: 'none',
|
|
10
|
-
height: '100%',
|
|
11
|
-
width: 1,
|
|
12
|
-
position: 'absolute',
|
|
13
|
-
left: 0,
|
|
14
|
-
background: 'red',
|
|
15
|
-
zIndex: 1001,
|
|
16
|
-
},
|
|
17
|
-
});
|
|
18
6
|
const VerticalGuide = observer(function VerticalGuide({ model, coordX, }) {
|
|
19
|
-
const { classes } = useStyles();
|
|
20
7
|
const { width, stickyViewHeaders, headerHeight } = model;
|
|
21
8
|
const { scalebar } = stickyChromeTops({ stickyViewHeaders, headerHeight });
|
|
22
|
-
return (
|
|
9
|
+
return (_jsx(VerticalGuideLine, { coordX: coordX, viewWidth: width, stickyTop: scalebar, children: stringify(model.pxToBp(coordX)) }));
|
|
23
10
|
});
|
|
24
11
|
export default VerticalGuide;
|
|
@@ -15,7 +15,12 @@ const ZoomButton = observer(function ZoomButton({ model, direction, small, }) {
|
|
|
15
15
|
? coarseBpPerPx >= maxBpPerPx - EPSILON
|
|
16
16
|
: coarseBpPerPx <= minBpPerPx + EPSILON;
|
|
17
17
|
const fontSize = small ? 'small' : undefined;
|
|
18
|
-
return (_jsx(Tooltip, { title: out ? 'Zoom out 2x' : 'Zoom in 2x', children: _jsx("span", { children: _jsx(IconButton
|
|
18
|
+
return (_jsx(Tooltip, { title: out ? 'Zoom out 2x' : 'Zoom in 2x', children: _jsx("span", { children: _jsx(IconButton
|
|
19
|
+
// on the button, not left to the Tooltip: its title lands on the
|
|
20
|
+
// <span> the disabled case needs, so the button itself reached the
|
|
21
|
+
// accessibility tree unnamed and nothing driving by name could aim at
|
|
22
|
+
// it
|
|
23
|
+
, { "aria-label": out ? 'Zoom out' : 'Zoom in', "data-testid": out ? 'zoom_out' : 'zoom_in', size: small ? 'small' : undefined, disabled: disabled, onClick: () => {
|
|
19
24
|
model.zoom(out ? model.bpPerPx * 2 : model.bpPerPx / 2);
|
|
20
25
|
}, children: out ? (_jsx(ZoomOut, { fontSize: fontSize })) : (_jsx(ZoomIn, { fontSize: fontSize })) }) }) }));
|
|
21
26
|
});
|
|
@@ -13,6 +13,10 @@ const useStyles = makeStyles()({
|
|
|
13
13
|
position: 'absolute',
|
|
14
14
|
height: '100%',
|
|
15
15
|
pointerEvents: 'none',
|
|
16
|
+
// its own compositor layer: a pan then moves the layer instead of
|
|
17
|
+
// re-rasterizing the root layer's tiles, which paid for the gridline paths
|
|
18
|
+
// on every frame
|
|
19
|
+
willChange: 'transform',
|
|
16
20
|
},
|
|
17
21
|
});
|
|
18
22
|
// Shared zoom/scroll-transform wrapper for the gridline ticks and padding-block
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { StatusCallback } from '@jbrowse/core/util';
|
|
2
|
-
import type { StopToken } from '@jbrowse/core/util/stopToken';
|
|
3
2
|
import type { Region } from '@jbrowse/core/util/types';
|
|
4
3
|
import type { IAnyStateTreeNode } from '@jbrowse/mobx-state-tree';
|
|
5
4
|
export declare function fetchSequence(model: IAnyStateTreeNode, regions: Region[], opts?: {
|
|
6
|
-
|
|
5
|
+
signal?: AbortSignal;
|
|
7
6
|
statusCallback?: StatusCallback;
|
|
8
7
|
}): Promise<import("@jbrowse/core/util").Feature[]>;
|
|
@@ -19,6 +19,16 @@ export function recentLocationsMenu({ recentLocations, onNavigate, onClear, }) {
|
|
|
19
19
|
label: 'Recent',
|
|
20
20
|
subMenu: [
|
|
21
21
|
...recentLocations.map(({ label, loc }) => ({
|
|
22
|
+
// the list dedupes on the location, so two rows can share a
|
|
23
|
+
// display string — two features of the same name at different
|
|
24
|
+
// loci, or two snippets ellipsized to the same text. `id` is what
|
|
25
|
+
// keeps them separate rows to React, which otherwise keys both on
|
|
26
|
+
// that one label.
|
|
27
|
+
//
|
|
28
|
+
// Prefixed, because a freehand row has no location and falls back
|
|
29
|
+
// to its label, which may itself be a locstring — unprefixed, that
|
|
30
|
+
// row and a recorded one at the same locus share an id.
|
|
31
|
+
id: loc ? `loc:${loc}` : `query:${label}`,
|
|
22
32
|
label,
|
|
23
33
|
onClick: () => {
|
|
24
34
|
// a row that recorded a location navigates straight to it; one
|
|
@@ -14,7 +14,7 @@ export function addReferenceScanTrack(model, args) {
|
|
|
14
14
|
type: 'FeatureTrack',
|
|
15
15
|
adapter: args.adapter,
|
|
16
16
|
});
|
|
17
|
-
model.
|
|
17
|
+
void model.launchTrack(args.trackId);
|
|
18
18
|
}
|
|
19
19
|
else {
|
|
20
20
|
session.notify('This session does not support adding tracks', 'warning');
|
|
@@ -7,11 +7,8 @@ interface AnchorPosition {
|
|
|
7
7
|
isClick: boolean;
|
|
8
8
|
}
|
|
9
9
|
export declare function useRangeSelect(ref: React.RefObject<HTMLDivElement | null>, model: LinearGenomeViewModel, shiftOnly?: boolean): {
|
|
10
|
-
open: boolean;
|
|
11
10
|
isClick: boolean | undefined;
|
|
12
|
-
clickBpOffset: import("@jbrowse/core/util/Base1DUtils").PxToBpResult | undefined;
|
|
13
11
|
guideX: number | undefined;
|
|
14
|
-
rubberbandOn: boolean;
|
|
15
12
|
mouseDown: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
16
13
|
mouseMove: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
17
14
|
mouseOut: () => void;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { useCallback,
|
|
1
|
+
import { useCallback, useState } from 'react';
|
|
2
2
|
import { getRelativeX } from '@jbrowse/core/util/getRelativeX';
|
|
3
|
+
import { useWindowDrag } from '../../shared/useWindowDrag.js';
|
|
4
|
+
import { isOnScalebarRefLabel } from './util.js';
|
|
3
5
|
export function useRangeSelect(ref, model, shiftOnly) {
|
|
4
6
|
const [startX, setStartX] = useState();
|
|
5
7
|
const [currentX, setCurrentX] = useState();
|
|
8
|
+
const [startedOnRefLabel, setStartedOnRefLabel] = useState(false);
|
|
6
9
|
// clientX and clientY used for anchorPosition for menu
|
|
7
10
|
// offsetX used for calculations about width of selection
|
|
8
11
|
const [anchorPosition, setAnchorPosition] = useState();
|
|
@@ -14,67 +17,32 @@ export function useRangeSelect(ref, model, shiftOnly) {
|
|
|
14
17
|
setCurrentX(undefined);
|
|
15
18
|
setGuideX(undefined);
|
|
16
19
|
}, []);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// it once here rather than calling getBoundingClientRect on every mousemove
|
|
24
|
-
const { left } = el.getBoundingClientRect();
|
|
25
|
-
function globalMouseMove(event) {
|
|
26
|
-
setCurrentX(event.clientX - left);
|
|
27
|
-
}
|
|
28
|
-
function globalMouseUp(event) {
|
|
29
|
-
if (startX === undefined) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
const { clientX, clientY } = event;
|
|
33
|
-
const offsetX = clientX - left;
|
|
34
|
-
const isClick = Math.abs(offsetX - startX) <= 3;
|
|
35
|
-
// Clear the flag unconditionally once consumed: the label's own onClick
|
|
36
|
-
// also clears it, but that only fires if mouseup lands on the label, so
|
|
37
|
-
// relying on it alone can leave the flag stuck (swallowing the next
|
|
38
|
-
// scalebar click) when mouseup drifts a few px off the label edge.
|
|
39
|
-
const startedOnRefLabel = model.scalebarRefNameClickPending;
|
|
40
|
-
if (startedOnRefLabel) {
|
|
41
|
-
model.setScalebarRefNameClickPending(false);
|
|
42
|
-
}
|
|
43
|
-
// A click that began on a scalebar refname label is handled by that
|
|
44
|
-
// label's onClick (opens its menu), not by the rubberband menu here.
|
|
45
|
-
// Drop the hover guide too: the label's menu covers it while it is open,
|
|
46
|
-
// and nothing else clears it, so picking an item like "Focus on X" left a
|
|
47
|
-
// red line stranded on the scalebar with the pointer nowhere near it
|
|
20
|
+
useWindowDrag(ref, mouseDragging ? startX : undefined, {
|
|
21
|
+
onMove: setCurrentX,
|
|
22
|
+
onEnd: ({ startX, endX, isClick, clientX, clientY }) => {
|
|
23
|
+
// A click on a scalebar refName label belongs to the label's own menu.
|
|
24
|
+
// Drop the hover guide too: that menu covers it, and nothing else clears
|
|
25
|
+
// it once the menu closes
|
|
48
26
|
if (isClick && startedOnRefLabel) {
|
|
49
27
|
setStartX(undefined);
|
|
50
28
|
setCurrentX(undefined);
|
|
51
29
|
setGuideX(undefined);
|
|
52
30
|
return;
|
|
53
31
|
}
|
|
54
|
-
setAnchorPosition({ offsetX, clientX, clientY, isClick });
|
|
32
|
+
setAnchorPosition({ offsetX: endX, clientX, clientY, isClick });
|
|
55
33
|
if (isClick) {
|
|
56
|
-
setGuideX(
|
|
34
|
+
setGuideX(endX);
|
|
57
35
|
}
|
|
58
36
|
else {
|
|
59
|
-
model.setOffsets(model.pxToBp(Math.min(startX,
|
|
37
|
+
model.setOffsets(model.pxToBp(Math.min(startX, endX)), model.pxToBp(Math.max(startX, endX)));
|
|
60
38
|
setGuideX(undefined);
|
|
61
39
|
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
window.addEventListener('mousemove', globalMouseMove);
|
|
70
|
-
window.addEventListener('mouseup', globalMouseUp);
|
|
71
|
-
window.addEventListener('keydown', globalKeyDown);
|
|
72
|
-
return () => {
|
|
73
|
-
window.removeEventListener('mousemove', globalMouseMove);
|
|
74
|
-
window.removeEventListener('mouseup', globalMouseUp);
|
|
75
|
-
window.removeEventListener('keydown', globalKeyDown);
|
|
76
|
-
};
|
|
77
|
-
}, [startX, mouseDragging, model, ref]);
|
|
40
|
+
},
|
|
41
|
+
onCancel: () => {
|
|
42
|
+
setStartX(undefined);
|
|
43
|
+
setCurrentX(undefined);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
78
46
|
function mouseDown(event) {
|
|
79
47
|
if (shiftOnly && !event.shiftKey) {
|
|
80
48
|
return;
|
|
@@ -90,6 +58,7 @@ export function useRangeSelect(ref, model, shiftOnly) {
|
|
|
90
58
|
// clear any leftover menu/selection so a fresh drag isn't blocked by a
|
|
91
59
|
// stale anchorPosition keeping mouseDragging false
|
|
92
60
|
setAnchorPosition(undefined);
|
|
61
|
+
setStartedOnRefLabel(isOnScalebarRefLabel(event.target));
|
|
93
62
|
const relativeX = getRelativeX(event, ref.current);
|
|
94
63
|
setStartX(relativeX);
|
|
95
64
|
setCurrentX(relativeX);
|
|
@@ -111,11 +80,7 @@ export function useRangeSelect(ref, model, shiftOnly) {
|
|
|
111
80
|
callback();
|
|
112
81
|
handleClose();
|
|
113
82
|
}
|
|
114
|
-
const open = Boolean(anchorPosition);
|
|
115
83
|
const isClick = anchorPosition?.isClick;
|
|
116
|
-
const clickBpOffset = isClick
|
|
117
|
-
? model.pxToBp(anchorPosition.offsetX)
|
|
118
|
-
: undefined;
|
|
119
84
|
// rubberband geometry only exists while a drag is in progress (startX set);
|
|
120
85
|
// grouped so a single truthiness check narrows all fields for RubberbandSpan
|
|
121
86
|
let rubberband;
|
|
@@ -132,12 +97,8 @@ export function useRangeSelect(ref, model, shiftOnly) {
|
|
|
132
97
|
};
|
|
133
98
|
}
|
|
134
99
|
return {
|
|
135
|
-
open,
|
|
136
100
|
isClick,
|
|
137
|
-
clickBpOffset,
|
|
138
101
|
guideX,
|
|
139
|
-
// true only mid-drag and not a click — drives RubberbandSpan vs guide
|
|
140
|
-
rubberbandOn: rubberband !== undefined && !isClick,
|
|
141
102
|
mouseDown,
|
|
142
103
|
mouseMove,
|
|
143
104
|
mouseOut,
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import type { LinearGenomeViewModel } from '../index.ts';
|
|
2
2
|
import type React from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Drag to pan and pinch to zoom, on pointer events so a finger works the same
|
|
5
|
+
* as a mouse. A second finger turns a pan into a pinch: the spread between the
|
|
6
|
+
* two zooms about their midpoint, and moving the midpoint pans. Lifting either
|
|
7
|
+
* finger goes back to panning with the other.
|
|
8
|
+
*
|
|
9
|
+
* The host sets `touch-action` to leave the browser only the gestures this
|
|
10
|
+
* does not want (TracksContainer keeps vertical scroll); without it a touch
|
|
11
|
+
* drag is a page scroll and a pinch zooms the page, and no pointer stream
|
|
12
|
+
* arrives.
|
|
13
|
+
*
|
|
14
|
+
* The window listeners go on in the press handler itself rather than in an
|
|
15
|
+
* effect, so a release that lands before React commits still finds them.
|
|
16
|
+
*/
|
|
3
17
|
export declare function useSideScroll(model: LinearGenomeViewModel): {
|
|
4
|
-
|
|
5
|
-
|
|
18
|
+
pointerDown: (event: React.PointerEvent) => void;
|
|
19
|
+
clickCapture: (event: React.MouseEvent) => void;
|
|
6
20
|
};
|