@jbrowse/plugin-linear-genome-view 4.2.1 → 4.3.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/esm/LinearGenomeView/afterAttach.js +45 -7
- package/esm/LinearGenomeView/components/Highlight.d.ts +2 -6
- package/esm/LinearGenomeView/components/Highlight.js +29 -77
- package/esm/LinearGenomeView/components/HighlightBand.d.ts +8 -0
- package/esm/LinearGenomeView/components/HighlightBand.js +23 -0
- package/esm/LinearGenomeView/components/OverviewHighlight.js +3 -1
- package/esm/LinearGenomeView/components/RefNameAutocomplete/AutocompleteTextField.d.ts +1 -4
- package/esm/LinearGenomeView/components/RefNameAutocomplete/AutocompleteTextField.js +3 -7
- package/esm/LinearGenomeView/components/RefNameAutocomplete/index.js +21 -9
- package/esm/LinearGenomeView/components/TracksContainer.js +1 -1
- package/esm/LinearGenomeView/index.d.ts +1 -0
- package/esm/LinearGenomeView/index.js +1 -0
- package/esm/LinearGenomeView/model.d.ts +18 -0
- package/esm/LinearGenomeView/model.js +32 -1
- package/esm/LinearGenomeView/types.d.ts +3 -1
- package/esm/index.d.ts +1 -1
- package/esm/index.js +1 -1
- package/esm/searchUtils.js +7 -5
- package/package.json +6 -6
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { getSession, localStorageSetItem, parseLocString, } from '@jbrowse/core/util';
|
|
2
2
|
import { addDisposer } from '@jbrowse/mobx-state-tree';
|
|
3
3
|
import { autorun, when } from 'mobx';
|
|
4
|
+
function tryParseJson(s) {
|
|
5
|
+
try {
|
|
6
|
+
const v = JSON.parse(s);
|
|
7
|
+
return v && typeof v === 'object'
|
|
8
|
+
? v
|
|
9
|
+
: undefined;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
4
15
|
export function setupInitAutorun(self) {
|
|
5
16
|
addDisposer(self, autorun(async function initAutorun() {
|
|
6
17
|
const { init, initialized } = self;
|
|
@@ -65,18 +76,45 @@ export function setupInitAutorun(self) {
|
|
|
65
76
|
if (init.nav !== undefined) {
|
|
66
77
|
self.setHideHeader(!init.nav);
|
|
67
78
|
}
|
|
79
|
+
if (self.highlight.length) {
|
|
80
|
+
const fallback = self.assemblyNames[0];
|
|
81
|
+
if (fallback) {
|
|
82
|
+
const normalized = self.highlight.map(h => h.assemblyName ? h : { ...h, assemblyName: fallback });
|
|
83
|
+
if (normalized.some((h, i) => h !== self.highlight[i])) {
|
|
84
|
+
self.setHighlight(normalized);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
68
88
|
if (init.highlight) {
|
|
69
89
|
for (const h of init.highlight) {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
90
|
+
const json = h.trim().startsWith('{') && tryParseJson(h);
|
|
91
|
+
if (json &&
|
|
92
|
+
typeof json.refName === 'string' &&
|
|
93
|
+
typeof json.start === 'number' &&
|
|
94
|
+
typeof json.end === 'number') {
|
|
73
95
|
self.addToHighlights({
|
|
74
|
-
|
|
75
|
-
start,
|
|
76
|
-
end,
|
|
77
|
-
assemblyName:
|
|
96
|
+
refName: json.refName,
|
|
97
|
+
start: json.start,
|
|
98
|
+
end: json.end,
|
|
99
|
+
assemblyName: typeof json.assemblyName === 'string'
|
|
100
|
+
? json.assemblyName
|
|
101
|
+
: init.assembly,
|
|
102
|
+
color: typeof json.color === 'string' ? json.color : undefined,
|
|
103
|
+
label: typeof json.label === 'string' ? json.label : undefined,
|
|
78
104
|
});
|
|
79
105
|
}
|
|
106
|
+
else {
|
|
107
|
+
const p = parseLocString(h, refName => assemblyManager.isValidRefName(refName, init.assembly));
|
|
108
|
+
const { start, end } = p;
|
|
109
|
+
if (start !== undefined && end !== undefined) {
|
|
110
|
+
self.addToHighlights({
|
|
111
|
+
...p,
|
|
112
|
+
start,
|
|
113
|
+
end,
|
|
114
|
+
assemblyName: init.assembly,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
80
118
|
}
|
|
81
119
|
}
|
|
82
120
|
self.setInit(undefined);
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import type { LinearGenomeViewModel } from '../model.ts';
|
|
2
|
+
import type { HighlightType } from '../types.ts';
|
|
2
3
|
type LGV = LinearGenomeViewModel;
|
|
3
4
|
declare const Highlight: ({ model, highlight, }: {
|
|
4
5
|
model: LGV;
|
|
5
|
-
highlight:
|
|
6
|
-
assemblyName: string;
|
|
7
|
-
refName: string;
|
|
8
|
-
start: number;
|
|
9
|
-
end: number;
|
|
10
|
-
};
|
|
6
|
+
highlight: HighlightType;
|
|
11
7
|
}) => import("react/jsx-runtime").JSX.Element | null;
|
|
12
8
|
export default Highlight;
|
|
@@ -1,90 +1,42 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
3
|
-
import { Menu } from '@jbrowse/core/ui';
|
|
2
|
+
import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
|
|
4
3
|
import { getSession } from '@jbrowse/core/util';
|
|
5
4
|
import { colord } from '@jbrowse/core/util/colord';
|
|
6
|
-
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
7
5
|
import BookmarkIcon from '@mui/icons-material/Bookmark';
|
|
8
6
|
import CloseIcon from '@mui/icons-material/Close';
|
|
9
7
|
import LinkIcon from '@mui/icons-material/Link';
|
|
10
|
-
import {
|
|
8
|
+
import { Box, Tooltip, Typography, useTheme } from '@mui/material';
|
|
11
9
|
import { observer } from 'mobx-react';
|
|
12
|
-
|
|
13
|
-
highlight: {
|
|
14
|
-
height: '100%',
|
|
15
|
-
position: 'absolute',
|
|
16
|
-
left: 0,
|
|
17
|
-
overflow: 'hidden',
|
|
18
|
-
background: colord(theme.palette.highlight.main).alpha(0.35).toRgbString(),
|
|
19
|
-
},
|
|
20
|
-
linkIcon: {
|
|
21
|
-
color: colord(theme.palette.highlight.main).darken(0.2).toRgbString(),
|
|
22
|
-
},
|
|
23
|
-
z3: {
|
|
24
|
-
zIndex: 3,
|
|
25
|
-
},
|
|
26
|
-
}));
|
|
10
|
+
import HighlightBand from "./HighlightBand.js";
|
|
27
11
|
const Highlight = observer(function Highlight({ model, highlight, }) {
|
|
28
|
-
const
|
|
29
|
-
const [open, setOpen] = useState(false);
|
|
30
|
-
const anchorEl = useRef(null);
|
|
12
|
+
const theme = useTheme();
|
|
31
13
|
const session = getSession(model);
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
coord: r.start,
|
|
43
|
-
});
|
|
44
|
-
const e = model.bpToPx({
|
|
45
|
-
refName: r.refName,
|
|
46
|
-
coord: r.end,
|
|
47
|
-
});
|
|
48
|
-
return s && e
|
|
49
|
-
? {
|
|
50
|
-
width: Math.max(Math.abs(e.offsetPx - s.offsetPx), 3),
|
|
51
|
-
left: Math.min(s.offsetPx, e.offsetPx) - model.offsetPx,
|
|
52
|
-
}
|
|
53
|
-
: undefined;
|
|
54
|
-
};
|
|
55
|
-
const asm = assemblyManager.get(highlight.assemblyName);
|
|
56
|
-
const h = mapCoords({
|
|
57
|
-
...highlight,
|
|
58
|
-
refName: asm?.getCanonicalRefName(highlight.refName) ?? highlight.refName,
|
|
59
|
-
});
|
|
60
|
-
return h ? (_jsxs("div", { className: classes.highlight, style: {
|
|
61
|
-
transform: `translateX(${h.left}px)`,
|
|
62
|
-
width: h.width,
|
|
63
|
-
}, children: [_jsx(Tooltip, { title: "Highlighted from URL parameter", arrow: true, children: _jsx(IconButton, { ref: anchorEl, className: classes.z3, onClick: () => {
|
|
64
|
-
setOpen(true);
|
|
65
|
-
}, children: _jsx(LinkIcon, { fontSize: "small", className: classes.linkIcon }) }) }), _jsx(Menu, { anchorEl: anchorEl.current, onMenuItemClick: (_event, callback) => {
|
|
66
|
-
callback();
|
|
67
|
-
handleClose();
|
|
68
|
-
}, open: open, onClose: handleClose, menuItems: [
|
|
69
|
-
{
|
|
70
|
-
label: 'Dismiss highlight',
|
|
71
|
-
icon: CloseIcon,
|
|
72
|
-
onClick: () => {
|
|
73
|
-
dismissHighlight();
|
|
74
|
-
},
|
|
14
|
+
const coords = model.getHighlightCoords(highlight);
|
|
15
|
+
const bandColor = highlight.color
|
|
16
|
+
? colord(highlight.color)
|
|
17
|
+
: colord(theme.palette.highlight.main).alpha(0.35);
|
|
18
|
+
return coords ? (_jsx(HighlightBand, { coords: coords, background: bandColor.toRgbString(), children: _jsx(CascadingMenuButton, { menuItems: [
|
|
19
|
+
{
|
|
20
|
+
label: 'Dismiss highlight',
|
|
21
|
+
icon: CloseIcon,
|
|
22
|
+
onClick: () => {
|
|
23
|
+
model.removeHighlight(highlight);
|
|
75
24
|
},
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: 'Bookmark highlighted region',
|
|
28
|
+
icon: BookmarkIcon,
|
|
29
|
+
onClick: () => {
|
|
30
|
+
const bookmarkWidget = (session.widgets.get('GridBookmark') ??
|
|
31
|
+
session.addWidget('GridBookmarkWidget', 'GridBookmark'));
|
|
32
|
+
bookmarkWidget.addBookmark({
|
|
33
|
+
...highlight,
|
|
34
|
+
assemblyName: highlight.assemblyName ?? model.assemblyNames[0],
|
|
35
|
+
});
|
|
36
|
+
session.showWidget(bookmarkWidget);
|
|
37
|
+
model.removeHighlight(highlight);
|
|
87
38
|
},
|
|
88
|
-
|
|
39
|
+
},
|
|
40
|
+
], children: _jsx(Tooltip, { title: highlight.label ?? 'Highlighted region', arrow: true, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [_jsx(LinkIcon, { fontSize: "small", sx: { color: bandColor.alpha(0.8).toRgbString() } }), highlight.label && model.labelsVisible ? (_jsx(Typography, { variant: "caption", noWrap: true, children: highlight.label })) : null] }) }) }) })) : null;
|
|
89
41
|
});
|
|
90
42
|
export default Highlight;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
3
|
+
const useStyles = makeStyles()({
|
|
4
|
+
highlight: {
|
|
5
|
+
height: '100%',
|
|
6
|
+
position: 'absolute',
|
|
7
|
+
left: 0,
|
|
8
|
+
overflow: 'hidden',
|
|
9
|
+
zIndex: 1,
|
|
10
|
+
pointerEvents: 'none',
|
|
11
|
+
},
|
|
12
|
+
chip: {
|
|
13
|
+
pointerEvents: 'auto',
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
export default function HighlightBand({ coords, background, children, }) {
|
|
17
|
+
const { classes } = useStyles();
|
|
18
|
+
return (_jsx("div", { className: classes.highlight, style: {
|
|
19
|
+
transform: `translateX(${coords.left}px)`,
|
|
20
|
+
width: coords.width,
|
|
21
|
+
background,
|
|
22
|
+
}, children: coords.width > 3 && children ? (_jsx("div", { className: classes.chip, children: children })) : null }));
|
|
23
|
+
}
|
|
@@ -20,7 +20,9 @@ const OverviewHighlight = observer(function OverviewHighlight({ model, overview,
|
|
|
20
20
|
const { assemblyManager } = session;
|
|
21
21
|
return highlight
|
|
22
22
|
.map(r => {
|
|
23
|
-
const asm =
|
|
23
|
+
const asm = r.assemblyName
|
|
24
|
+
? assemblyManager.get(r.assemblyName)
|
|
25
|
+
: undefined;
|
|
24
26
|
const refName = asm?.getCanonicalRefName(r.refName) ?? r.refName;
|
|
25
27
|
const s = overview.bpToPx({
|
|
26
28
|
...r,
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { AutocompleteRenderInputParams, TextFieldProps as TFP } from '@mui/material';
|
|
2
|
-
export default function AutocompleteTextField({ TextFieldProps,
|
|
2
|
+
export default function AutocompleteTextField({ TextFieldProps, params, }: {
|
|
3
3
|
TextFieldProps: TFP;
|
|
4
|
-
inputBoxVal: string;
|
|
5
4
|
params: AutocompleteRenderInputParams;
|
|
6
|
-
setInputValue: (arg: string) => void;
|
|
7
|
-
setCurrentSearch: (arg: string) => void;
|
|
8
5
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { TextField } from '@mui/material';
|
|
3
|
-
export default function AutocompleteTextField({ TextFieldProps,
|
|
3
|
+
export default function AutocompleteTextField({ TextFieldProps, params, }) {
|
|
4
4
|
const { helperText, slotProps = {} } = TextFieldProps;
|
|
5
5
|
const { ref: inputRef, ...restInputProps } = params.InputProps;
|
|
6
6
|
const { InputProps: _InputProps, ...restParams } = params;
|
|
7
|
-
return (_jsx(TextField, {
|
|
8
|
-
setInputValue(inputBoxVal);
|
|
9
|
-
}, ...restParams, ...TextFieldProps, inputRef: inputRef, size: "small", helperText: helperText, slotProps: {
|
|
7
|
+
return (_jsx(TextField, { ...restParams, ...TextFieldProps, inputRef: inputRef, size: "small", helperText: helperText, slotProps: {
|
|
10
8
|
input: {
|
|
11
9
|
...restInputProps,
|
|
12
10
|
...slotProps.input,
|
|
13
11
|
},
|
|
14
|
-
}, placeholder: "Search for location"
|
|
15
|
-
setCurrentSearch(e.target.value);
|
|
16
|
-
} }));
|
|
12
|
+
}, placeholder: "Search for location" }));
|
|
17
13
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import BaseResult, { RefSequenceResult, } from '@jbrowse/core/TextSearch/BaseResults';
|
|
4
4
|
import { getSession, measureText, useDebounce } from '@jbrowse/core/util';
|
|
5
5
|
import { Autocomplete } from '@mui/material';
|
|
@@ -11,12 +11,14 @@ const RefNameAutocomplete = observer(function RefNameAutocomplete({ model, onSel
|
|
|
11
11
|
const { assemblyManager } = session;
|
|
12
12
|
const [open, setOpen] = useState(false);
|
|
13
13
|
const [loaded, setLoaded] = useState(true);
|
|
14
|
-
const [currentSearch, setCurrentSearch] = useState('');
|
|
15
14
|
const [inputValue, setInputValue] = useState('');
|
|
15
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
16
16
|
const [searchOptions, setSearchOptions] = useState();
|
|
17
|
-
const debouncedSearch = useDebounce(
|
|
17
|
+
const debouncedSearch = useDebounce(searchQuery, 50);
|
|
18
18
|
const assembly = assemblyName ? assemblyManager.get(assemblyName) : undefined;
|
|
19
19
|
const { coarseVisibleLocStrings, hasDisplayedRegions } = model;
|
|
20
|
+
const fetchResultsRef = useRef(fetchResults);
|
|
21
|
+
fetchResultsRef.current = fetchResults;
|
|
20
22
|
useEffect(() => {
|
|
21
23
|
const isCurrent = { cancelled: false };
|
|
22
24
|
(async () => {
|
|
@@ -25,7 +27,7 @@ const RefNameAutocomplete = observer(function RefNameAutocomplete({ model, onSel
|
|
|
25
27
|
return;
|
|
26
28
|
}
|
|
27
29
|
setLoaded(false);
|
|
28
|
-
const results = await
|
|
30
|
+
const results = await fetchResultsRef.current(debouncedSearch);
|
|
29
31
|
if (!isCurrent.cancelled) {
|
|
30
32
|
setSearchOptions(getDeduplicatedResult(results));
|
|
31
33
|
}
|
|
@@ -45,7 +47,7 @@ const RefNameAutocomplete = observer(function RefNameAutocomplete({ model, onSel
|
|
|
45
47
|
return () => {
|
|
46
48
|
isCurrent.cancelled = true;
|
|
47
49
|
};
|
|
48
|
-
}, [assemblyName,
|
|
50
|
+
}, [assemblyName, debouncedSearch, session]);
|
|
49
51
|
const inputBoxVal = coarseVisibleLocStrings || value || '';
|
|
50
52
|
const regions = assembly?.regions;
|
|
51
53
|
const regionOptions = useMemo(() => regions?.map(region => ({
|
|
@@ -59,16 +61,26 @@ const RefNameAutocomplete = observer(function RefNameAutocomplete({ model, onSel
|
|
|
59
61
|
return (_jsx(Autocomplete, { "data-testid": "autocomplete", disableListWrap: true, disableClearable: true, disabled: !assemblyName, freeSolo: true, includeInputInList: true, selectOnFocus: true, style: {
|
|
60
62
|
...style,
|
|
61
63
|
width: Math.min(Math.max(measureText(inputBoxVal, 14) + 100, minWidth), maxWidth),
|
|
62
|
-
}, value: inputBoxVal, loading: !loaded, inputValue: inputValue, onInputChange: (_event, newInputValue) => {
|
|
64
|
+
}, value: inputBoxVal, loading: !loaded, inputValue: inputValue, onInputChange: (_event, newInputValue, reason) => {
|
|
63
65
|
setInputValue(newInputValue);
|
|
64
|
-
|
|
66
|
+
if (reason === 'input') {
|
|
67
|
+
setSearchQuery(newInputValue);
|
|
68
|
+
onChange?.(newInputValue);
|
|
69
|
+
}
|
|
70
|
+
else if (reason === 'selectOption' || reason === 'clear') {
|
|
71
|
+
onChange?.(newInputValue);
|
|
72
|
+
setSearchQuery('');
|
|
73
|
+
}
|
|
74
|
+
else if (reason === 'blur') {
|
|
75
|
+
setSearchQuery('');
|
|
76
|
+
}
|
|
65
77
|
}, loadingText: "loading results", open: open, onOpen: () => {
|
|
66
78
|
setOpen(true);
|
|
67
79
|
}, onClose: () => {
|
|
68
80
|
setOpen(false);
|
|
69
81
|
setLoaded(true);
|
|
70
82
|
if (hasDisplayedRegions) {
|
|
71
|
-
|
|
83
|
+
setSearchQuery('');
|
|
72
84
|
setSearchOptions(undefined);
|
|
73
85
|
}
|
|
74
86
|
}, onChange: (_event, selectedOption) => {
|
|
@@ -84,6 +96,6 @@ const RefNameAutocomplete = observer(function RefNameAutocomplete({ model, onSel
|
|
|
84
96
|
onSelect?.(selectedOption.result);
|
|
85
97
|
}
|
|
86
98
|
setInputValue(inputBoxVal);
|
|
87
|
-
}, options: searchOptions?.length ? searchOptions : regionOptions, getOptionDisabled: option => option.group === 'limitOption', filterOptions:
|
|
99
|
+
}, options: searchOptions?.length ? searchOptions : regionOptions, getOptionDisabled: option => option.group === 'limitOption', filterOptions: opts => getFiltered(opts, searchQuery), renderInput: params => (_jsx(AutocompleteTextField, { params: params, TextFieldProps: TextFieldProps })), getOptionLabel: opt => typeof opt === 'string' ? opt : opt.result.getDisplayString() }));
|
|
88
100
|
});
|
|
89
101
|
export default RefNameAutocomplete;
|
|
@@ -44,6 +44,6 @@ const TracksContainer = observer(function TracksContainer({ children, model, })
|
|
|
44
44
|
} }) }), _jsx(HighlightGroup, { model: model }), additional, children] }));
|
|
45
45
|
});
|
|
46
46
|
const HighlightGroup = observer(function HighlightGroup({ model, }) {
|
|
47
|
-
return model.highlight.length ? (_jsx(Suspense, { fallback: null, children: model.highlight.map((highlight, idx) => (_jsx(Highlight, { model: model, highlight: highlight }, `${JSON.stringify(highlight)}-${idx}`))) })) : null;
|
|
47
|
+
return model.highlightsVisible && model.highlight.length ? (_jsx(Suspense, { fallback: null, children: model.highlight.map((highlight, idx) => (_jsx(Highlight, { model: model, highlight: highlight }, `${JSON.stringify(highlight)}-${idx}`))) })) : null;
|
|
48
48
|
});
|
|
49
49
|
export default TracksContainer;
|
|
@@ -2,3 +2,4 @@ import type PluginManager from '@jbrowse/core/PluginManager';
|
|
|
2
2
|
export default function LinearGenomeViewF(pluginManager: PluginManager): void;
|
|
3
3
|
export * from './model.ts';
|
|
4
4
|
export * from './types.ts';
|
|
5
|
+
export { default as HighlightBand } from './components/HighlightBand.tsx';
|
|
@@ -28,6 +28,8 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
28
28
|
trackLabels: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
29
29
|
showGridlines: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
30
30
|
highlight: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IType<HighlightType, HighlightType, HighlightType>>, [undefined]>;
|
|
31
|
+
highlightsVisible: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
32
|
+
labelsVisible: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
31
33
|
colorByCDS: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
32
34
|
showTrackOutlines: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
33
35
|
init: import("@jbrowse/mobx-state-tree").IType<InitState | undefined, InitState | undefined, InitState | undefined>;
|
|
@@ -119,6 +121,9 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
119
121
|
addToHighlights(highlight: HighlightType): void;
|
|
120
122
|
setHighlight(highlight?: HighlightType[]): void;
|
|
121
123
|
removeHighlight(highlight: HighlightType): void;
|
|
124
|
+
updateHighlight(old: HighlightType, updates: Partial<HighlightType>): void;
|
|
125
|
+
setHighlightsVisible(arg: boolean): void;
|
|
126
|
+
setLabelsVisible(arg: boolean): void;
|
|
122
127
|
setVolatileGuides(guides: VolatileGuide[]): void;
|
|
123
128
|
scrollTo(offsetPx: number): number;
|
|
124
129
|
zoomTo(bpPerPx: number, offset?: number, centerAtOffset?: boolean): number;
|
|
@@ -199,6 +204,15 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
199
204
|
index: number;
|
|
200
205
|
offsetPx: number;
|
|
201
206
|
} | undefined;
|
|
207
|
+
getHighlightCoords(region: {
|
|
208
|
+
assemblyName?: string;
|
|
209
|
+
refName: string;
|
|
210
|
+
start: number;
|
|
211
|
+
end: number;
|
|
212
|
+
}): {
|
|
213
|
+
width: number;
|
|
214
|
+
left: number;
|
|
215
|
+
} | undefined;
|
|
202
216
|
centerAt(coord: number, refName: string, regionNumber?: number): void;
|
|
203
217
|
pxToBp(px: number): {
|
|
204
218
|
coord: number;
|
|
@@ -248,6 +262,8 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
248
262
|
trackLabels: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
249
263
|
showGridlines: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
250
264
|
highlight: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IType<HighlightType, HighlightType, HighlightType>>, [undefined]>;
|
|
265
|
+
highlightsVisible: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
266
|
+
labelsVisible: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
251
267
|
colorByCDS: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
252
268
|
showTrackOutlines: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
253
269
|
init: import("@jbrowse/mobx-state-tree").IType<InitState | undefined, InitState | undefined, InitState | undefined>;
|
|
@@ -271,6 +287,8 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
271
287
|
trackLabels: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
272
288
|
showGridlines: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
273
289
|
highlight: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IType<HighlightType, HighlightType, HighlightType>>, [undefined]>;
|
|
290
|
+
highlightsVisible: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
291
|
+
labelsVisible: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
274
292
|
colorByCDS: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
275
293
|
showTrackOutlines: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
276
294
|
init: import("@jbrowse/mobx-state-tree").IType<InitState | undefined, InitState | undefined, InitState | undefined>;
|
|
@@ -42,6 +42,8 @@ export function stateModelFactory(pluginManager) {
|
|
|
42
42
|
trackLabels: types.optional(types.string, () => localStorageGetItem('lgv-trackLabels') || ''),
|
|
43
43
|
showGridlines: true,
|
|
44
44
|
highlight: types.optional(types.array(types.frozen()), []),
|
|
45
|
+
highlightsVisible: types.optional(types.boolean, true),
|
|
46
|
+
labelsVisible: types.optional(types.boolean, true),
|
|
45
47
|
colorByCDS: types.optional(types.boolean, () => localStorageGetBoolean('lgv-colorByCDS', false)),
|
|
46
48
|
showTrackOutlines: types.optional(types.boolean, () => localStorageGetBoolean('lgv-showTrackOutlines', true)),
|
|
47
49
|
init: types.frozen(),
|
|
@@ -351,6 +353,18 @@ export function stateModelFactory(pluginManager) {
|
|
|
351
353
|
removeHighlight(highlight) {
|
|
352
354
|
self.highlight.remove(highlight);
|
|
353
355
|
},
|
|
356
|
+
updateHighlight(old, updates) {
|
|
357
|
+
const idx = self.highlight.indexOf(old);
|
|
358
|
+
if (idx !== -1) {
|
|
359
|
+
self.highlight.splice(idx, 1, { ...old, ...updates });
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
setHighlightsVisible(arg) {
|
|
363
|
+
self.highlightsVisible = arg;
|
|
364
|
+
},
|
|
365
|
+
setLabelsVisible(arg) {
|
|
366
|
+
self.labelsVisible = arg;
|
|
367
|
+
},
|
|
354
368
|
setVolatileGuides(guides) {
|
|
355
369
|
self.volatileGuides = guides;
|
|
356
370
|
},
|
|
@@ -826,6 +840,21 @@ export function stateModelFactory(pluginManager) {
|
|
|
826
840
|
bpToPx({ refName, coord, regionNumber, }) {
|
|
827
841
|
return bpToPx({ refName, coord, regionNumber, self });
|
|
828
842
|
},
|
|
843
|
+
getHighlightCoords(region) {
|
|
844
|
+
const { assemblyManager } = getSession(self);
|
|
845
|
+
const asm = region.assemblyName
|
|
846
|
+
? assemblyManager.get(region.assemblyName)
|
|
847
|
+
: undefined;
|
|
848
|
+
const refName = asm?.getCanonicalRefName(region.refName) ?? region.refName;
|
|
849
|
+
const s = this.bpToPx({ refName, coord: region.start });
|
|
850
|
+
const e = this.bpToPx({ refName, coord: region.end });
|
|
851
|
+
return s && e
|
|
852
|
+
? {
|
|
853
|
+
width: Math.max(Math.abs(e.offsetPx - s.offsetPx), 3),
|
|
854
|
+
left: Math.min(s.offsetPx, e.offsetPx) - self.offsetPx,
|
|
855
|
+
}
|
|
856
|
+
: undefined;
|
|
857
|
+
},
|
|
829
858
|
centerAt(coord, refName, regionNumber) {
|
|
830
859
|
const centerPx = this.bpToPx({
|
|
831
860
|
refName,
|
|
@@ -877,7 +906,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
877
906
|
if (!snap) {
|
|
878
907
|
return snap;
|
|
879
908
|
}
|
|
880
|
-
const { init, offsetPx, bpPerPx, hideHeader, hideHeaderOverview, hideNoTracksActive, showGridlines, trackSelectorType, displayedRegions, highlight, showCenterLine, showCytobandsSetting, trackLabels, colorByCDS, showTrackOutlines, ...rest } = snap;
|
|
909
|
+
const { init, offsetPx, bpPerPx, hideHeader, hideHeaderOverview, hideNoTracksActive, showGridlines, trackSelectorType, displayedRegions, highlight, showCenterLine, showCytobandsSetting, trackLabels, colorByCDS, showTrackOutlines, highlightsVisible, labelsVisible, ...rest } = snap;
|
|
881
910
|
return {
|
|
882
911
|
...rest,
|
|
883
912
|
...(offsetPx ? { offsetPx } : {}),
|
|
@@ -894,6 +923,8 @@ export function stateModelFactory(pluginManager) {
|
|
|
894
923
|
...(trackLabels ? { trackLabels } : {}),
|
|
895
924
|
...(colorByCDS ? { colorByCDS } : {}),
|
|
896
925
|
...(!showTrackOutlines ? { showTrackOutlines } : {}),
|
|
926
|
+
...(!highlightsVisible ? { highlightsVisible } : {}),
|
|
927
|
+
...(!labelsVisible ? { labelsVisible } : {}),
|
|
897
928
|
};
|
|
898
929
|
});
|
|
899
930
|
}
|
|
@@ -29,8 +29,10 @@ export interface ExportSvgOptions {
|
|
|
29
29
|
export interface HighlightType {
|
|
30
30
|
start: number;
|
|
31
31
|
end: number;
|
|
32
|
-
assemblyName
|
|
32
|
+
assemblyName?: string;
|
|
33
33
|
refName: string;
|
|
34
|
+
color?: string;
|
|
35
|
+
label?: string;
|
|
34
36
|
}
|
|
35
37
|
export interface NavLocation {
|
|
36
38
|
refName: string;
|
package/esm/index.d.ts
CHANGED
|
@@ -1245,7 +1245,7 @@ export type { BaseLinearDisplayModel, BlockModel, ExportSvgDisplayOptions, Float
|
|
|
1245
1245
|
export { configSchemaFactory as linearBareDisplayConfigSchemaFactory, stateModelFactory as linearBareDisplayStateModelFactory, } from './LinearBareDisplay/index.ts';
|
|
1246
1246
|
export { BaseLinearDisplay, BaseLinearDisplayComponent, BlockMsg, FeatureDensityMixin, FloatingLegend, NonBlockCanvasDisplayComponent, NonBlockCanvasDisplayMixin, SVGLegend, TooLargeMessage, TrackHeightMixin, baseLinearDisplayConfigSchema, calculateSvgLegendWidth, createSubfeatureLabelMetadata, drawCanvasImageData, } from './BaseLinearDisplay/index.ts';
|
|
1247
1247
|
export type { NonBlockCanvasDisplayMixinType, NonBlockCanvasDisplayModel, } from './BaseLinearDisplay/index.ts';
|
|
1248
|
-
export { type LinearGenomeViewModel, type LinearGenomeViewStateModel, RefNameAutocomplete, SearchBox, } from './LinearGenomeView/index.ts';
|
|
1248
|
+
export { HighlightBand, type LinearGenomeViewModel, type LinearGenomeViewStateModel, RefNameAutocomplete, SearchBox, } from './LinearGenomeView/index.ts';
|
|
1249
1249
|
export { fetchResults } from './searchUtils.ts';
|
|
1250
1250
|
export type { BpOffset, ExportSvgOptions, HighlightType, InitState, NavLocation, VolatileGuide, } from './LinearGenomeView/types.ts';
|
|
1251
1251
|
export { SVGGridlines, SVGRuler, SVGTracks, renderToSvg, } from './LinearGenomeView/svgcomponents/SVGLinearGenomeView.tsx';
|
package/esm/index.js
CHANGED
|
@@ -54,7 +54,7 @@ export default class LinearGenomeViewPlugin extends Plugin {
|
|
|
54
54
|
}
|
|
55
55
|
export { configSchemaFactory as linearBareDisplayConfigSchemaFactory, stateModelFactory as linearBareDisplayStateModelFactory, } from "./LinearBareDisplay/index.js";
|
|
56
56
|
export { BaseLinearDisplay, BaseLinearDisplayComponent, BlockMsg, FeatureDensityMixin, FloatingLegend, NonBlockCanvasDisplayComponent, NonBlockCanvasDisplayMixin, SVGLegend, TooLargeMessage, TrackHeightMixin, baseLinearDisplayConfigSchema, calculateSvgLegendWidth, createSubfeatureLabelMetadata, drawCanvasImageData, } from "./BaseLinearDisplay/index.js";
|
|
57
|
-
export { RefNameAutocomplete, SearchBox, } from "./LinearGenomeView/index.js";
|
|
57
|
+
export { HighlightBand, RefNameAutocomplete, SearchBox, } from "./LinearGenomeView/index.js";
|
|
58
58
|
export { fetchResults } from "./searchUtils.js";
|
|
59
59
|
export { SVGGridlines, SVGRuler, SVGTracks, renderToSvg, } from "./LinearGenomeView/svgcomponents/SVGLinearGenomeView.js";
|
|
60
60
|
export { totalHeight } from "./LinearGenomeView/svgcomponents/util.js";
|
package/esm/searchUtils.js
CHANGED
|
@@ -58,11 +58,13 @@ export async function fetchResults({ queryString, searchType, searchScope, rankS
|
|
|
58
58
|
queryString,
|
|
59
59
|
searchType,
|
|
60
60
|
}, searchScope, rankSearchResults);
|
|
61
|
-
const refNameResults =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
const refNameResults = [
|
|
62
|
+
...new Set(assembly?.allRefNames
|
|
63
|
+
?.filter(ref => ref.toLowerCase().startsWith(queryString.toLowerCase()))
|
|
64
|
+
.map(ref => assembly.getCanonicalRefName(ref) ?? ref)
|
|
65
|
+
.slice(0, 10)),
|
|
66
|
+
].map(r => new BaseResult({ label: r, matchedObject: { refName: r } }));
|
|
67
|
+
return dedupe([...refNameResults, ...(textSearchResults ?? [])], elt => elt.getId());
|
|
66
68
|
}
|
|
67
69
|
export function splitLast(str, split) {
|
|
68
70
|
const lastIndex = str.lastIndexOf(split);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-linear-genome-view",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "JBrowse 2 linear genome view",
|
|
6
6
|
"keywords": [
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@jbrowse/mobx-state-tree": "^5.6.0",
|
|
25
|
-
"@mui/icons-material": "^7.3.
|
|
26
|
-
"@mui/material": "^7.3.
|
|
25
|
+
"@mui/icons-material": "^7.3.11",
|
|
26
|
+
"@mui/material": "^7.3.11",
|
|
27
27
|
"@types/file-saver-es": "^2.0.3",
|
|
28
28
|
"copy-to-clipboard": "^3.3.3",
|
|
29
29
|
"file-saver-es": "^2.0.5",
|
|
30
|
-
"mobx": "^6.15.
|
|
30
|
+
"mobx": "^6.15.3",
|
|
31
31
|
"mobx-react": "^9.2.1",
|
|
32
|
-
"@jbrowse/core": "^4.
|
|
33
|
-
"@jbrowse/
|
|
32
|
+
"@jbrowse/product-core": "^4.3.0",
|
|
33
|
+
"@jbrowse/core": "^4.3.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": ">=18.0.0",
|