@jbrowse/plugin-linear-genome-view 3.1.0 → 3.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/dist/BaseLinearDisplay/components/LinearBlocks.js +1 -1
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +9 -9
- package/dist/LaunchLinearGenomeView/index.js +9 -5
- package/dist/LinearBasicDisplay/components/AddFiltersDialog.js +1 -1
- package/dist/LinearBasicDisplay/model.js +8 -2
- package/dist/LinearGenomeView/components/HeaderZoomControls.js +8 -2
- package/dist/LinearGenomeView/components/ImportForm.js +1 -1
- 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 +7 -21
- 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 +28 -3
- package/dist/LinearGenomeView/model.js +62 -26
- package/dist/LinearGenomeView/types.d.ts +5 -0
- package/esm/BaseLinearDisplay/components/LinearBlocks.js +1 -1
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js +9 -9
- package/esm/LaunchLinearGenomeView/index.js +9 -5
- package/esm/LinearBasicDisplay/components/AddFiltersDialog.js +1 -1
- package/esm/LinearBasicDisplay/model.js +8 -2
- package/esm/LinearGenomeView/components/HeaderZoomControls.js +9 -3
- package/esm/LinearGenomeView/components/ImportForm.js +1 -1
- 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 +6 -23
- 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 +28 -3
- package/esm/LinearGenomeView/model.js +62 -26
- package/esm/LinearGenomeView/types.d.ts +5 -0
- package/package.json +5 -5
|
@@ -93,6 +93,7 @@ function stateModelFactory(pluginManager) {
|
|
|
93
93
|
highlight: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.array(mobx_state_tree_1.types.frozen()), []),
|
|
94
94
|
colorByCDS: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.boolean, () => (0, util_1.localStorageGetBoolean)('lgv-colorByCDS', false)),
|
|
95
95
|
showTrackOutlines: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.boolean, () => (0, util_1.localStorageGetBoolean)('lgv-showTrackOutlines', true)),
|
|
96
|
+
init: mobx_state_tree_1.types.frozen(),
|
|
96
97
|
}))
|
|
97
98
|
.volatile(() => ({
|
|
98
99
|
volatileWidth: undefined,
|
|
@@ -141,10 +142,10 @@ function stateModelFactory(pluginManager) {
|
|
|
141
142
|
? session.stickyViewHeaders
|
|
142
143
|
: false;
|
|
143
144
|
},
|
|
144
|
-
get
|
|
145
|
+
get rubberbandTop() {
|
|
145
146
|
let pinnedTracksTop = 0;
|
|
146
147
|
if (this.stickyViewHeaders) {
|
|
147
|
-
pinnedTracksTop = ui_1.VIEW_HEADER_HEIGHT
|
|
148
|
+
pinnedTracksTop = ui_1.VIEW_HEADER_HEIGHT;
|
|
148
149
|
if (!self.hideHeader) {
|
|
149
150
|
pinnedTracksTop += consts_1.HEADER_BAR_HEIGHT;
|
|
150
151
|
if (!self.hideHeaderOverview) {
|
|
@@ -154,6 +155,9 @@ function stateModelFactory(pluginManager) {
|
|
|
154
155
|
}
|
|
155
156
|
return pinnedTracksTop;
|
|
156
157
|
},
|
|
158
|
+
get pinnedTracksTop() {
|
|
159
|
+
return this.rubberbandTop + consts_1.SCALE_BAR_HEIGHT;
|
|
160
|
+
},
|
|
157
161
|
}))
|
|
158
162
|
.views(self => ({
|
|
159
163
|
scaleBarDisplayPrefix() {
|
|
@@ -267,32 +271,32 @@ function stateModelFactory(pluginManager) {
|
|
|
267
271
|
return results;
|
|
268
272
|
},
|
|
269
273
|
rewriteOnClicks(trackType, viewMenuActions) {
|
|
270
|
-
|
|
274
|
+
for (const action of viewMenuActions) {
|
|
271
275
|
if ('subMenu' in action) {
|
|
272
276
|
this.rewriteOnClicks(trackType, action.subMenu);
|
|
273
277
|
}
|
|
274
278
|
if ('onClick' in action) {
|
|
275
279
|
const holdOnClick = action.onClick;
|
|
276
280
|
action.onClick = (...args) => {
|
|
277
|
-
self.tracks
|
|
281
|
+
for (const track of self.tracks) {
|
|
278
282
|
if (track.type === trackType) {
|
|
279
283
|
holdOnClick.apply(track, [track, ...args]);
|
|
280
284
|
}
|
|
281
|
-
}
|
|
285
|
+
}
|
|
282
286
|
};
|
|
283
287
|
}
|
|
284
|
-
}
|
|
288
|
+
}
|
|
285
289
|
},
|
|
286
290
|
get trackTypeActions() {
|
|
287
291
|
const allActions = new Map();
|
|
288
|
-
self.tracks
|
|
292
|
+
for (const track of self.tracks) {
|
|
289
293
|
const trackInMap = allActions.get(track.type);
|
|
290
294
|
if (!trackInMap) {
|
|
291
295
|
const viewMenuActions = structuredClone(track.viewMenuActions);
|
|
292
296
|
this.rewriteOnClicks(track.type, viewMenuActions);
|
|
293
297
|
allActions.set(track.type, viewMenuActions);
|
|
294
298
|
}
|
|
295
|
-
}
|
|
299
|
+
}
|
|
296
300
|
return allActions;
|
|
297
301
|
},
|
|
298
302
|
}))
|
|
@@ -417,11 +421,13 @@ function stateModelFactory(pluginManager) {
|
|
|
417
421
|
hideTrack(trackId) {
|
|
418
422
|
const schema = pluginManager.pluggableConfigSchemaType('track');
|
|
419
423
|
const conf = (0, mobx_state_tree_1.resolveIdentifier)(schema, (0, mobx_state_tree_1.getRoot)(self), trackId);
|
|
420
|
-
const
|
|
424
|
+
const tracks = self.tracks.filter(t => t.configuration === conf);
|
|
421
425
|
(0, mobx_1.transaction)(() => {
|
|
422
|
-
|
|
426
|
+
for (const track of tracks) {
|
|
427
|
+
self.tracks.remove(track);
|
|
428
|
+
}
|
|
423
429
|
});
|
|
424
|
-
return
|
|
430
|
+
return tracks.length;
|
|
425
431
|
},
|
|
426
432
|
}))
|
|
427
433
|
.actions(self => ({
|
|
@@ -562,6 +568,9 @@ function stateModelFactory(pluginManager) {
|
|
|
562
568
|
self.scrollTo(0);
|
|
563
569
|
self.zoomTo(10);
|
|
564
570
|
},
|
|
571
|
+
setInit(arg) {
|
|
572
|
+
self.init = arg;
|
|
573
|
+
},
|
|
565
574
|
async exportSvg(opts = {}) {
|
|
566
575
|
const { renderToSvg } = await Promise.resolve().then(() => __importStar(require('./svgcomponents/SVGLinearGenomeView')));
|
|
567
576
|
const html = await renderToSvg(self, opts);
|
|
@@ -782,7 +791,9 @@ function stateModelFactory(pluginManager) {
|
|
|
782
791
|
for (const [key, value] of self.trackTypeActions.entries()) {
|
|
783
792
|
if (value.length) {
|
|
784
793
|
menuItems.push({ type: 'divider' }, { type: 'subHeader', label: key });
|
|
785
|
-
|
|
794
|
+
for (const action of value) {
|
|
795
|
+
menuItems.push(action);
|
|
796
|
+
}
|
|
786
797
|
}
|
|
787
798
|
}
|
|
788
799
|
return menuItems;
|
|
@@ -824,20 +835,6 @@ function stateModelFactory(pluginManager) {
|
|
|
824
835
|
self.coarseDynamicBlocks = blocks.contentBlocks;
|
|
825
836
|
self.coarseTotalBp = blocks.totalBp;
|
|
826
837
|
},
|
|
827
|
-
afterAttach() {
|
|
828
|
-
(0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => {
|
|
829
|
-
if (self.initialized) {
|
|
830
|
-
this.setCoarseDynamicBlocks(self.dynamicBlocks);
|
|
831
|
-
}
|
|
832
|
-
}, { delay: 150 }));
|
|
833
|
-
(0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => {
|
|
834
|
-
const s = (s) => JSON.stringify(s);
|
|
835
|
-
const { showCytobandsSetting, showCenterLine, colorByCDS } = self;
|
|
836
|
-
(0, util_1.localStorageSetItem)('lgv-showCytobands', s(showCytobandsSetting));
|
|
837
|
-
(0, util_1.localStorageSetItem)('lgv-showCenterLine', s(showCenterLine));
|
|
838
|
-
(0, util_1.localStorageSetItem)('lgv-colorByCDS', s(colorByCDS));
|
|
839
|
-
}));
|
|
840
|
-
},
|
|
841
838
|
}))
|
|
842
839
|
.actions(self => ({
|
|
843
840
|
moveTo(start, end) {
|
|
@@ -859,6 +856,9 @@ function stateModelFactory(pluginManager) {
|
|
|
859
856
|
model: self,
|
|
860
857
|
});
|
|
861
858
|
},
|
|
859
|
+
async navToLocation(parsedLocString, assemblyName) {
|
|
860
|
+
return this.navToLocations([parsedLocString], assemblyName);
|
|
861
|
+
},
|
|
862
862
|
async navToLocations(parsedLocStrings, assemblyName) {
|
|
863
863
|
const { assemblyManager } = (0, util_1.getSession)(self);
|
|
864
864
|
await (0, mobx_1.when)(() => self.volatileWidth !== undefined);
|
|
@@ -1004,6 +1004,33 @@ function stateModelFactory(pluginManager) {
|
|
|
1004
1004
|
document.removeEventListener('keydown', handler);
|
|
1005
1005
|
});
|
|
1006
1006
|
},
|
|
1007
|
+
afterAttach() {
|
|
1008
|
+
(0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => {
|
|
1009
|
+
var _a;
|
|
1010
|
+
const { init } = self;
|
|
1011
|
+
if (init) {
|
|
1012
|
+
self
|
|
1013
|
+
.navToLocString(init.loc, init.assembly)
|
|
1014
|
+
.catch((e) => {
|
|
1015
|
+
(0, util_1.getSession)(self).notifyError(`${e}`, e);
|
|
1016
|
+
});
|
|
1017
|
+
(_a = init.tracks) === null || _a === void 0 ? void 0 : _a.map(t => self.showTrack(t));
|
|
1018
|
+
self.setInit(undefined);
|
|
1019
|
+
}
|
|
1020
|
+
}));
|
|
1021
|
+
(0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => {
|
|
1022
|
+
if (self.initialized) {
|
|
1023
|
+
self.setCoarseDynamicBlocks(self.dynamicBlocks);
|
|
1024
|
+
}
|
|
1025
|
+
}, { delay: 150 }));
|
|
1026
|
+
(0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => {
|
|
1027
|
+
const s = (s) => JSON.stringify(s);
|
|
1028
|
+
const { showCytobandsSetting, showCenterLine, colorByCDS } = self;
|
|
1029
|
+
(0, util_1.localStorageSetItem)('lgv-showCytobands', s(showCytobandsSetting));
|
|
1030
|
+
(0, util_1.localStorageSetItem)('lgv-showCenterLine', s(showCenterLine));
|
|
1031
|
+
(0, util_1.localStorageSetItem)('lgv-colorByCDS', s(colorByCDS));
|
|
1032
|
+
}));
|
|
1033
|
+
},
|
|
1007
1034
|
}))
|
|
1008
1035
|
.preProcessSnapshot(snap => {
|
|
1009
1036
|
if (!snap) {
|
|
@@ -1016,6 +1043,15 @@ function stateModelFactory(pluginManager) {
|
|
|
1016
1043
|
: [highlight],
|
|
1017
1044
|
...rest,
|
|
1018
1045
|
};
|
|
1046
|
+
})
|
|
1047
|
+
.postProcessSnapshot(snap => {
|
|
1048
|
+
if (!snap) {
|
|
1049
|
+
return snap;
|
|
1050
|
+
}
|
|
1051
|
+
else {
|
|
1052
|
+
const { init, ...rest } = snap;
|
|
1053
|
+
return rest;
|
|
1054
|
+
}
|
|
1019
1055
|
});
|
|
1020
1056
|
}
|
|
1021
1057
|
var LinearGenomeView_1 = require("./components/LinearGenomeView");
|
|
@@ -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
|
}
|
|
@@ -41,7 +41,7 @@ const AddFiltersDialog = observer(function ({ model, handleClose, }) {
|
|
|
41
41
|
setError(e);
|
|
42
42
|
}
|
|
43
43
|
}, [data]);
|
|
44
|
-
return (_jsxs(Dialog, { maxWidth: "xl", open: true, onClose: handleClose, title: "Add track filters", children: [_jsxs(DialogContent, { children: [_jsxs("div", { children: ["Add filters, in jexl format, one per line, starting with the string jexl:. Examples:", ' ', _jsxs("ul", { children: [_jsxs("li", { children: [_jsx("code", { children: "jexl:get(feature,'name')=='BRCA1'" }), " - show only feature where the name attribute is BRCA1"] }), _jsxs("li", { children: [_jsx("code", { children: "jexl:get(feature,'type')=='gene'" }), " - show only gene type features in a GFF that has many other feature types"] }), _jsxs("li", { children: [_jsx("code", { children: "jexl:get(feature,'score') > 400" }), " - show only features that have a score greater than 400"] })] })] }), error ? _jsx("p", { className: classes.error, children: `${error}` }) : null, _jsx(TextField, { variant: "outlined", multiline: true, minRows: 5, maxRows: 10, className: classes.dialogContent, fullWidth: true, value: data, onChange: event => {
|
|
44
|
+
return (_jsxs(Dialog, { maxWidth: "xl", open: true, onClose: handleClose, title: "Add track filters", children: [_jsxs(DialogContent, { children: [_jsxs("div", { children: ["Add filters, in jexl format, one per line, starting with the string jexl:. Examples:", ' ', _jsxs("ul", { children: [_jsxs("li", { children: [_jsx("code", { children: "jexl:get(feature,'name')=='BRCA1'" }), " - show only feature where the name attribute is BRCA1"] }), _jsxs("li", { children: [_jsx("code", { children: "jexl:get(feature,'type')=='gene'" }), " - show only gene type features in a GFF that has many other feature types"] }), _jsxs("li", { children: [_jsx("code", { children: "jexl:get(feature,'score') > 400" }), " - show only features that have a score greater than 400"] }), _jsxs("li", { children: [_jsx("code", { children: "jexl:get(feature,'end') - get(feature,'start') < 1000000" }), ' ', "- show only features with length less than 1Mbp"] })] })] }), error ? _jsx("p", { className: classes.error, children: `${error}` }) : null, _jsx(TextField, { variant: "outlined", multiline: true, minRows: 5, maxRows: 10, className: classes.dialogContent, fullWidth: true, value: data, onChange: event => {
|
|
45
45
|
setData(event.target.value);
|
|
46
46
|
}, slotProps: {
|
|
47
47
|
input: {
|
|
@@ -127,7 +127,10 @@ function stateModelFactory(configSchema) {
|
|
|
127
127
|
onClick: () => {
|
|
128
128
|
getSession(self).queueDialog(handleClose => [
|
|
129
129
|
SetMaxHeightDialog,
|
|
130
|
-
{
|
|
130
|
+
{
|
|
131
|
+
model: self,
|
|
132
|
+
handleClose,
|
|
133
|
+
},
|
|
131
134
|
]);
|
|
132
135
|
},
|
|
133
136
|
},
|
|
@@ -136,7 +139,10 @@ function stateModelFactory(configSchema) {
|
|
|
136
139
|
onClick: () => {
|
|
137
140
|
getSession(self).queueDialog(handleClose => [
|
|
138
141
|
AddFiltersDialog,
|
|
139
|
-
{
|
|
142
|
+
{
|
|
143
|
+
model: self,
|
|
144
|
+
handleClose,
|
|
145
|
+
},
|
|
140
146
|
]);
|
|
141
147
|
},
|
|
142
148
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { lazy, useEffect, useState } from 'react';
|
|
3
3
|
import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
|
|
4
|
-
import { getSession } from '@jbrowse/core/util';
|
|
4
|
+
import { getBpDisplayStr, getSession } from '@jbrowse/core/util';
|
|
5
5
|
import MoreVert from '@mui/icons-material/MoreVert';
|
|
6
6
|
import ZoomIn from '@mui/icons-material/ZoomIn';
|
|
7
7
|
import ZoomOut from '@mui/icons-material/ZoomOut';
|
|
@@ -20,9 +20,13 @@ const useStyles = makeStyles()(theme => ({
|
|
|
20
20
|
color: theme.palette.text.secondary,
|
|
21
21
|
},
|
|
22
22
|
}));
|
|
23
|
+
function ValueLabelComponent(props) {
|
|
24
|
+
const { children, open, value } = props;
|
|
25
|
+
return (_jsx(Tooltip, { open: open, enterTouchDelay: 0, placement: "top", title: value, arrow: true, children: children }));
|
|
26
|
+
}
|
|
23
27
|
const HeaderZoomControls = observer(function ({ model, }) {
|
|
24
28
|
const { classes } = useStyles();
|
|
25
|
-
const { maxBpPerPx, minBpPerPx, bpPerPx } = model;
|
|
29
|
+
const { width, maxBpPerPx, minBpPerPx, bpPerPx } = model;
|
|
26
30
|
const [value, setValue] = useState(-Math.log2(bpPerPx) * 100);
|
|
27
31
|
useEffect(() => {
|
|
28
32
|
setValue(-Math.log2(bpPerPx) * 100);
|
|
@@ -31,7 +35,9 @@ const HeaderZoomControls = observer(function ({ model, }) {
|
|
|
31
35
|
const zoomOutDisabled = bpPerPx >= maxBpPerPx - 0.0001;
|
|
32
36
|
return (_jsxs("div", { className: classes.container, children: [_jsx(Tooltip, { title: "Zoom out 2x", children: _jsx("span", { children: _jsx(IconButton, { "data-testid": "zoom_out", disabled: zoomOutDisabled, onClick: () => {
|
|
33
37
|
model.zoom(bpPerPx * 2);
|
|
34
|
-
}, children: _jsx(ZoomOut, {}) }) }) }), _jsx(Slider, { size: "small", className: classes.slider, value: value, min: -Math.log2(maxBpPerPx) * 100, max: -Math.log2(minBpPerPx) * 100, onChangeCommitted: () => model.zoomTo(2 ** (-value / 100)),
|
|
38
|
+
}, children: _jsx(ZoomOut, {}) }) }) }), _jsx(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: ${getBpDisplayStr(2 ** (-newValue / 100) * width)}`, slots: {
|
|
39
|
+
valueLabel: ValueLabelComponent,
|
|
40
|
+
}, onChange: (_, val) => {
|
|
35
41
|
setValue(val);
|
|
36
42
|
} }), _jsx(Tooltip, { title: "Zoom in 2x", children: _jsx("span", { children: _jsx(IconButton, { "data-testid": "zoom_in", disabled: zoomInDisabled, onClick: () => {
|
|
37
43
|
model.zoom(model.bpPerPx / 2);
|
|
@@ -3,7 +3,7 @@ import { useEffect, useState } from 'react';
|
|
|
3
3
|
import { AssemblySelector, ErrorMessage } from '@jbrowse/core/ui';
|
|
4
4
|
import { getSession } from '@jbrowse/core/util';
|
|
5
5
|
import CloseIcon from '@mui/icons-material/Close';
|
|
6
|
-
import { Button, CircularProgress, Container, FormControl,
|
|
6
|
+
import { Button, CircularProgress, Container, FormControl, Grid as Grid, } from '@mui/material';
|
|
7
7
|
import { observer } from 'mobx-react';
|
|
8
8
|
import { makeStyles } from 'tss-react/mui';
|
|
9
9
|
import ImportFormRefNameAutocomplete from './ImportFormRefNameAutocomplete';
|
|
@@ -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
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { getBpDisplayStr, stringify } from '@jbrowse/core/util';
|
|
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,35 +21,17 @@ 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 ? (_jsx(Typography, { ref: el => {
|
|
49
32
|
setAnchorEl(el);
|
|
50
33
|
}, variant: "h6", className: classes.rubberbandText, style: {
|
|
51
34
|
top,
|
|
52
35
|
position: sticky ? 'sticky' : undefined,
|
|
53
|
-
}, children:
|
|
36
|
+
}, children: getBpDisplayStr(numOfBpSelected) })) : null })] }));
|
|
54
37
|
}
|
|
@@ -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: {
|