@jbrowse/plugin-linear-genome-view 3.1.0 → 3.2.0
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/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +9 -9
- package/dist/LaunchLinearGenomeView/index.js +9 -5
- package/dist/LinearGenomeView/components/OverviewRubberband.js +2 -14
- package/dist/LinearGenomeView/components/OverviewRubberbandHoverTooltip.d.ts +10 -0
- package/dist/LinearGenomeView/components/OverviewRubberbandHoverTooltip.js +36 -0
- package/dist/LinearGenomeView/components/Rubberband.js +3 -21
- package/dist/LinearGenomeView/components/RubberbandSpan.js +6 -20
- package/dist/LinearGenomeView/components/RubberbandTooltip.d.ts +5 -0
- package/dist/LinearGenomeView/components/RubberbandTooltip.js +28 -0
- package/dist/LinearGenomeView/components/TracksContainer.js +2 -2
- package/dist/LinearGenomeView/components/VerticalGuide.js +3 -21
- package/dist/LinearGenomeView/model.d.ts +27 -3
- package/dist/LinearGenomeView/model.js +59 -26
- package/dist/LinearGenomeView/types.d.ts +5 -0
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js +9 -9
- package/esm/LaunchLinearGenomeView/index.js +9 -5
- package/esm/LinearGenomeView/components/OverviewRubberband.js +3 -15
- package/esm/LinearGenomeView/components/OverviewRubberbandHoverTooltip.d.ts +10 -0
- package/esm/LinearGenomeView/components/OverviewRubberbandHoverTooltip.js +34 -0
- package/esm/LinearGenomeView/components/Rubberband.js +4 -22
- package/esm/LinearGenomeView/components/RubberbandSpan.js +4 -21
- package/esm/LinearGenomeView/components/RubberbandTooltip.d.ts +5 -0
- package/esm/LinearGenomeView/components/RubberbandTooltip.js +25 -0
- package/esm/LinearGenomeView/components/TracksContainer.js +2 -2
- package/esm/LinearGenomeView/components/VerticalGuide.js +4 -22
- package/esm/LinearGenomeView/model.d.ts +27 -3
- package/esm/LinearGenomeView/model.js +59 -26
- package/esm/LinearGenomeView/types.d.ts +5 -0
- package/package.json +3 -3
|
@@ -78,14 +78,14 @@ function stateModelFactory() {
|
|
|
78
78
|
return (_b = (_a = self.blockState.get(blockKey)) === null || _a === void 0 ? void 0 : _a.layout) === null || _b === void 0 ? void 0 : _b.getByID(id);
|
|
79
79
|
},
|
|
80
80
|
searchFeatureByID(id) {
|
|
81
|
+
var _a;
|
|
81
82
|
let ret;
|
|
82
|
-
self.blockState.
|
|
83
|
-
var _a;
|
|
83
|
+
for (const block of self.blockState.values()) {
|
|
84
84
|
const val = (_a = block.layout) === null || _a === void 0 ? void 0 : _a.getByID(id);
|
|
85
85
|
if (val) {
|
|
86
86
|
ret = val;
|
|
87
87
|
}
|
|
88
|
-
}
|
|
88
|
+
}
|
|
89
89
|
return ret;
|
|
90
90
|
},
|
|
91
91
|
}))
|
|
@@ -138,9 +138,9 @@ function stateModelFactory() {
|
|
|
138
138
|
self.setError();
|
|
139
139
|
self.setCurrStatsBpPerPx(0);
|
|
140
140
|
self.clearFeatureDensityStats();
|
|
141
|
-
|
|
141
|
+
for (const val of self.blockState.values()) {
|
|
142
142
|
val.doReload();
|
|
143
|
-
}
|
|
143
|
+
}
|
|
144
144
|
superReload();
|
|
145
145
|
},
|
|
146
146
|
};
|
|
@@ -230,17 +230,17 @@ function stateModelFactory() {
|
|
|
230
230
|
if (!view.initialized) {
|
|
231
231
|
return;
|
|
232
232
|
}
|
|
233
|
-
self.blockDefinitions.contentBlocks
|
|
233
|
+
for (const block of self.blockDefinitions.contentBlocks) {
|
|
234
234
|
blocksPresent[block.key] = true;
|
|
235
235
|
if (!self.blockState.has(block.key)) {
|
|
236
236
|
self.addBlock(block.key, block);
|
|
237
237
|
}
|
|
238
|
-
}
|
|
239
|
-
self.blockState.
|
|
238
|
+
}
|
|
239
|
+
for (const key of self.blockState.keys()) {
|
|
240
240
|
if (!blocksPresent[key]) {
|
|
241
241
|
self.deleteBlock(key);
|
|
242
242
|
}
|
|
243
|
-
}
|
|
243
|
+
}
|
|
244
244
|
}));
|
|
245
245
|
},
|
|
246
246
|
}))
|
|
@@ -20,7 +20,7 @@ export default function LaunchLinearGenomeViewF(pluginManager) {
|
|
|
20
20
|
view.setHideHeader(!nav);
|
|
21
21
|
}
|
|
22
22
|
if (highlight !== undefined) {
|
|
23
|
-
|
|
23
|
+
for (const h of highlight) {
|
|
24
24
|
const p = parseLocString(h, refName => assemblyManager.isValidRefName(refName, assembly));
|
|
25
25
|
const { start, end } = p;
|
|
26
26
|
if (start !== undefined && end !== undefined) {
|
|
@@ -31,13 +31,17 @@ export default function LaunchLinearGenomeViewF(pluginManager) {
|
|
|
31
31
|
assemblyName: assembly,
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
-
}
|
|
34
|
+
}
|
|
35
35
|
}
|
|
36
|
-
await handleSelectedRegion({
|
|
36
|
+
await handleSelectedRegion({
|
|
37
|
+
input: loc,
|
|
38
|
+
model: view,
|
|
39
|
+
assembly: asm,
|
|
40
|
+
});
|
|
37
41
|
const idsNotFound = [];
|
|
38
|
-
|
|
42
|
+
for (const track of tracks) {
|
|
39
43
|
tryTrack(view, track, idsNotFound);
|
|
40
|
-
}
|
|
44
|
+
}
|
|
41
45
|
if (idsNotFound.length) {
|
|
42
46
|
throw new Error(`Could not resolve identifiers: ${idsNotFound.join(',')}`);
|
|
43
47
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
|
-
import { getSession
|
|
4
|
-
import { Tooltip } from '@mui/material';
|
|
3
|
+
import { getSession } from '@jbrowse/core/util';
|
|
5
4
|
import { observer } from 'mobx-react';
|
|
6
5
|
import { makeStyles } from 'tss-react/mui';
|
|
6
|
+
import OverviewRubberbandHoverTooltip from './OverviewRubberbandHoverTooltip';
|
|
7
7
|
import RubberbandSpan from './RubberbandSpan';
|
|
8
8
|
import { getRelativeX } from './util';
|
|
9
9
|
const useStyles = makeStyles()({
|
|
@@ -22,18 +22,6 @@ const useStyles = makeStyles()({
|
|
|
22
22
|
position: 'relative',
|
|
23
23
|
},
|
|
24
24
|
});
|
|
25
|
-
const HoverTooltip = observer(function ({ model, open, guideX, overview, }) {
|
|
26
|
-
var _a;
|
|
27
|
-
const { classes } = useStyles();
|
|
28
|
-
const { cytobandOffset } = model;
|
|
29
|
-
const { assemblyManager } = getSession(model);
|
|
30
|
-
const px = overview.pxToBp(guideX - cytobandOffset);
|
|
31
|
-
const assembly = assemblyManager.get(px.assemblyName);
|
|
32
|
-
const cytoband = (_a = assembly === null || assembly === void 0 ? void 0 : assembly.cytobands) === null || _a === void 0 ? void 0 : _a.find(f => px.coord > f.get('start') &&
|
|
33
|
-
px.coord < f.get('end') &&
|
|
34
|
-
px.refName === assembly.getCanonicalRefName(f.get('refName')));
|
|
35
|
-
return (_jsx(Tooltip, { open: open, placement: "top", title: [stringify(px), cytoband === null || cytoband === void 0 ? void 0 : cytoband.get('name')].join(' '), arrow: true, children: _jsx("div", { className: classes.guide, style: { left: guideX } }) }));
|
|
36
|
-
});
|
|
37
25
|
const OverviewRubberband = observer(function OverviewRubberband({ model, overview, ControlComponent = _jsx("div", {}), }) {
|
|
38
26
|
const { cytobandOffset } = model;
|
|
39
27
|
const [startX, setStartX] = useState();
|
|
@@ -103,7 +91,7 @@ const OverviewRubberband = observer(function OverviewRubberband({ model, overvie
|
|
|
103
91
|
setGuideX(undefined);
|
|
104
92
|
}
|
|
105
93
|
if (startX === undefined) {
|
|
106
|
-
return (_jsxs("div", { className: classes.rel, children: [guideX !== undefined ? (_jsx(
|
|
94
|
+
return (_jsxs("div", { className: classes.rel, children: [guideX !== undefined ? (_jsx(OverviewRubberbandHoverTooltip, { model: model, open: !mouseDragging, overview: overview, guideX: guideX })) : null, _jsx("div", { className: classes.rubberbandControl, ref: controlsRef, onMouseDown: mouseDown, onMouseOut: mouseOut, onMouseMove: mouseMove, children: ControlComponent })] }));
|
|
107
95
|
}
|
|
108
96
|
let left = startX || 0;
|
|
109
97
|
let width = 0;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LinearGenomeViewModel } from '..';
|
|
2
|
+
import type { Base1DViewModel } from '@jbrowse/core/util/Base1DViewModel';
|
|
3
|
+
type LGV = LinearGenomeViewModel;
|
|
4
|
+
declare const OverviewRubberbandHoverTooltip: ({ model, open, guideX, overview, }: {
|
|
5
|
+
model: LGV;
|
|
6
|
+
open: boolean;
|
|
7
|
+
guideX: number;
|
|
8
|
+
overview: Base1DViewModel;
|
|
9
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export default OverviewRubberbandHoverTooltip;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { getSession, stringify } from '@jbrowse/core/util';
|
|
3
|
+
import { Tooltip } from '@mui/material';
|
|
4
|
+
import { observer } from 'mobx-react';
|
|
5
|
+
import { makeStyles } from 'tss-react/mui';
|
|
6
|
+
const useStyles = makeStyles()({
|
|
7
|
+
rubberbandControl: {
|
|
8
|
+
cursor: 'crosshair',
|
|
9
|
+
width: '100%',
|
|
10
|
+
minHeight: 8,
|
|
11
|
+
},
|
|
12
|
+
guide: {
|
|
13
|
+
pointerEvents: 'none',
|
|
14
|
+
height: '100%',
|
|
15
|
+
width: 1,
|
|
16
|
+
position: 'absolute',
|
|
17
|
+
},
|
|
18
|
+
rel: {
|
|
19
|
+
position: 'relative',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
const OverviewRubberbandHoverTooltip = observer(function ({ model, open, guideX, overview, }) {
|
|
23
|
+
var _a;
|
|
24
|
+
const { classes } = useStyles();
|
|
25
|
+
const { cytobandOffset } = model;
|
|
26
|
+
const { assemblyManager } = getSession(model);
|
|
27
|
+
const px = overview.pxToBp(guideX - cytobandOffset);
|
|
28
|
+
const assembly = assemblyManager.get(px.assemblyName);
|
|
29
|
+
const cytoband = (_a = assembly === null || assembly === void 0 ? void 0 : assembly.cytobands) === null || _a === void 0 ? void 0 : _a.find(f => px.coord > f.get('start') &&
|
|
30
|
+
px.coord < f.get('end') &&
|
|
31
|
+
px.refName === assembly.getCanonicalRefName(f.get('refName')));
|
|
32
|
+
return (_jsx(Tooltip, { open: open, placement: "top", title: [stringify(px), cytoband === null || cytoband === void 0 ? void 0 : cytoband.get('name')].join(' '), arrow: true, children: _jsx("div", { className: classes.guide, style: { left: guideX } }) }));
|
|
33
|
+
});
|
|
34
|
+
export default OverviewRubberbandHoverTooltip;
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useRef } from 'react';
|
|
3
|
-
import { Menu
|
|
4
|
-
import { getSession } from '@jbrowse/core/util';
|
|
5
|
-
import { isSessionWithMultipleViews } from '@jbrowse/product-core';
|
|
3
|
+
import { Menu } from '@jbrowse/core/ui';
|
|
6
4
|
import { observer } from 'mobx-react';
|
|
7
5
|
import { makeStyles } from 'tss-react/mui';
|
|
8
6
|
import RubberbandSpan from './RubberbandSpan';
|
|
9
7
|
import VerticalGuide from './VerticalGuide';
|
|
10
8
|
import { useRangeSelect } from './useRangeSelect';
|
|
11
|
-
import { HEADER_BAR_HEIGHT, HEADER_OVERVIEW_HEIGHT } from '../consts';
|
|
12
9
|
const useStyles = makeStyles()({
|
|
13
10
|
rubberbandControl: {
|
|
14
11
|
cursor: 'crosshair',
|
|
@@ -20,28 +17,13 @@ const useStyles = makeStyles()({
|
|
|
20
17
|
const Rubberband = observer(function ({ model, ControlComponent = _jsx("div", {}), }) {
|
|
21
18
|
const ref = useRef(null);
|
|
22
19
|
const { classes } = useStyles();
|
|
23
|
-
const
|
|
20
|
+
const { stickyViewHeaders, rubberbandTop } = model;
|
|
24
21
|
const { guideX, rubberbandOn, leftBpOffset, rightBpOffset, numOfBpSelected, width, left, anchorPosition, open, handleMenuItemClick, handleClose, mouseMove, mouseDown, mouseOut, } = useRangeSelect(ref, model);
|
|
25
|
-
|
|
26
|
-
if (isSessionWithMultipleViews(session)) {
|
|
27
|
-
;
|
|
28
|
-
({ stickyViewHeaders } = session);
|
|
29
|
-
}
|
|
30
|
-
let rubberbandControlTop = 0;
|
|
31
|
-
if (stickyViewHeaders) {
|
|
32
|
-
rubberbandControlTop = VIEW_HEADER_HEIGHT;
|
|
33
|
-
if (!model.hideHeader) {
|
|
34
|
-
rubberbandControlTop += HEADER_BAR_HEIGHT;
|
|
35
|
-
if (!model.hideHeaderOverview) {
|
|
36
|
-
rubberbandControlTop += HEADER_OVERVIEW_HEIGHT;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return (_jsxs(_Fragment, { children: [guideX !== undefined ? (_jsx(VerticalGuide, { model: model, coordX: guideX })) : rubberbandOn ? (_jsx(RubberbandSpan, { leftBpOffset: leftBpOffset, rightBpOffset: rightBpOffset, numOfBpSelected: numOfBpSelected, width: width, left: left, top: rubberbandControlTop, sticky: stickyViewHeaders })) : null, anchorPosition ? (_jsx(Menu, { anchorReference: "anchorPosition", anchorPosition: {
|
|
22
|
+
return (_jsxs(_Fragment, { children: [guideX !== undefined ? (_jsx(VerticalGuide, { model: model, coordX: guideX })) : rubberbandOn ? (_jsx(RubberbandSpan, { leftBpOffset: leftBpOffset, rightBpOffset: rightBpOffset, numOfBpSelected: numOfBpSelected, width: width, left: left, top: rubberbandTop, sticky: stickyViewHeaders })) : null, anchorPosition ? (_jsx(Menu, { anchorReference: "anchorPosition", anchorPosition: {
|
|
41
23
|
left: anchorPosition.clientX,
|
|
42
24
|
top: anchorPosition.clientY,
|
|
43
25
|
}, onMenuItemClick: handleMenuItemClick, open: open, onClose: handleClose, menuItems: model.rubberBandMenuItems() })) : null, _jsx("div", { "data-testid": "rubberband_controls", className: classes.rubberbandControl, style: {
|
|
44
|
-
top:
|
|
26
|
+
top: rubberbandTop,
|
|
45
27
|
position: stickyViewHeaders ? 'sticky' : undefined,
|
|
46
28
|
}, ref: ref, onMouseDown: mouseDown, onMouseMove: mouseMove, onMouseOut: mouseOut, children: ControlComponent })] }));
|
|
47
29
|
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { stringify, toLocale } from '@jbrowse/core/util';
|
|
4
|
-
import {
|
|
4
|
+
import { Typography, alpha } from '@mui/material';
|
|
5
5
|
import { makeStyles } from 'tss-react/mui';
|
|
6
|
+
import RubberbandTooltip from './RubberbandTooltip';
|
|
6
7
|
const useStyles = makeStyles()(theme => {
|
|
7
8
|
const { tertiary } = theme.palette;
|
|
8
9
|
const background = alpha(tertiary.light, 0.7);
|
|
@@ -20,32 +21,14 @@ const useStyles = makeStyles()(theme => {
|
|
|
20
21
|
minHeight: 8,
|
|
21
22
|
},
|
|
22
23
|
rubberbandText: {
|
|
23
|
-
color: tertiary.contrastText,
|
|
24
|
-
},
|
|
25
|
-
popover: {
|
|
26
|
-
mouseEvents: 'none',
|
|
27
|
-
cursor: 'crosshair',
|
|
28
|
-
},
|
|
29
|
-
paper: {
|
|
30
|
-
paddingLeft: theme.spacing(1),
|
|
31
|
-
paddingRight: theme.spacing(1),
|
|
24
|
+
color: theme.palette.tertiary.contrastText,
|
|
32
25
|
},
|
|
33
26
|
};
|
|
34
27
|
});
|
|
35
|
-
function Tooltip({ anchorEl, side, text, }) {
|
|
36
|
-
const { classes } = useStyles();
|
|
37
|
-
return (_jsx(Popover, { className: classes.popover, classes: { paper: classes.paper }, open: true, anchorEl: anchorEl, anchorOrigin: {
|
|
38
|
-
vertical: 'top',
|
|
39
|
-
horizontal: side === 'left' ? 'right' : 'left',
|
|
40
|
-
}, transformOrigin: {
|
|
41
|
-
vertical: 'bottom',
|
|
42
|
-
horizontal: side === 'left' ? 'left' : 'right',
|
|
43
|
-
}, keepMounted: true, disableRestoreFocus: true, children: _jsx(Typography, { children: text }) }));
|
|
44
|
-
}
|
|
45
28
|
export default function RubberbandSpan({ leftBpOffset, rightBpOffset, numOfBpSelected, left, width, top = 0, sticky = false, }) {
|
|
46
29
|
const { classes } = useStyles();
|
|
47
30
|
const [anchorEl, setAnchorEl] = useState(null);
|
|
48
|
-
return (_jsxs(_Fragment, { children: [anchorEl ? (_jsxs(_Fragment, { children: [_jsx(
|
|
31
|
+
return (_jsxs(_Fragment, { children: [anchorEl ? (_jsxs(_Fragment, { children: [_jsx(RubberbandTooltip, { side: "left", anchorEl: anchorEl, text: stringify(leftBpOffset) }), _jsx(RubberbandTooltip, { side: "right", anchorEl: anchorEl, text: stringify(rightBpOffset) })] })) : null, _jsx("div", { className: classes.rubberband, style: { left, width }, children: numOfBpSelected ? (_jsxs(Typography, { ref: el => {
|
|
49
32
|
setAnchorEl(el);
|
|
50
33
|
}, variant: "h6", className: classes.rubberbandText, style: {
|
|
51
34
|
top,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Popover, Typography } from '@mui/material';
|
|
3
|
+
import { makeStyles } from 'tss-react/mui';
|
|
4
|
+
const useStyles = makeStyles()(theme => {
|
|
5
|
+
return {
|
|
6
|
+
popover: {
|
|
7
|
+
mouseEvents: 'none',
|
|
8
|
+
cursor: 'crosshair',
|
|
9
|
+
},
|
|
10
|
+
paper: {
|
|
11
|
+
paddingLeft: theme.spacing(1),
|
|
12
|
+
paddingRight: theme.spacing(1),
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
export default function RubberbandTooltip({ anchorEl, side, text, }) {
|
|
17
|
+
const { classes } = useStyles();
|
|
18
|
+
return (_jsx(Popover, { className: classes.popover, classes: { paper: classes.paper }, open: true, anchorEl: anchorEl, anchorOrigin: {
|
|
19
|
+
vertical: 'top',
|
|
20
|
+
horizontal: side === 'left' ? 'left' : 'right',
|
|
21
|
+
}, transformOrigin: {
|
|
22
|
+
vertical: 'bottom',
|
|
23
|
+
horizontal: side === 'left' ? 'right' : 'left',
|
|
24
|
+
}, keepMounted: true, disableRestoreFocus: true, children: _jsx(Typography, { children: text }) }));
|
|
25
|
+
}
|
|
@@ -24,7 +24,7 @@ const TracksContainer = observer(function TracksContainer({ children, model, })
|
|
|
24
24
|
const { classes } = useStyles();
|
|
25
25
|
const { pluginManager } = getEnv(model);
|
|
26
26
|
const { mouseDown: mouseDown1, mouseUp } = useSideScroll(model);
|
|
27
|
-
const { stickyViewHeaders,
|
|
27
|
+
const { stickyViewHeaders, rubberbandTop, showGridlines, showCenterLine } = model;
|
|
28
28
|
const ref = useRef(null);
|
|
29
29
|
const { guideX, rubberbandOn, leftBpOffset, rightBpOffset, numOfBpSelected, width, left, anchorPosition, open, handleMenuItemClick, handleClose, mouseMove, mouseDown: mouseDown2, } = useRangeSelect(ref, model, true);
|
|
30
30
|
useWheelScroll(ref, model);
|
|
@@ -32,7 +32,7 @@ const TracksContainer = observer(function TracksContainer({ children, model, })
|
|
|
32
32
|
return (_jsxs("div", { ref: ref, "data-testid": "tracksContainer", className: classes.tracksContainer, onMouseDown: event => {
|
|
33
33
|
mouseDown1(event);
|
|
34
34
|
mouseDown2(event);
|
|
35
|
-
}, onMouseMove: mouseMove, onMouseUp: mouseUp, children: [showGridlines ? _jsx(Gridlines, { model: model }) : null, _jsx(Suspense, { fallback: null, children: showCenterLine ? _jsx(CenterLine, { model: model }) : null }), guideX !== undefined ? (_jsx(VerticalGuide, { model: model, coordX: guideX })) : rubberbandOn ? (_jsx(Suspense, { fallback: null, children: _jsx(RubberbandSpan, { leftBpOffset: leftBpOffset, rightBpOffset: rightBpOffset, numOfBpSelected: numOfBpSelected, width: width, left: left, top:
|
|
35
|
+
}, onMouseMove: mouseMove, onMouseUp: mouseUp, children: [showGridlines ? _jsx(Gridlines, { model: model }) : null, _jsx(Suspense, { fallback: null, children: showCenterLine ? _jsx(CenterLine, { model: model }) : null }), guideX !== undefined ? (_jsx(VerticalGuide, { model: model, coordX: guideX })) : rubberbandOn ? (_jsx(Suspense, { fallback: null, children: _jsx(RubberbandSpan, { leftBpOffset: leftBpOffset, rightBpOffset: rightBpOffset, numOfBpSelected: numOfBpSelected, width: width, left: left, top: rubberbandTop, sticky: stickyViewHeaders }) })) : null, anchorPosition ? (_jsx(Menu, { anchorReference: "anchorPosition", anchorPosition: {
|
|
36
36
|
left: anchorPosition.clientX,
|
|
37
37
|
top: anchorPosition.clientY,
|
|
38
38
|
}, onMenuItemClick: handleMenuItemClick, open: open, onClose: handleClose, menuItems: model.rubberBandMenuItems() })) : null, _jsx(Rubberband, { model: model, ControlComponent: _jsx(Scalebar, { model: model, style: {
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import { getSession, stringify } from '@jbrowse/core/util';
|
|
4
|
-
import { isSessionWithMultipleViews } from '@jbrowse/product-core';
|
|
2
|
+
import { stringify } from '@jbrowse/core/util';
|
|
5
3
|
import { Tooltip } from '@mui/material';
|
|
6
4
|
import { observer } from 'mobx-react';
|
|
7
5
|
import { makeStyles } from 'tss-react/mui';
|
|
8
|
-
import { HEADER_BAR_HEIGHT, HEADER_OVERVIEW_HEIGHT } from '../consts';
|
|
9
6
|
const useStyles = makeStyles()({
|
|
10
7
|
guide: {
|
|
11
8
|
pointerEvents: 'none',
|
|
@@ -13,7 +10,7 @@ const useStyles = makeStyles()({
|
|
|
13
10
|
width: 1,
|
|
14
11
|
position: 'absolute',
|
|
15
12
|
background: 'red',
|
|
16
|
-
zIndex:
|
|
13
|
+
zIndex: 1001,
|
|
17
14
|
},
|
|
18
15
|
tooltipTarget: {
|
|
19
16
|
position: 'sticky',
|
|
@@ -22,25 +19,10 @@ const useStyles = makeStyles()({
|
|
|
22
19
|
});
|
|
23
20
|
const VerticalGuide = observer(function VerticalGuide({ model, coordX, }) {
|
|
24
21
|
const { classes } = useStyles();
|
|
25
|
-
const
|
|
26
|
-
let stickyViewHeaders = false;
|
|
27
|
-
if (isSessionWithMultipleViews(session)) {
|
|
28
|
-
;
|
|
29
|
-
({ stickyViewHeaders } = session);
|
|
30
|
-
}
|
|
31
|
-
let tooltipTop = 0;
|
|
32
|
-
if (stickyViewHeaders) {
|
|
33
|
-
tooltipTop = VIEW_HEADER_HEIGHT;
|
|
34
|
-
if (!model.hideHeader) {
|
|
35
|
-
tooltipTop += HEADER_BAR_HEIGHT;
|
|
36
|
-
if (!model.hideHeaderOverview) {
|
|
37
|
-
tooltipTop += HEADER_OVERVIEW_HEIGHT;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
22
|
+
const { stickyViewHeaders, rubberbandTop } = model;
|
|
41
23
|
return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { open: true, placement: "top", title: stringify(model.pxToBp(coordX)), arrow: true, children: _jsx("div", { className: classes.tooltipTarget, style: {
|
|
42
24
|
left: coordX + 6,
|
|
43
|
-
top:
|
|
25
|
+
top: rubberbandTop,
|
|
44
26
|
position: stickyViewHeaders ? 'sticky' : undefined,
|
|
45
27
|
} }) }), _jsx("div", { className: classes.guide, style: { left: coordX } })] }));
|
|
46
28
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import type { BpOffset, ExportSvgOptions, HighlightType, NavLocation } from './types';
|
|
2
|
+
import type { BpOffset, ExportSvgOptions, HighlightType, InitState, NavLocation } from './types';
|
|
3
3
|
import type PluginManager from '@jbrowse/core/PluginManager';
|
|
4
4
|
import type BaseResult from '@jbrowse/core/TextSearch/BaseResults';
|
|
5
5
|
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly';
|
|
@@ -30,6 +30,7 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
30
30
|
highlight: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").IArrayType<import("mobx-state-tree").IType<HighlightType, HighlightType, HighlightType>>, [undefined]>;
|
|
31
31
|
colorByCDS: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
32
32
|
showTrackOutlines: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
33
|
+
init: import("mobx-state-tree").IType<InitState | undefined, InitState | undefined, InitState | undefined>;
|
|
33
34
|
}, {
|
|
34
35
|
width: number;
|
|
35
36
|
} & {
|
|
@@ -58,6 +59,7 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
58
59
|
readonly interRegionPaddingWidth: number;
|
|
59
60
|
readonly assemblyNames: string[];
|
|
60
61
|
readonly stickyViewHeaders: boolean;
|
|
62
|
+
readonly rubberbandTop: number;
|
|
61
63
|
readonly pinnedTracksTop: number;
|
|
62
64
|
} & {
|
|
63
65
|
scaleBarDisplayPrefix(): string | undefined;
|
|
@@ -144,6 +146,7 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
144
146
|
setDraggingTrackId(idx?: string): void;
|
|
145
147
|
setScaleFactor(factor: number): void;
|
|
146
148
|
clearView(): void;
|
|
149
|
+
setInit(arg?: InitState): void;
|
|
147
150
|
exportSvg(opts?: ExportSvgOptions): Promise<void>;
|
|
148
151
|
} & {
|
|
149
152
|
slide: (viewWidths: number) => void;
|
|
@@ -164,7 +167,6 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
164
167
|
readonly coarseVisibleLocStrings: string;
|
|
165
168
|
} & {
|
|
166
169
|
setCoarseDynamicBlocks(blocks: BlockSet): void;
|
|
167
|
-
afterAttach(): void;
|
|
168
170
|
} & {
|
|
169
171
|
moveTo(start?: BpOffset, end?: BpOffset): void;
|
|
170
172
|
navToLocString(input: string, optAssemblyName?: string): Promise<void>;
|
|
@@ -210,6 +212,7 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
210
212
|
} | undefined;
|
|
211
213
|
} & {
|
|
212
214
|
afterCreate(): void;
|
|
215
|
+
afterAttach(): void;
|
|
213
216
|
}, import("mobx-state-tree").ModelCreationType<import("mobx-state-tree/dist/internal").ExtractCFromProps<{
|
|
214
217
|
id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
215
218
|
displayName: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<string>>;
|
|
@@ -232,7 +235,28 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
232
235
|
highlight: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").IArrayType<import("mobx-state-tree").IType<HighlightType, HighlightType, HighlightType>>, [undefined]>;
|
|
233
236
|
colorByCDS: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
234
237
|
showTrackOutlines: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
235
|
-
|
|
238
|
+
init: import("mobx-state-tree").IType<InitState | undefined, InitState | undefined, InitState | undefined>;
|
|
239
|
+
}>>, {
|
|
240
|
+
type: string;
|
|
241
|
+
id: string;
|
|
242
|
+
displayName: string | undefined;
|
|
243
|
+
tracks: any[];
|
|
244
|
+
minimized: boolean;
|
|
245
|
+
displayedRegions: Region[];
|
|
246
|
+
offsetPx: number;
|
|
247
|
+
bpPerPx: number;
|
|
248
|
+
hideHeader: boolean;
|
|
249
|
+
hideHeaderOverview: boolean;
|
|
250
|
+
hideNoTracksActive: boolean;
|
|
251
|
+
trackSelectorType: string;
|
|
252
|
+
showCenterLine: boolean;
|
|
253
|
+
showCytobandsSetting: boolean;
|
|
254
|
+
trackLabels: string;
|
|
255
|
+
showGridlines: boolean;
|
|
256
|
+
highlight: HighlightType[];
|
|
257
|
+
colorByCDS: boolean;
|
|
258
|
+
showTrackOutlines: boolean;
|
|
259
|
+
}>;
|
|
236
260
|
export type LinearGenomeViewStateModel = ReturnType<typeof stateModelFactory>;
|
|
237
261
|
export type LinearGenomeViewModel = Instance<LinearGenomeViewStateModel>;
|
|
238
262
|
export { default as LinearGenomeView, default as ReactComponent, } from './components/LinearGenomeView';
|
|
@@ -53,6 +53,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
53
53
|
highlight: types.optional(types.array(types.frozen()), []),
|
|
54
54
|
colorByCDS: types.optional(types.boolean, () => localStorageGetBoolean('lgv-colorByCDS', false)),
|
|
55
55
|
showTrackOutlines: types.optional(types.boolean, () => localStorageGetBoolean('lgv-showTrackOutlines', true)),
|
|
56
|
+
init: types.frozen(),
|
|
56
57
|
}))
|
|
57
58
|
.volatile(() => ({
|
|
58
59
|
volatileWidth: undefined,
|
|
@@ -101,10 +102,10 @@ export function stateModelFactory(pluginManager) {
|
|
|
101
102
|
? session.stickyViewHeaders
|
|
102
103
|
: false;
|
|
103
104
|
},
|
|
104
|
-
get
|
|
105
|
+
get rubberbandTop() {
|
|
105
106
|
let pinnedTracksTop = 0;
|
|
106
107
|
if (this.stickyViewHeaders) {
|
|
107
|
-
pinnedTracksTop = VIEW_HEADER_HEIGHT
|
|
108
|
+
pinnedTracksTop = VIEW_HEADER_HEIGHT;
|
|
108
109
|
if (!self.hideHeader) {
|
|
109
110
|
pinnedTracksTop += HEADER_BAR_HEIGHT;
|
|
110
111
|
if (!self.hideHeaderOverview) {
|
|
@@ -114,6 +115,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
114
115
|
}
|
|
115
116
|
return pinnedTracksTop;
|
|
116
117
|
},
|
|
118
|
+
get pinnedTracksTop() {
|
|
119
|
+
return this.rubberbandTop + SCALE_BAR_HEIGHT;
|
|
120
|
+
},
|
|
117
121
|
}))
|
|
118
122
|
.views(self => ({
|
|
119
123
|
scaleBarDisplayPrefix() {
|
|
@@ -227,32 +231,32 @@ export function stateModelFactory(pluginManager) {
|
|
|
227
231
|
return results;
|
|
228
232
|
},
|
|
229
233
|
rewriteOnClicks(trackType, viewMenuActions) {
|
|
230
|
-
|
|
234
|
+
for (const action of viewMenuActions) {
|
|
231
235
|
if ('subMenu' in action) {
|
|
232
236
|
this.rewriteOnClicks(trackType, action.subMenu);
|
|
233
237
|
}
|
|
234
238
|
if ('onClick' in action) {
|
|
235
239
|
const holdOnClick = action.onClick;
|
|
236
240
|
action.onClick = (...args) => {
|
|
237
|
-
self.tracks
|
|
241
|
+
for (const track of self.tracks) {
|
|
238
242
|
if (track.type === trackType) {
|
|
239
243
|
holdOnClick.apply(track, [track, ...args]);
|
|
240
244
|
}
|
|
241
|
-
}
|
|
245
|
+
}
|
|
242
246
|
};
|
|
243
247
|
}
|
|
244
|
-
}
|
|
248
|
+
}
|
|
245
249
|
},
|
|
246
250
|
get trackTypeActions() {
|
|
247
251
|
const allActions = new Map();
|
|
248
|
-
self.tracks
|
|
252
|
+
for (const track of self.tracks) {
|
|
249
253
|
const trackInMap = allActions.get(track.type);
|
|
250
254
|
if (!trackInMap) {
|
|
251
255
|
const viewMenuActions = structuredClone(track.viewMenuActions);
|
|
252
256
|
this.rewriteOnClicks(track.type, viewMenuActions);
|
|
253
257
|
allActions.set(track.type, viewMenuActions);
|
|
254
258
|
}
|
|
255
|
-
}
|
|
259
|
+
}
|
|
256
260
|
return allActions;
|
|
257
261
|
},
|
|
258
262
|
}))
|
|
@@ -377,11 +381,13 @@ export function stateModelFactory(pluginManager) {
|
|
|
377
381
|
hideTrack(trackId) {
|
|
378
382
|
const schema = pluginManager.pluggableConfigSchemaType('track');
|
|
379
383
|
const conf = resolveIdentifier(schema, getRoot(self), trackId);
|
|
380
|
-
const
|
|
384
|
+
const tracks = self.tracks.filter(t => t.configuration === conf);
|
|
381
385
|
transaction(() => {
|
|
382
|
-
|
|
386
|
+
for (const track of tracks) {
|
|
387
|
+
self.tracks.remove(track);
|
|
388
|
+
}
|
|
383
389
|
});
|
|
384
|
-
return
|
|
390
|
+
return tracks.length;
|
|
385
391
|
},
|
|
386
392
|
}))
|
|
387
393
|
.actions(self => ({
|
|
@@ -522,6 +528,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
522
528
|
self.scrollTo(0);
|
|
523
529
|
self.zoomTo(10);
|
|
524
530
|
},
|
|
531
|
+
setInit(arg) {
|
|
532
|
+
self.init = arg;
|
|
533
|
+
},
|
|
525
534
|
async exportSvg(opts = {}) {
|
|
526
535
|
const { renderToSvg } = await import('./svgcomponents/SVGLinearGenomeView');
|
|
527
536
|
const html = await renderToSvg(self, opts);
|
|
@@ -742,7 +751,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
742
751
|
for (const [key, value] of self.trackTypeActions.entries()) {
|
|
743
752
|
if (value.length) {
|
|
744
753
|
menuItems.push({ type: 'divider' }, { type: 'subHeader', label: key });
|
|
745
|
-
|
|
754
|
+
for (const action of value) {
|
|
755
|
+
menuItems.push(action);
|
|
756
|
+
}
|
|
746
757
|
}
|
|
747
758
|
}
|
|
748
759
|
return menuItems;
|
|
@@ -784,20 +795,6 @@ export function stateModelFactory(pluginManager) {
|
|
|
784
795
|
self.coarseDynamicBlocks = blocks.contentBlocks;
|
|
785
796
|
self.coarseTotalBp = blocks.totalBp;
|
|
786
797
|
},
|
|
787
|
-
afterAttach() {
|
|
788
|
-
addDisposer(self, autorun(() => {
|
|
789
|
-
if (self.initialized) {
|
|
790
|
-
this.setCoarseDynamicBlocks(self.dynamicBlocks);
|
|
791
|
-
}
|
|
792
|
-
}, { delay: 150 }));
|
|
793
|
-
addDisposer(self, autorun(() => {
|
|
794
|
-
const s = (s) => JSON.stringify(s);
|
|
795
|
-
const { showCytobandsSetting, showCenterLine, colorByCDS } = self;
|
|
796
|
-
localStorageSetItem('lgv-showCytobands', s(showCytobandsSetting));
|
|
797
|
-
localStorageSetItem('lgv-showCenterLine', s(showCenterLine));
|
|
798
|
-
localStorageSetItem('lgv-colorByCDS', s(colorByCDS));
|
|
799
|
-
}));
|
|
800
|
-
},
|
|
801
798
|
}))
|
|
802
799
|
.actions(self => ({
|
|
803
800
|
moveTo(start, end) {
|
|
@@ -964,6 +961,33 @@ export function stateModelFactory(pluginManager) {
|
|
|
964
961
|
document.removeEventListener('keydown', handler);
|
|
965
962
|
});
|
|
966
963
|
},
|
|
964
|
+
afterAttach() {
|
|
965
|
+
addDisposer(self, autorun(() => {
|
|
966
|
+
var _a;
|
|
967
|
+
const { init } = self;
|
|
968
|
+
if (init) {
|
|
969
|
+
self
|
|
970
|
+
.navToLocString(init.loc, init.assembly)
|
|
971
|
+
.catch((e) => {
|
|
972
|
+
getSession(self).notifyError(`${e}`, e);
|
|
973
|
+
});
|
|
974
|
+
(_a = init.tracks) === null || _a === void 0 ? void 0 : _a.map(t => self.showTrack(t));
|
|
975
|
+
self.setInit(undefined);
|
|
976
|
+
}
|
|
977
|
+
}));
|
|
978
|
+
addDisposer(self, autorun(() => {
|
|
979
|
+
if (self.initialized) {
|
|
980
|
+
self.setCoarseDynamicBlocks(self.dynamicBlocks);
|
|
981
|
+
}
|
|
982
|
+
}, { delay: 150 }));
|
|
983
|
+
addDisposer(self, autorun(() => {
|
|
984
|
+
const s = (s) => JSON.stringify(s);
|
|
985
|
+
const { showCytobandsSetting, showCenterLine, colorByCDS } = self;
|
|
986
|
+
localStorageSetItem('lgv-showCytobands', s(showCytobandsSetting));
|
|
987
|
+
localStorageSetItem('lgv-showCenterLine', s(showCenterLine));
|
|
988
|
+
localStorageSetItem('lgv-colorByCDS', s(colorByCDS));
|
|
989
|
+
}));
|
|
990
|
+
},
|
|
967
991
|
}))
|
|
968
992
|
.preProcessSnapshot(snap => {
|
|
969
993
|
if (!snap) {
|
|
@@ -976,6 +1000,15 @@ export function stateModelFactory(pluginManager) {
|
|
|
976
1000
|
: [highlight],
|
|
977
1001
|
...rest,
|
|
978
1002
|
};
|
|
1003
|
+
})
|
|
1004
|
+
.postProcessSnapshot(snap => {
|
|
1005
|
+
if (!snap) {
|
|
1006
|
+
return snap;
|
|
1007
|
+
}
|
|
1008
|
+
else {
|
|
1009
|
+
const { init, ...rest } = snap;
|
|
1010
|
+
return rest;
|
|
1011
|
+
}
|
|
979
1012
|
});
|
|
980
1013
|
}
|
|
981
1014
|
export { default as LinearGenomeView, default as ReactComponent, } from './components/LinearGenomeView';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-linear-genome-view",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "JBrowse 2 linear genome view",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"useSrc": "node ../../scripts/useSrc.js"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@jbrowse/core": "^3.
|
|
41
|
+
"@jbrowse/core": "^3.2.0",
|
|
42
42
|
"@mui/icons-material": "^6.0.0",
|
|
43
43
|
"@mui/material": "^6.0.0",
|
|
44
44
|
"@types/file-saver": "^2.0.1",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"access": "public"
|
|
59
59
|
},
|
|
60
60
|
"module": "esm/index.js",
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "c750e3f56706a490c19ba75abd807fec5e38aebf"
|
|
62
62
|
}
|