@jbrowse/plugin-linear-genome-view 3.2.0 → 3.4.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/components/LinearBlocks.js +1 -1
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +1 -1
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +22 -8
- package/dist/LinearBareDisplay/model.d.ts +1 -1
- package/dist/LinearBasicDisplay/components/AddFiltersDialog.js +1 -1
- package/dist/LinearBasicDisplay/model.d.ts +1 -1
- package/dist/LinearBasicDisplay/model.js +8 -2
- package/dist/LinearGenomeView/components/Cytobands.js +18 -4
- package/dist/LinearGenomeView/components/GetSequenceDialog.js +3 -2
- package/dist/LinearGenomeView/components/HeaderZoomControls.js +8 -2
- package/dist/LinearGenomeView/components/ImportForm.js +1 -1
- package/dist/LinearGenomeView/components/OverviewRubberband.js +0 -6
- package/dist/LinearGenomeView/components/OverviewRubberbandHoverTooltip.js +1 -9
- package/dist/LinearGenomeView/components/RefNameAutocomplete/index.js +16 -10
- package/dist/LinearGenomeView/components/RubberbandSpan.js +2 -2
- package/dist/LinearGenomeView/components/SearchBox.d.ts +1 -1
- package/dist/LinearGenomeView/components/SearchBox.js +29 -16
- package/dist/LinearGenomeView/components/useWheelScroll.js +13 -1
- package/dist/LinearGenomeView/components/util.d.ts +1 -0
- package/dist/LinearGenomeView/components/util.js +7 -4
- package/dist/LinearGenomeView/model.d.ts +4 -3
- package/dist/LinearGenomeView/model.js +12 -10
- package/dist/LinearGenomeView/util.d.ts +6 -1
- package/dist/LinearGenomeView/util.js +20 -6
- package/dist/index.d.ts +1 -1
- package/dist/searchUtils.js +1 -1
- package/esm/BaseLinearDisplay/components/LinearBlocks.js +1 -1
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +1 -1
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js +24 -10
- package/esm/LinearBareDisplay/model.d.ts +1 -1
- package/esm/LinearBasicDisplay/components/AddFiltersDialog.js +1 -1
- package/esm/LinearBasicDisplay/model.d.ts +1 -1
- package/esm/LinearBasicDisplay/model.js +8 -2
- package/esm/LinearGenomeView/components/Cytobands.js +18 -4
- package/esm/LinearGenomeView/components/GetSequenceDialog.js +3 -2
- package/esm/LinearGenomeView/components/HeaderZoomControls.js +9 -3
- package/esm/LinearGenomeView/components/ImportForm.js +1 -1
- package/esm/LinearGenomeView/components/OverviewRubberband.js +0 -6
- package/esm/LinearGenomeView/components/OverviewRubberbandHoverTooltip.js +1 -9
- package/esm/LinearGenomeView/components/RefNameAutocomplete/index.js +16 -10
- package/esm/LinearGenomeView/components/RubberbandSpan.js +3 -3
- package/esm/LinearGenomeView/components/SearchBox.d.ts +1 -1
- package/esm/LinearGenomeView/components/SearchBox.js +29 -16
- package/esm/LinearGenomeView/components/useWheelScroll.js +13 -1
- package/esm/LinearGenomeView/components/util.d.ts +1 -0
- package/esm/LinearGenomeView/components/util.js +7 -4
- package/esm/LinearGenomeView/model.d.ts +4 -3
- package/esm/LinearGenomeView/model.js +12 -10
- package/esm/LinearGenomeView/util.d.ts +6 -1
- package/esm/LinearGenomeView/util.js +20 -6
- package/esm/index.d.ts +1 -1
- package/esm/searchUtils.js +1 -1
- package/package.json +5 -5
|
@@ -206,7 +206,7 @@ export declare const BaseLinearDisplay: import("mobx-state-tree").IModelType<{
|
|
|
206
206
|
} & {
|
|
207
207
|
addBlock(key: string, block: BaseBlock): void;
|
|
208
208
|
deleteBlock(key: string): void;
|
|
209
|
-
selectFeature(feature: Feature): void
|
|
209
|
+
selectFeature(feature: Feature): Promise<void>;
|
|
210
210
|
navToFeature(feature: Feature): void;
|
|
211
211
|
clearFeatureSelection(): void;
|
|
212
212
|
setFeatureIdUnderMouse(feature?: string): void;
|
|
@@ -138,15 +138,23 @@ function stateModelFactory() {
|
|
|
138
138
|
deleteBlock(key) {
|
|
139
139
|
self.blockState.delete(key);
|
|
140
140
|
},
|
|
141
|
-
selectFeature(feature) {
|
|
141
|
+
async selectFeature(feature) {
|
|
142
142
|
const session = (0, util_1.getSession)(self);
|
|
143
143
|
if ((0, util_1.isSessionModelWithWidgets)(session)) {
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
const { rpcManager } = session;
|
|
145
|
+
const sessionId = (0, tracks_1.getRpcSessionId)(self);
|
|
146
|
+
const track = (0, util_1.getContainingTrack)(self);
|
|
147
|
+
const view = (0, util_1.getContainingView)(self);
|
|
148
|
+
const adapterConfig = (0, configuration_1.getConf)(track, 'adapter');
|
|
149
|
+
const descriptions = await rpcManager.call(sessionId, 'CoreGetMetadata', {
|
|
150
|
+
adapterConfig,
|
|
148
151
|
});
|
|
149
|
-
session.showWidget(
|
|
152
|
+
session.showWidget(session.addWidget('BaseFeatureWidget', 'baseFeature', {
|
|
153
|
+
featureData: feature.toJSON(),
|
|
154
|
+
view,
|
|
155
|
+
track,
|
|
156
|
+
descriptions,
|
|
157
|
+
}));
|
|
150
158
|
}
|
|
151
159
|
if ((0, util_1.isSelectionContainer)(session)) {
|
|
152
160
|
session.setSelection(feature);
|
|
@@ -197,7 +205,11 @@ function stateModelFactory() {
|
|
|
197
205
|
icon: MenuOpen_1.default,
|
|
198
206
|
onClick: () => {
|
|
199
207
|
if (self.contextMenuFeature) {
|
|
200
|
-
self
|
|
208
|
+
self
|
|
209
|
+
.selectFeature(self.contextMenuFeature)
|
|
210
|
+
.catch((e) => {
|
|
211
|
+
(0, util_1.getSession)(e).notifyError(`${e}`, e);
|
|
212
|
+
});
|
|
201
213
|
}
|
|
202
214
|
},
|
|
203
215
|
},
|
|
@@ -228,7 +240,9 @@ function stateModelFactory() {
|
|
|
228
240
|
else {
|
|
229
241
|
const feature = self.features.get(f);
|
|
230
242
|
if (feature) {
|
|
231
|
-
self.selectFeature(feature)
|
|
243
|
+
self.selectFeature(feature).catch((e) => {
|
|
244
|
+
(0, util_1.getSession)(e).notifyError(`${e}`, e);
|
|
245
|
+
});
|
|
232
246
|
}
|
|
233
247
|
}
|
|
234
248
|
},
|
|
@@ -190,7 +190,7 @@ export declare function stateModelFactory(configSchema: AnyConfigurationSchemaTy
|
|
|
190
190
|
} & {
|
|
191
191
|
addBlock(key: string, block: import("@jbrowse/core/util/blockTypes").BaseBlock): void;
|
|
192
192
|
deleteBlock(key: string): void;
|
|
193
|
-
selectFeature(feature: import("@jbrowse/core/util").Feature): void
|
|
193
|
+
selectFeature(feature: import("@jbrowse/core/util").Feature): Promise<void>;
|
|
194
194
|
navToFeature(feature: import("@jbrowse/core/util").Feature): void;
|
|
195
195
|
clearFeatureSelection(): void;
|
|
196
196
|
setFeatureIdUnderMouse(feature?: string): void;
|
|
@@ -43,7 +43,7 @@ const AddFiltersDialog = (0, mobx_react_1.observer)(function ({ model, handleClo
|
|
|
43
43
|
setError(e);
|
|
44
44
|
}
|
|
45
45
|
}, [data]);
|
|
46
|
-
return ((0, jsx_runtime_1.jsxs)(ui_1.Dialog, { maxWidth: "xl", open: true, onClose: handleClose, title: "Add track filters", children: [(0, jsx_runtime_1.jsxs)(material_1.DialogContent, { children: [(0, jsx_runtime_1.jsxs)("div", { children: ["Add filters, in jexl format, one per line, starting with the string jexl:. Examples:", ' ', (0, jsx_runtime_1.jsxs)("ul", { children: [(0, jsx_runtime_1.jsxs)("li", { children: [(0, jsx_runtime_1.jsx)("code", { children: "jexl:get(feature,'name')=='BRCA1'" }), " - show only feature where the name attribute is BRCA1"] }), (0, jsx_runtime_1.jsxs)("li", { children: [(0, jsx_runtime_1.jsx)("code", { children: "jexl:get(feature,'type')=='gene'" }), " - show only gene type features in a GFF that has many other feature types"] }), (0, jsx_runtime_1.jsxs)("li", { children: [(0, jsx_runtime_1.jsx)("code", { children: "jexl:get(feature,'score') > 400" }), " - show only features that have a score greater than 400"] })] })] }), error ? (0, jsx_runtime_1.jsx)("p", { className: classes.error, children: `${error}` }) : null, (0, jsx_runtime_1.jsx)(material_1.TextField, { variant: "outlined", multiline: true, minRows: 5, maxRows: 10, className: classes.dialogContent, fullWidth: true, value: data, onChange: event => {
|
|
46
|
+
return ((0, jsx_runtime_1.jsxs)(ui_1.Dialog, { maxWidth: "xl", open: true, onClose: handleClose, title: "Add track filters", children: [(0, jsx_runtime_1.jsxs)(material_1.DialogContent, { children: [(0, jsx_runtime_1.jsxs)("div", { children: ["Add filters, in jexl format, one per line, starting with the string jexl:. Examples:", ' ', (0, jsx_runtime_1.jsxs)("ul", { children: [(0, jsx_runtime_1.jsxs)("li", { children: [(0, jsx_runtime_1.jsx)("code", { children: "jexl:get(feature,'name')=='BRCA1'" }), " - show only feature where the name attribute is BRCA1"] }), (0, jsx_runtime_1.jsxs)("li", { children: [(0, jsx_runtime_1.jsx)("code", { children: "jexl:get(feature,'type')=='gene'" }), " - show only gene type features in a GFF that has many other feature types"] }), (0, jsx_runtime_1.jsxs)("li", { children: [(0, jsx_runtime_1.jsx)("code", { children: "jexl:get(feature,'score') > 400" }), " - show only features that have a score greater than 400"] }), (0, jsx_runtime_1.jsxs)("li", { children: [(0, jsx_runtime_1.jsx)("code", { children: "jexl:get(feature,'end') - get(feature,'start') < 1000000" }), ' ', "- show only features with length less than 1Mbp"] })] })] }), error ? (0, jsx_runtime_1.jsx)("p", { className: classes.error, children: `${error}` }) : null, (0, jsx_runtime_1.jsx)(material_1.TextField, { variant: "outlined", multiline: true, minRows: 5, maxRows: 10, className: classes.dialogContent, fullWidth: true, value: data, onChange: event => {
|
|
47
47
|
setData(event.target.value);
|
|
48
48
|
}, slotProps: {
|
|
49
49
|
input: {
|
|
@@ -198,7 +198,7 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
198
198
|
} & {
|
|
199
199
|
addBlock(key: string, block: import("@jbrowse/core/util/blockTypes").BaseBlock): void;
|
|
200
200
|
deleteBlock(key: string): void;
|
|
201
|
-
selectFeature(feature: import("@jbrowse/core/util").Feature): void
|
|
201
|
+
selectFeature(feature: import("@jbrowse/core/util").Feature): Promise<void>;
|
|
202
202
|
navToFeature(feature: import("@jbrowse/core/util").Feature): void;
|
|
203
203
|
clearFeatureSelection(): void;
|
|
204
204
|
setFeatureIdUnderMouse(feature?: string): void;
|
|
@@ -165,7 +165,10 @@ function stateModelFactory(configSchema) {
|
|
|
165
165
|
onClick: () => {
|
|
166
166
|
(0, util_1.getSession)(self).queueDialog(handleClose => [
|
|
167
167
|
SetMaxHeightDialog,
|
|
168
|
-
{
|
|
168
|
+
{
|
|
169
|
+
model: self,
|
|
170
|
+
handleClose,
|
|
171
|
+
},
|
|
169
172
|
]);
|
|
170
173
|
},
|
|
171
174
|
},
|
|
@@ -174,7 +177,10 @@ function stateModelFactory(configSchema) {
|
|
|
174
177
|
onClick: () => {
|
|
175
178
|
(0, util_1.getSession)(self).queueDialog(handleClose => [
|
|
176
179
|
AddFiltersDialog,
|
|
177
|
-
{
|
|
180
|
+
{
|
|
181
|
+
model: self,
|
|
182
|
+
handleClose,
|
|
183
|
+
},
|
|
178
184
|
]);
|
|
179
185
|
},
|
|
180
186
|
},
|
|
@@ -11,14 +11,14 @@ function rightRoundedRect(x, y, width, height, radius) {
|
|
|
11
11
|
function leftRoundedRect(x, y, width, height, radius) {
|
|
12
12
|
return `M${x + radius},${y}h${width - radius}v${height}h${radius - width}a${radius},${radius} 0 0 1 ${-radius},${-radius}v${2 * radius - height}a${radius},${radius} 0 0 1 ${radius},${-radius}z`;
|
|
13
13
|
}
|
|
14
|
-
function leftTriangle(x,
|
|
14
|
+
function leftTriangle(x, _y, width, height) {
|
|
15
15
|
return [
|
|
16
16
|
[x, 0],
|
|
17
17
|
[x + width, height / 2],
|
|
18
18
|
[x, height],
|
|
19
19
|
].toString();
|
|
20
20
|
}
|
|
21
|
-
function rightTriangle(x,
|
|
21
|
+
function rightTriangle(x, _y, width, height) {
|
|
22
22
|
return [
|
|
23
23
|
[x, height / 2],
|
|
24
24
|
[x + width, 0],
|
|
@@ -42,14 +42,28 @@ const Cytobands = (0, mobx_react_1.observer)(function ({ overview, block, assemb
|
|
|
42
42
|
const rcap = reversed ? 0 : cytobands.length - 1;
|
|
43
43
|
const h = consts_1.HEADER_OVERVIEW_HEIGHT;
|
|
44
44
|
let centromereSeen = false;
|
|
45
|
+
let curr = '';
|
|
46
|
+
let idx = 0;
|
|
45
47
|
return ((0, jsx_runtime_1.jsx)("g", { transform: `translate(-${offsetPx})`, children: cytobands.map((args, index) => {
|
|
46
48
|
const k = JSON.stringify(args);
|
|
47
|
-
const { refName, type, start, end } = args;
|
|
49
|
+
const { refName, name, type, start, end } = args;
|
|
48
50
|
const s = overview.bpToPx({ refName, coord: start }) || 0;
|
|
49
51
|
const e = overview.bpToPx({ refName, coord: end }) || 0;
|
|
50
52
|
const l = Math.min(s, e);
|
|
51
53
|
const w = Math.abs(e - s);
|
|
52
|
-
|
|
54
|
+
if (type === 'n/a') {
|
|
55
|
+
const match = name === null || name === void 0 ? void 0 : name.match(/^(\d+)([A-Za-z])/);
|
|
56
|
+
const ret = match[1] + match[2];
|
|
57
|
+
if (ret && ret !== curr) {
|
|
58
|
+
curr = ret;
|
|
59
|
+
idx++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const c = type === 'n/a'
|
|
63
|
+
? idx % 2
|
|
64
|
+
? 'black'
|
|
65
|
+
: '#a77'
|
|
66
|
+
: colorMap[type] || 'black';
|
|
53
67
|
if (type === 'acen' && !centromereSeen) {
|
|
54
68
|
centromereSeen = true;
|
|
55
69
|
return ((0, jsx_runtime_1.jsx)("polygon", { points: reversed
|
|
@@ -33,8 +33,9 @@ async function fetchSequence(model, regions) {
|
|
|
33
33
|
if (!leftOffset || !rightOffset) {
|
|
34
34
|
throw new Error('no offsets on model to use for range');
|
|
35
35
|
}
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const assemblyNames = new Set(regions.map(r => r.assemblyName));
|
|
37
|
+
if (assemblyNames.size > 1) {
|
|
38
|
+
throw new Error('not able to fetch sequences from multiple assemblies currently');
|
|
38
39
|
}
|
|
39
40
|
const { rpcManager, assemblyManager } = session;
|
|
40
41
|
const assemblyName = leftOffset.assemblyName || rightOffset.assemblyName || '';
|
|
@@ -58,9 +58,13 @@ const useStyles = (0, mui_1.makeStyles)()(theme => ({
|
|
|
58
58
|
color: theme.palette.text.secondary,
|
|
59
59
|
},
|
|
60
60
|
}));
|
|
61
|
+
function ValueLabelComponent(props) {
|
|
62
|
+
const { children, open, value } = props;
|
|
63
|
+
return ((0, jsx_runtime_1.jsx)(material_1.Tooltip, { open: open, enterTouchDelay: 0, placement: "top", title: value, arrow: true, children: children }));
|
|
64
|
+
}
|
|
61
65
|
const HeaderZoomControls = (0, mobx_react_1.observer)(function ({ model, }) {
|
|
62
66
|
const { classes } = useStyles();
|
|
63
|
-
const { maxBpPerPx, minBpPerPx, bpPerPx } = model;
|
|
67
|
+
const { width, maxBpPerPx, minBpPerPx, bpPerPx } = model;
|
|
64
68
|
const [value, setValue] = (0, react_1.useState)(-Math.log2(bpPerPx) * 100);
|
|
65
69
|
(0, react_1.useEffect)(() => {
|
|
66
70
|
setValue(-Math.log2(bpPerPx) * 100);
|
|
@@ -69,7 +73,9 @@ const HeaderZoomControls = (0, mobx_react_1.observer)(function ({ model, }) {
|
|
|
69
73
|
const zoomOutDisabled = bpPerPx >= maxBpPerPx - 0.0001;
|
|
70
74
|
return ((0, jsx_runtime_1.jsxs)("div", { className: classes.container, children: [(0, jsx_runtime_1.jsx)(material_1.Tooltip, { title: "Zoom out 2x", children: (0, jsx_runtime_1.jsx)("span", { children: (0, jsx_runtime_1.jsx)(material_1.IconButton, { "data-testid": "zoom_out", disabled: zoomOutDisabled, onClick: () => {
|
|
71
75
|
model.zoom(bpPerPx * 2);
|
|
72
|
-
}, children: (0, jsx_runtime_1.jsx)(ZoomOut_1.default, {}) }) }) }), (0, jsx_runtime_1.jsx)(material_1.Slider, { size: "small", className: classes.slider, value: value, min: -Math.log2(maxBpPerPx) * 100, max: -Math.log2(minBpPerPx) * 100, onChangeCommitted: () => model.zoomTo(2 ** (-value / 100)),
|
|
76
|
+
}, children: (0, jsx_runtime_1.jsx)(ZoomOut_1.default, {}) }) }) }), (0, jsx_runtime_1.jsx)(material_1.Slider, { size: "small", className: classes.slider, value: value, min: -Math.log2(maxBpPerPx) * 100, max: -Math.log2(minBpPerPx) * 100, onChangeCommitted: () => model.zoomTo(2 ** (-value / 100)), valueLabelDisplay: "auto", valueLabelFormat: newValue => `Window size: ${(0, util_1.getBpDisplayStr)(2 ** (-newValue / 100) * width)}`, slots: {
|
|
77
|
+
valueLabel: ValueLabelComponent,
|
|
78
|
+
}, onChange: (_, val) => {
|
|
73
79
|
setValue(val);
|
|
74
80
|
} }), (0, jsx_runtime_1.jsx)(material_1.Tooltip, { title: "Zoom in 2x", children: (0, jsx_runtime_1.jsx)("span", { children: (0, jsx_runtime_1.jsx)(material_1.IconButton, { "data-testid": "zoom_in", disabled: zoomInDisabled, onClick: () => {
|
|
75
81
|
model.zoom(model.bpPerPx / 2);
|
|
@@ -70,7 +70,7 @@ const LinearGenomeViewImportForm = (0, mobx_react_1.observer)(function ({ model,
|
|
|
70
70
|
session.notify(`${e}`, 'warning');
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
}, children: (0, jsx_runtime_1.jsxs)(material_1.
|
|
73
|
+
}, children: (0, jsx_runtime_1.jsxs)(material_1.Grid, { container: true, spacing: 1, justifyContent: "center", alignItems: "center", children: [(0, jsx_runtime_1.jsx)(material_1.FormControl, { children: (0, jsx_runtime_1.jsx)(ui_1.AssemblySelector, { onChange: val => {
|
|
74
74
|
setSelectedAsm(val);
|
|
75
75
|
}, localStorageKey: "lgv", session: session, selected: selectedAsm }) }), selectedAsm ? (assemblyError ? ((0, jsx_runtime_1.jsx)(Close_1.default, { style: { color: 'red' } })) : assemblyLoaded ? ((0, jsx_runtime_1.jsx)(material_1.FormControl, { children: (0, jsx_runtime_1.jsx)(ImportFormRefNameAutocomplete_1.default, { value: value, setValue: setValue, selectedAsm: selectedAsm, setOption: setOption, model: model }) })) : ((0, jsx_runtime_1.jsx)(material_1.CircularProgress, { size: 20, disableShrink: true }))) : null, (0, jsx_runtime_1.jsx)(material_1.FormControl, { children: (0, jsx_runtime_1.jsx)(material_1.Button, { type: "submit", disabled: !value, className: classes.button, variant: "contained", color: "primary", children: "Open" }) }), (0, jsx_runtime_1.jsx)(material_1.FormControl, { children: (0, jsx_runtime_1.jsx)(material_1.Button, { disabled: !value, className: classes.button, onClick: () => {
|
|
76
76
|
model.setError(undefined);
|
|
@@ -6,20 +6,12 @@ const material_1 = require("@mui/material");
|
|
|
6
6
|
const mobx_react_1 = require("mobx-react");
|
|
7
7
|
const mui_1 = require("tss-react/mui");
|
|
8
8
|
const useStyles = (0, mui_1.makeStyles)()({
|
|
9
|
-
rubberbandControl: {
|
|
10
|
-
cursor: 'crosshair',
|
|
11
|
-
width: '100%',
|
|
12
|
-
minHeight: 8,
|
|
13
|
-
},
|
|
14
9
|
guide: {
|
|
15
10
|
pointerEvents: 'none',
|
|
16
11
|
height: '100%',
|
|
17
12
|
width: 1,
|
|
18
13
|
position: 'absolute',
|
|
19
14
|
},
|
|
20
|
-
rel: {
|
|
21
|
-
position: 'relative',
|
|
22
|
-
},
|
|
23
15
|
});
|
|
24
16
|
const OverviewRubberbandHoverTooltip = (0, mobx_react_1.observer)(function ({ model, open, guideX, overview, }) {
|
|
25
17
|
var _a;
|
|
@@ -31,6 +23,6 @@ const OverviewRubberbandHoverTooltip = (0, mobx_react_1.observer)(function ({ mo
|
|
|
31
23
|
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') &&
|
|
32
24
|
px.coord < f.get('end') &&
|
|
33
25
|
px.refName === assembly.getCanonicalRefName(f.get('refName')));
|
|
34
|
-
return ((0, jsx_runtime_1.jsx)(material_1.Tooltip, { open: open, placement: "top", title: [(0, util_1.stringify)(px), cytoband === null || cytoband === void 0 ? void 0 : cytoband.get('name')].join(' '), arrow: true, children: (0, jsx_runtime_1.jsx)("div", { className: classes.guide, style: { left: guideX } }) }));
|
|
26
|
+
return ((0, jsx_runtime_1.jsx)(material_1.Tooltip, { open: open, placement: "top", title: [(0, util_1.stringify)(px), cytoband === null || cytoband === void 0 ? void 0 : cytoband.get('name'), cytoband === null || cytoband === void 0 ? void 0 : cytoband.get('type')].join(' '), arrow: true, children: (0, jsx_runtime_1.jsx)("div", { className: classes.guide, style: { left: guideX } }) }));
|
|
35
27
|
});
|
|
36
28
|
exports.default = OverviewRubberbandHoverTooltip;
|
|
@@ -63,27 +63,31 @@ const RefNameAutocomplete = (0, mobx_react_1.observer)(function ({ model, onSele
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
setLoaded(false);
|
|
66
|
-
|
|
67
|
-
setLoaded(true);
|
|
68
|
-
setSearchOptions((0, util_2.getDeduplicatedResult)(results));
|
|
66
|
+
setSearchOptions((0, util_2.getDeduplicatedResult)(await fetchResults(debouncedSearch)));
|
|
69
67
|
}
|
|
70
68
|
catch (e) {
|
|
71
69
|
console.error(e);
|
|
72
70
|
session.notifyError(`${e}`, e);
|
|
73
71
|
}
|
|
72
|
+
finally {
|
|
73
|
+
setLoaded(true);
|
|
74
|
+
}
|
|
74
75
|
})();
|
|
75
76
|
}, [assemblyName, fetchResults, debouncedSearch, session]);
|
|
76
77
|
const inputBoxVal = coarseVisibleLocStrings || value || '';
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const regionOptions = (refNames === null || refNames === void 0 ? void 0 : refNames.map(refName => ({
|
|
78
|
+
const regions = assembly === null || assembly === void 0 ? void 0 : assembly.regions;
|
|
79
|
+
const regionOptions = (regions === null || regions === void 0 ? void 0 : regions.map(region => ({
|
|
80
80
|
result: new BaseResults_1.RefSequenceResult({
|
|
81
|
-
refName,
|
|
82
|
-
label: refName,
|
|
81
|
+
refName: region.refName,
|
|
82
|
+
label: region.refName,
|
|
83
|
+
displayString: region.refName,
|
|
83
84
|
matchedAttribute: 'refName',
|
|
84
85
|
}),
|
|
85
86
|
}))) || [];
|
|
86
|
-
return ((0, jsx_runtime_1.jsx)(material_1.Autocomplete, { "data-testid": "autocomplete", disableListWrap: true, disableClearable: true, disabled: !assemblyName, freeSolo: true, includeInputInList: true, selectOnFocus: true, style: {
|
|
87
|
+
return ((0, jsx_runtime_1.jsx)(material_1.Autocomplete, { "data-testid": "autocomplete", disableListWrap: true, disableClearable: true, disabled: !assemblyName, freeSolo: true, includeInputInList: true, selectOnFocus: true, style: {
|
|
88
|
+
...style,
|
|
89
|
+
width: Math.min(Math.max((0, util_1.measureText)(inputBoxVal, 14) + 100, minWidth), maxWidth),
|
|
90
|
+
}, value: inputBoxVal, loading: !loaded, inputValue: inputValue, onInputChange: (_event, newInputValue) => {
|
|
87
91
|
setInputValue(newInputValue);
|
|
88
92
|
onChange === null || onChange === void 0 ? void 0 : onChange(newInputValue);
|
|
89
93
|
}, loadingText: "loading results", open: open, onOpen: () => {
|
|
@@ -100,7 +104,9 @@ const RefNameAutocomplete = (0, mobx_react_1.observer)(function ({ model, onSele
|
|
|
100
104
|
return;
|
|
101
105
|
}
|
|
102
106
|
if (typeof selectedOption === 'string') {
|
|
103
|
-
onSelect === null || onSelect === void 0 ? void 0 : onSelect(new BaseResults_1.default({
|
|
107
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(new BaseResults_1.default({
|
|
108
|
+
label: selectedOption,
|
|
109
|
+
}));
|
|
104
110
|
}
|
|
105
111
|
else {
|
|
106
112
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(selectedOption.result);
|
|
@@ -34,10 +34,10 @@ const useStyles = (0, mui_1.makeStyles)()(theme => {
|
|
|
34
34
|
function RubberbandSpan({ leftBpOffset, rightBpOffset, numOfBpSelected, left, width, top = 0, sticky = false, }) {
|
|
35
35
|
const { classes } = useStyles();
|
|
36
36
|
const [anchorEl, setAnchorEl] = (0, react_1.useState)(null);
|
|
37
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [anchorEl ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(RubberbandTooltip_1.default, { side: "left", anchorEl: anchorEl, text: (0, util_1.stringify)(leftBpOffset) }), (0, jsx_runtime_1.jsx)(RubberbandTooltip_1.default, { side: "right", anchorEl: anchorEl, text: (0, util_1.stringify)(rightBpOffset) })] })) : null, (0, jsx_runtime_1.jsx)("div", { className: classes.rubberband, style: { left, width }, children: numOfBpSelected ? ((0, jsx_runtime_1.
|
|
37
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [anchorEl ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(RubberbandTooltip_1.default, { side: "left", anchorEl: anchorEl, text: (0, util_1.stringify)(leftBpOffset) }), (0, jsx_runtime_1.jsx)(RubberbandTooltip_1.default, { side: "right", anchorEl: anchorEl, text: (0, util_1.stringify)(rightBpOffset) })] })) : null, (0, jsx_runtime_1.jsx)("div", { className: classes.rubberband, style: { left, width }, children: numOfBpSelected ? ((0, jsx_runtime_1.jsx)(material_1.Typography, { ref: el => {
|
|
38
38
|
setAnchorEl(el);
|
|
39
39
|
}, variant: "h6", className: classes.rubberbandText, style: {
|
|
40
40
|
top,
|
|
41
41
|
position: sticky ? 'sticky' : undefined,
|
|
42
|
-
}, children:
|
|
42
|
+
}, children: (0, util_1.getBpDisplayStr)(numOfBpSelected) })) : null })] }));
|
|
43
43
|
}
|
|
@@ -13,11 +13,33 @@ const EndAdornment_1 = __importDefault(require("./RefNameAutocomplete/EndAdornme
|
|
|
13
13
|
const util_2 = require("./util");
|
|
14
14
|
const searchUtils_1 = require("../../searchUtils");
|
|
15
15
|
const consts_1 = require("../consts");
|
|
16
|
-
const useStyles = (0, mui_1.makeStyles)()(
|
|
16
|
+
const useStyles = (0, mui_1.makeStyles)()({
|
|
17
17
|
headerRefName: {
|
|
18
18
|
minWidth: 100,
|
|
19
19
|
},
|
|
20
|
-
})
|
|
20
|
+
});
|
|
21
|
+
async function onSelect({ option, model, assemblyName, }) {
|
|
22
|
+
var _a;
|
|
23
|
+
const { assemblyManager } = (0, util_1.getSession)(model);
|
|
24
|
+
const assembly = assemblyManager.get(assemblyName);
|
|
25
|
+
if (option.hasLocation()) {
|
|
26
|
+
await (0, searchUtils_1.navToOption)({
|
|
27
|
+
option,
|
|
28
|
+
model,
|
|
29
|
+
assemblyName,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
else if ((_a = option.results) === null || _a === void 0 ? void 0 : _a.length) {
|
|
33
|
+
model.setSearchResults(option.results, option.getLabel());
|
|
34
|
+
}
|
|
35
|
+
else if (assembly) {
|
|
36
|
+
await (0, searchUtils_1.handleSelectedRegion)({
|
|
37
|
+
input: option.getLabel(),
|
|
38
|
+
assembly,
|
|
39
|
+
model,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
21
43
|
const SearchBox = (0, mobx_react_1.observer)(function ({ model, showHelp = true, }) {
|
|
22
44
|
const { classes } = useStyles();
|
|
23
45
|
const theme = (0, material_1.useTheme)();
|
|
@@ -28,21 +50,12 @@ const SearchBox = (0, mobx_react_1.observer)(function ({ model, showHelp = true,
|
|
|
28
50
|
const assembly = assemblyManager.get(assemblyName);
|
|
29
51
|
const searchScope = model.searchScope(assemblyName);
|
|
30
52
|
return ((0, jsx_runtime_1.jsx)(RefNameAutocomplete_1.default, { onSelect: async (option) => {
|
|
31
|
-
var _a;
|
|
32
53
|
try {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
else if (assembly) {
|
|
40
|
-
await (0, searchUtils_1.handleSelectedRegion)({
|
|
41
|
-
input: option.getLabel(),
|
|
42
|
-
assembly,
|
|
43
|
-
model,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
54
|
+
await onSelect({
|
|
55
|
+
model,
|
|
56
|
+
assemblyName,
|
|
57
|
+
option,
|
|
58
|
+
});
|
|
46
59
|
}
|
|
47
60
|
catch (e) {
|
|
48
61
|
console.error(e);
|
|
@@ -2,16 +2,27 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useWheelScroll = useWheelScroll;
|
|
4
4
|
const react_1 = require("react");
|
|
5
|
+
const util_1 = require("@jbrowse/core/util");
|
|
5
6
|
function useWheelScroll(ref, model) {
|
|
6
7
|
const delta = (0, react_1.useRef)(0);
|
|
7
8
|
const timeout = (0, react_1.useRef)(null);
|
|
8
9
|
const scheduled = (0, react_1.useRef)(false);
|
|
9
10
|
(0, react_1.useEffect)(() => {
|
|
11
|
+
let samples = [];
|
|
10
12
|
const curr = ref.current;
|
|
11
13
|
function onWheel(event) {
|
|
12
14
|
if (event.ctrlKey) {
|
|
13
15
|
event.preventDefault();
|
|
14
|
-
|
|
16
|
+
samples.push(event.deltaY);
|
|
17
|
+
const averageDeltaY = Math.abs((0, util_1.sum)(samples)) / samples.length;
|
|
18
|
+
const normalizer = averageDeltaY < 6
|
|
19
|
+
? 25
|
|
20
|
+
: averageDeltaY > 30
|
|
21
|
+
? averageDeltaY > 150
|
|
22
|
+
? 500
|
|
23
|
+
: 150
|
|
24
|
+
: 75;
|
|
25
|
+
delta.current += event.deltaY / normalizer;
|
|
15
26
|
model.setScaleFactor(delta.current < 0 ? 1 - delta.current : 1 / (1 + delta.current));
|
|
16
27
|
if (timeout.current) {
|
|
17
28
|
clearTimeout(timeout.current);
|
|
@@ -22,6 +33,7 @@ function useWheelScroll(ref, model) {
|
|
|
22
33
|
? model.bpPerPx * (1 + delta.current)
|
|
23
34
|
: model.bpPerPx / (1 - delta.current), event.clientX - ((curr === null || curr === void 0 ? void 0 : curr.getBoundingClientRect().left) || 0));
|
|
24
35
|
delta.current = 0;
|
|
36
|
+
samples = [];
|
|
25
37
|
}, 300);
|
|
26
38
|
}
|
|
27
39
|
else {
|
|
@@ -14,12 +14,14 @@ async function fetchResults({ queryString, searchType, searchScope, rankSearchRe
|
|
|
14
14
|
if (!textSearchManager) {
|
|
15
15
|
console.warn('No text search manager');
|
|
16
16
|
}
|
|
17
|
-
const textSearchResults = await (textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
|
|
17
|
+
const textSearchResults = (await (textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
|
|
18
18
|
queryString,
|
|
19
19
|
searchType,
|
|
20
|
-
}, searchScope, rankSearchResults));
|
|
21
|
-
const refNameResults = (_a = assembly === null || assembly === void 0 ? void 0 : assembly.allRefNames) === null || _a === void 0 ? void 0 : _a.filter(ref => ref.toLowerCase().startsWith(queryString.toLowerCase())).slice(0, 10).map(r => new BaseResults_1.default({
|
|
22
|
-
|
|
20
|
+
}, searchScope, rankSearchResults))) || [];
|
|
21
|
+
const refNameResults = ((_a = assembly === null || assembly === void 0 ? void 0 : assembly.allRefNames) === null || _a === void 0 ? void 0 : _a.filter(ref => ref.toLowerCase().startsWith(queryString.toLowerCase())).slice(0, 10).map(r => new BaseResults_1.default({
|
|
22
|
+
label: r,
|
|
23
|
+
}))) || [];
|
|
24
|
+
return (0, util_1.dedupe)([...refNameResults, ...textSearchResults], elt => elt.getId());
|
|
23
25
|
}
|
|
24
26
|
function splitLast(str, split) {
|
|
25
27
|
const lastIndex = str.lastIndexOf(split);
|
|
@@ -42,5 +44,6 @@ function getCytobands(assembly, refName) {
|
|
|
42
44
|
start: f.get('start'),
|
|
43
45
|
end: f.get('end'),
|
|
44
46
|
type: f.get('gieStain'),
|
|
47
|
+
name: f.get('name'),
|
|
45
48
|
})).filter(f => f.refName === refName)) || []);
|
|
46
49
|
}
|
|
@@ -169,12 +169,13 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
169
169
|
setCoarseDynamicBlocks(blocks: BlockSet): void;
|
|
170
170
|
} & {
|
|
171
171
|
moveTo(start?: BpOffset, end?: BpOffset): void;
|
|
172
|
-
navToLocString(input: string, optAssemblyName?: string): Promise<void>;
|
|
172
|
+
navToLocString(input: string, optAssemblyName?: string, grow?: number): Promise<void>;
|
|
173
173
|
navToSearchString({ input, assembly, }: {
|
|
174
174
|
input: string;
|
|
175
175
|
assembly: Assembly;
|
|
176
176
|
}): Promise<void>;
|
|
177
|
-
|
|
177
|
+
navToLocation(parsedLocString: ParsedLocString, assemblyName?: string, grow?: number): Promise<void>;
|
|
178
|
+
navToLocations(regions: ParsedLocString[], assemblyName?: string, grow?: number): Promise<void>;
|
|
178
179
|
navTo(query: NavLocation): void;
|
|
179
180
|
navToMultiple(locations: NavLocation[]): void;
|
|
180
181
|
} & {
|
|
@@ -242,9 +243,9 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
242
243
|
displayName: string | undefined;
|
|
243
244
|
tracks: any[];
|
|
244
245
|
minimized: boolean;
|
|
245
|
-
displayedRegions: Region[];
|
|
246
246
|
offsetPx: number;
|
|
247
247
|
bpPerPx: number;
|
|
248
|
+
displayedRegions: Region[];
|
|
248
249
|
hideHeader: boolean;
|
|
249
250
|
hideHeaderOverview: boolean;
|
|
250
251
|
hideNoTracksActive: boolean;
|
|
@@ -262,12 +262,6 @@ function stateModelFactory(pluginManager) {
|
|
|
262
262
|
return self.tracks.find(t => t.configuration.trackId === id);
|
|
263
263
|
},
|
|
264
264
|
rankSearchResults(results) {
|
|
265
|
-
const openTrackIds = new Set(self.tracks.map(track => track.configuration.trackId));
|
|
266
|
-
for (const result of results) {
|
|
267
|
-
if (openTrackIds.has(result.trackId)) {
|
|
268
|
-
result.updateScore(result.getScore() + 1);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
265
|
return results;
|
|
272
266
|
},
|
|
273
267
|
rewriteOnClicks(trackType, viewMenuActions) {
|
|
@@ -840,14 +834,14 @@ function stateModelFactory(pluginManager) {
|
|
|
840
834
|
moveTo(start, end) {
|
|
841
835
|
(0, Base1DUtils_1.moveTo)(self, start, end);
|
|
842
836
|
},
|
|
843
|
-
async navToLocString(input, optAssemblyName) {
|
|
837
|
+
async navToLocString(input, optAssemblyName, grow) {
|
|
844
838
|
const { assemblyNames } = self;
|
|
845
839
|
const { assemblyManager } = (0, util_1.getSession)(self);
|
|
846
840
|
const assemblyName = optAssemblyName || assemblyNames[0];
|
|
847
841
|
if (assemblyName) {
|
|
848
842
|
await assemblyManager.waitForAssembly(assemblyName);
|
|
849
843
|
}
|
|
850
|
-
return this.navToLocations((0, util_2.parseLocStrings)(input, assemblyName, (ref, asm) => assemblyManager.isValidRefName(ref, asm)), assemblyName);
|
|
844
|
+
return this.navToLocations((0, util_2.parseLocStrings)(input, assemblyName, (ref, asm) => assemblyManager.isValidRefName(ref, asm)), assemblyName, grow);
|
|
851
845
|
},
|
|
852
846
|
async navToSearchString({ input, assembly, }) {
|
|
853
847
|
await (0, searchUtils_1.handleSelectedRegion)({
|
|
@@ -856,10 +850,18 @@ function stateModelFactory(pluginManager) {
|
|
|
856
850
|
model: self,
|
|
857
851
|
});
|
|
858
852
|
},
|
|
859
|
-
async
|
|
853
|
+
async navToLocation(parsedLocString, assemblyName, grow) {
|
|
854
|
+
return this.navToLocations([parsedLocString], assemblyName, grow);
|
|
855
|
+
},
|
|
856
|
+
async navToLocations(regions, assemblyName, grow) {
|
|
860
857
|
const { assemblyManager } = (0, util_1.getSession)(self);
|
|
861
858
|
await (0, mobx_1.when)(() => self.volatileWidth !== undefined);
|
|
862
|
-
const locations = await (0, util_2.generateLocations)(
|
|
859
|
+
const locations = await (0, util_2.generateLocations)({
|
|
860
|
+
regions,
|
|
861
|
+
assemblyManager,
|
|
862
|
+
assemblyName,
|
|
863
|
+
grow,
|
|
864
|
+
});
|
|
863
865
|
if (locations.length === 1) {
|
|
864
866
|
const loc = locations[0];
|
|
865
867
|
const { reversed, parentRegion, start, end } = loc;
|
|
@@ -9,7 +9,12 @@ export declare function makeTicks(start: number, end: number, bpPerPx: number, e
|
|
|
9
9
|
base: number;
|
|
10
10
|
index: number;
|
|
11
11
|
}[];
|
|
12
|
-
export declare function generateLocations(regions
|
|
12
|
+
export declare function generateLocations({ regions, assemblyManager, assemblyName, grow, }: {
|
|
13
|
+
regions: ParsedLocString[];
|
|
14
|
+
assemblyManager: AssemblyManager;
|
|
15
|
+
assemblyName?: string;
|
|
16
|
+
grow?: number;
|
|
17
|
+
}): Promise<{
|
|
13
18
|
assemblyName: string;
|
|
14
19
|
parentRegion: import("@jbrowse/core/assemblyManager/assembly").BasicRegion;
|
|
15
20
|
end?: number | undefined;
|
|
@@ -57,7 +57,7 @@ function makeTicks(start, end, bpPerPx, emitMajor = true, emitMinor = true) {
|
|
|
57
57
|
}
|
|
58
58
|
return ticks;
|
|
59
59
|
}
|
|
60
|
-
async function generateLocations(regions, assemblyManager, assemblyName) {
|
|
60
|
+
async function generateLocations({ regions, assemblyManager, assemblyName, grow, }) {
|
|
61
61
|
return Promise.all(regions.map(async (region) => {
|
|
62
62
|
const asmName = region.assemblyName || assemblyName;
|
|
63
63
|
if (!asmName) {
|
|
@@ -80,11 +80,25 @@ async function generateLocations(regions, assemblyManager, assemblyName) {
|
|
|
80
80
|
if (!parentRegion) {
|
|
81
81
|
throw new Error(`Could not find refName ${refName} in ${asmName}`);
|
|
82
82
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
const { start, end } = region;
|
|
84
|
+
if (grow && start && end) {
|
|
85
|
+
const len = end - start;
|
|
86
|
+
const margin = len * grow;
|
|
87
|
+
return {
|
|
88
|
+
...region,
|
|
89
|
+
start: Math.max(0, start - margin),
|
|
90
|
+
end: end + margin,
|
|
91
|
+
assemblyName: asmName,
|
|
92
|
+
parentRegion,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return {
|
|
97
|
+
...region,
|
|
98
|
+
assemblyName: asmName,
|
|
99
|
+
parentRegion,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
88
102
|
}));
|
|
89
103
|
}
|
|
90
104
|
function parseLocStrings(input, assemblyName, isValidRefName) {
|
package/dist/index.d.ts
CHANGED
|
@@ -195,7 +195,7 @@ export default class LinearGenomeViewPlugin extends Plugin {
|
|
|
195
195
|
} & {
|
|
196
196
|
addBlock(key: string, block: import("@jbrowse/core/util/blockTypes").BaseBlock): void;
|
|
197
197
|
deleteBlock(key: string): void;
|
|
198
|
-
selectFeature(feature: import("@jbrowse/core/util").Feature): void
|
|
198
|
+
selectFeature(feature: import("@jbrowse/core/util").Feature): Promise<void>;
|
|
199
199
|
navToFeature(feature: import("@jbrowse/core/util").Feature): void;
|
|
200
200
|
clearFeatureSelection(): void;
|
|
201
201
|
setFeatureIdUnderMouse(feature?: string): void;
|