@jbrowse/sv-core 2.16.1 → 2.18.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/BreakendMultiLevelOptionDialog.d.ts +5 -16
- package/dist/BreakendMultiLevelOptionDialog.js +54 -46
- package/dist/BreakendSingleLevelOptionDialog.d.ts +5 -16
- package/dist/BreakendSingleLevelOptionDialog.js +19 -45
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -0
- package/dist/util.d.ts +61 -0
- package/dist/util.js +207 -0
- package/esm/BreakendMultiLevelOptionDialog.d.ts +5 -16
- package/esm/BreakendMultiLevelOptionDialog.js +54 -46
- package/esm/BreakendSingleLevelOptionDialog.d.ts +5 -16
- package/esm/BreakendSingleLevelOptionDialog.js +20 -46
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/util.d.ts +61 -0
- package/esm/util.js +201 -0
- package/package.json +5 -3
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Feature } from '@jbrowse/core/util';
|
|
2
|
+
import type { AbstractSessionModel, Feature } from '@jbrowse/core/util';
|
|
3
3
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
model: unknown;
|
|
4
|
+
declare const BreakendMultiLevelOptionDialog: ({ session, handleClose, feature, assemblyName, stableViewId, view, }: {
|
|
5
|
+
session: AbstractSessionModel;
|
|
7
6
|
handleClose: () => void;
|
|
8
7
|
feature: Feature;
|
|
9
|
-
view
|
|
8
|
+
view?: LinearGenomeViewModel;
|
|
10
9
|
assemblyName: string;
|
|
11
|
-
|
|
12
|
-
getBreakendCoveringRegions: (arg: {
|
|
13
|
-
feature: Feature;
|
|
14
|
-
assembly: Assembly;
|
|
15
|
-
}) => {
|
|
16
|
-
pos: number;
|
|
17
|
-
refName: string;
|
|
18
|
-
mateRefName: string;
|
|
19
|
-
matePos: number;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
10
|
+
stableViewId?: string;
|
|
22
11
|
}) => React.JSX.Element;
|
|
23
12
|
export default BreakendMultiLevelOptionDialog;
|
|
@@ -27,70 +27,78 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
const react_1 = __importStar(require("react"));
|
|
30
|
-
const mobx_react_1 = require("mobx-react");
|
|
31
|
-
const material_1 = require("@mui/material");
|
|
32
|
-
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
33
30
|
const ui_1 = require("@jbrowse/core/ui");
|
|
31
|
+
const material_1 = require("@mui/material");
|
|
34
32
|
const mobx_1 = require("mobx");
|
|
35
|
-
const
|
|
36
|
-
|
|
33
|
+
const mobx_react_1 = require("mobx-react");
|
|
34
|
+
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
37
35
|
const Checkbox2_1 = __importDefault(require("./Checkbox2"));
|
|
36
|
+
const util_1 = require("./util");
|
|
38
37
|
function stripIds(arr) {
|
|
39
38
|
return arr.map(({ id, displays, ...rest }) => ({
|
|
40
39
|
...rest,
|
|
41
40
|
displays: displays.map(({ id, ...rest }) => rest),
|
|
42
41
|
}));
|
|
43
42
|
}
|
|
44
|
-
const BreakendMultiLevelOptionDialog = (0, mobx_react_1.observer)(function ({
|
|
43
|
+
const BreakendMultiLevelOptionDialog = (0, mobx_react_1.observer)(function ({ session, handleClose, feature, assemblyName, stableViewId, view, }) {
|
|
45
44
|
const [copyTracks, setCopyTracks] = (0, react_1.useState)(true);
|
|
46
45
|
const [mirror, setMirror] = (0, react_1.useState)(true);
|
|
47
46
|
return (react_1.default.createElement(ui_1.Dialog, { open: true, onClose: handleClose, title: "Multi-level breakpoint split view options" },
|
|
48
47
|
react_1.default.createElement(material_1.DialogContent, null,
|
|
49
|
-
react_1.default.createElement(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
react_1.default.createElement("div", null, "Launch multi-level breakpoint split view"),
|
|
49
|
+
view ? (react_1.default.createElement(react_1.default.Fragment, null,
|
|
50
|
+
react_1.default.createElement(Checkbox2_1.default, { checked: copyTracks, label: "Copy tracks into the new view", onChange: event => {
|
|
51
|
+
setCopyTracks(event.target.checked);
|
|
52
|
+
} }),
|
|
53
|
+
copyTracks ? (react_1.default.createElement(Checkbox2_1.default, { checked: mirror, disabled: !copyTracks, label: "Mirror the copied tracks (only available if copying tracks and using two level)", onChange: event => {
|
|
54
|
+
setMirror(event.target.checked);
|
|
55
|
+
} })) : null)) : null),
|
|
55
56
|
react_1.default.createElement(material_1.DialogActions, null,
|
|
56
57
|
react_1.default.createElement(material_1.Button, { onClick: () => {
|
|
57
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
58
58
|
;
|
|
59
59
|
(async () => {
|
|
60
|
-
const session = (0, util_1.getSession)(model);
|
|
61
60
|
try {
|
|
62
|
-
const
|
|
63
|
-
|
|
61
|
+
const { assemblyManager } = session;
|
|
62
|
+
const assembly = await assemblyManager.waitForAssembly(assemblyName);
|
|
63
|
+
if (!assembly) {
|
|
64
64
|
throw new Error(`assembly ${assemblyName} not found`);
|
|
65
65
|
}
|
|
66
|
-
const { refName, pos, mateRefName, matePos } =
|
|
66
|
+
const { refName, pos, mateRefName, matePos } = (0, util_1.getBreakendCoveringRegions)({
|
|
67
67
|
feature,
|
|
68
|
-
assembly:
|
|
68
|
+
assembly: assembly,
|
|
69
69
|
});
|
|
70
|
-
const viewTracks =
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
70
|
+
const viewTracks = view
|
|
71
|
+
? (0, mobx_state_tree_1.getSnapshot)(view.tracks)
|
|
72
|
+
: [];
|
|
73
|
+
let viewInStack = session.views.find(f => f.id === stableViewId);
|
|
74
|
+
const displayName = `${feature.get('name') || feature.get('id') || 'breakend'} split detail`;
|
|
75
|
+
if (!viewInStack) {
|
|
76
|
+
viewInStack = session.addView('BreakpointSplitView', {
|
|
77
|
+
id: stableViewId,
|
|
78
|
+
type: 'BreakpointSplitView',
|
|
79
|
+
displayName,
|
|
80
|
+
views: [
|
|
81
|
+
{
|
|
82
|
+
type: 'LinearGenomeView',
|
|
83
|
+
hideHeader: true,
|
|
84
|
+
tracks: stripIds(viewTracks),
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
type: 'LinearGenomeView',
|
|
88
|
+
hideHeader: true,
|
|
89
|
+
tracks: stripIds(mirror ? [...viewTracks].reverse() : viewTracks),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
viewInStack.setDisplayName(displayName);
|
|
95
|
+
const r1 = assembly.regions.find(r => r.refName === refName);
|
|
96
|
+
const r2 = assembly.regions.find(r => r.refName === mateRefName);
|
|
89
97
|
if (!r1 || !r2) {
|
|
90
98
|
throw new Error("can't find regions");
|
|
91
99
|
}
|
|
92
100
|
await Promise.all([
|
|
93
|
-
|
|
101
|
+
viewInStack.views[0].navToLocations([
|
|
94
102
|
{
|
|
95
103
|
refName,
|
|
96
104
|
start: r1.start,
|
|
@@ -104,7 +112,7 @@ const BreakendMultiLevelOptionDialog = (0, mobx_react_1.observer)(function ({ mo
|
|
|
104
112
|
assemblyName,
|
|
105
113
|
},
|
|
106
114
|
]),
|
|
107
|
-
|
|
115
|
+
viewInStack.views[1].navToLocations([
|
|
108
116
|
{
|
|
109
117
|
refName: mateRefName,
|
|
110
118
|
start: r2.start,
|
|
@@ -119,16 +127,16 @@ const BreakendMultiLevelOptionDialog = (0, mobx_react_1.observer)(function ({ mo
|
|
|
119
127
|
},
|
|
120
128
|
]),
|
|
121
129
|
]);
|
|
122
|
-
await (0, mobx_1.when)(() =>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
130
|
+
await (0, mobx_1.when)(() => viewInStack.views[1].initialized &&
|
|
131
|
+
viewInStack.views[0].initialized);
|
|
132
|
+
viewInStack.views[1].zoomTo(10);
|
|
133
|
+
viewInStack.views[0].zoomTo(10);
|
|
134
|
+
viewInStack.views[1].centerAt(matePos, mateRefName);
|
|
135
|
+
viewInStack.views[0].centerAt(pos, refName);
|
|
128
136
|
}
|
|
129
137
|
catch (e) {
|
|
130
138
|
console.error(e);
|
|
131
|
-
session.
|
|
139
|
+
session.notifyError(`${e}`, e);
|
|
132
140
|
}
|
|
133
141
|
})();
|
|
134
142
|
handleClose();
|
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Feature } from '@jbrowse/core/util';
|
|
2
|
+
import type { AbstractSessionModel, Feature } from '@jbrowse/core/util';
|
|
3
3
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
model: unknown;
|
|
4
|
+
declare const BreakendSingleLevelOptionDialog: ({ session, handleClose, feature, stableViewId, assemblyName, view, }: {
|
|
5
|
+
session: AbstractSessionModel;
|
|
7
6
|
handleClose: () => void;
|
|
7
|
+
stableViewId?: string;
|
|
8
8
|
feature: Feature;
|
|
9
|
-
view
|
|
9
|
+
view?: LinearGenomeViewModel;
|
|
10
10
|
assemblyName: string;
|
|
11
|
-
viewType: {
|
|
12
|
-
getBreakendCoveringRegions: (arg: {
|
|
13
|
-
feature: Feature;
|
|
14
|
-
assembly: Assembly;
|
|
15
|
-
}) => {
|
|
16
|
-
pos: number;
|
|
17
|
-
refName: string;
|
|
18
|
-
mateRefName: string;
|
|
19
|
-
matePos: number;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
11
|
}) => React.JSX.Element;
|
|
23
12
|
export default BreakendSingleLevelOptionDialog;
|
|
@@ -27,71 +27,45 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
const react_1 = __importStar(require("react"));
|
|
30
|
-
const mobx_react_1 = require("mobx-react");
|
|
31
|
-
const material_1 = require("@mui/material");
|
|
32
|
-
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
33
30
|
const ui_1 = require("@jbrowse/core/ui");
|
|
34
31
|
const util_1 = require("@jbrowse/core/util");
|
|
35
|
-
|
|
32
|
+
const material_1 = require("@mui/material");
|
|
33
|
+
const mobx_react_1 = require("mobx-react");
|
|
36
34
|
const Checkbox2_1 = __importDefault(require("./Checkbox2"));
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
...rest,
|
|
40
|
-
displays: displays.map(({ id, ...rest }) => rest),
|
|
41
|
-
}));
|
|
42
|
-
}
|
|
43
|
-
const BreakendSingleLevelOptionDialog = (0, mobx_react_1.observer)(function ({ model, handleClose, feature, assemblyName, viewType, view, }) {
|
|
35
|
+
const util_2 = require("./util");
|
|
36
|
+
const BreakendSingleLevelOptionDialog = (0, mobx_react_1.observer)(function ({ session, handleClose, feature, stableViewId, assemblyName, view, }) {
|
|
44
37
|
const [copyTracks, setCopyTracks] = (0, react_1.useState)(true);
|
|
45
38
|
const [windowSize, setWindowSize] = (0, util_1.useLocalStorage)('breakpointWindowSize', '5000');
|
|
46
39
|
return (react_1.default.createElement(ui_1.Dialog, { open: true, onClose: handleClose, title: "Single-level breakpoint split view options" },
|
|
47
40
|
react_1.default.createElement(material_1.DialogContent, null,
|
|
48
|
-
react_1.default.createElement(Checkbox2_1.default, { checked: copyTracks, label: "Copy tracks into the new view", onChange: event => {
|
|
41
|
+
view ? (react_1.default.createElement(Checkbox2_1.default, { checked: copyTracks, label: "Copy tracks into the new view", onChange: event => {
|
|
49
42
|
setCopyTracks(event.target.checked);
|
|
50
|
-
} }),
|
|
43
|
+
} })) : null,
|
|
51
44
|
react_1.default.createElement(material_1.TextField, { label: "Window size (bp)", value: windowSize, onChange: event => {
|
|
52
45
|
setWindowSize(event.target.value);
|
|
53
46
|
} })),
|
|
54
47
|
react_1.default.createElement(material_1.DialogActions, null,
|
|
55
48
|
react_1.default.createElement(material_1.Button, { onClick: () => {
|
|
56
|
-
|
|
49
|
+
;
|
|
57
50
|
(async () => {
|
|
58
51
|
try {
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
if (
|
|
62
|
-
throw new Error(
|
|
52
|
+
const { assemblyManager } = session;
|
|
53
|
+
const assembly = await assemblyManager.waitForAssembly(assemblyName);
|
|
54
|
+
if (!assembly) {
|
|
55
|
+
throw new Error(`assembly ${assemblyName} not found`);
|
|
63
56
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
{
|
|
72
|
-
type: 'LinearGenomeView',
|
|
73
|
-
tracks: stripIds((0, mobx_state_tree_1.getSnapshot)(view.tracks)),
|
|
74
|
-
},
|
|
75
|
-
],
|
|
57
|
+
await (0, util_2.navToSingleLevelBreak)({
|
|
58
|
+
feature,
|
|
59
|
+
assemblyName,
|
|
60
|
+
session,
|
|
61
|
+
stableViewId,
|
|
62
|
+
tracks: view === null || view === void 0 ? void 0 : view.tracks,
|
|
63
|
+
windowSize: +windowSize || 0,
|
|
76
64
|
});
|
|
77
|
-
await breakpointSplitView.views[0].navToLocations((0, util_1.gatherOverlaps)([
|
|
78
|
-
{
|
|
79
|
-
refName,
|
|
80
|
-
start: Math.max(0, pos - w),
|
|
81
|
-
end: pos + w,
|
|
82
|
-
assemblyName,
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
refName: mateRefName,
|
|
86
|
-
start: Math.max(0, matePos - w),
|
|
87
|
-
end: matePos + w,
|
|
88
|
-
assemblyName,
|
|
89
|
-
},
|
|
90
|
-
], w));
|
|
91
65
|
}
|
|
92
66
|
catch (e) {
|
|
93
67
|
console.error(e);
|
|
94
|
-
session.
|
|
68
|
+
session.notifyError(`${e}`, e);
|
|
95
69
|
}
|
|
96
70
|
})();
|
|
97
71
|
handleClose();
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
18
|
};
|
|
@@ -8,3 +22,4 @@ var BreakendMultiLevelOptionDialog_1 = require("./BreakendMultiLevelOptionDialog
|
|
|
8
22
|
Object.defineProperty(exports, "BreakendMultiLevelOptionDialog", { enumerable: true, get: function () { return __importDefault(BreakendMultiLevelOptionDialog_1).default; } });
|
|
9
23
|
var BreakendSingleLevelOptionDialog_1 = require("./BreakendSingleLevelOptionDialog");
|
|
10
24
|
Object.defineProperty(exports, "BreakendSingleLevelOptionDialog", { enumerable: true, get: function () { return __importDefault(BreakendSingleLevelOptionDialog_1).default; } });
|
|
25
|
+
__exportStar(require("./util"), exports);
|
package/dist/util.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly';
|
|
2
|
+
import type { AbstractSessionModel, Feature } from '@jbrowse/core/util';
|
|
3
|
+
export interface Display {
|
|
4
|
+
id: string;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface Track {
|
|
8
|
+
id: string;
|
|
9
|
+
displays: Display[];
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export declare function getBreakendCoveringRegions({ feature, assembly, }: {
|
|
13
|
+
feature: Feature;
|
|
14
|
+
assembly: Assembly;
|
|
15
|
+
}): {
|
|
16
|
+
pos: number;
|
|
17
|
+
refName: string;
|
|
18
|
+
mateRefName: string;
|
|
19
|
+
matePos: any;
|
|
20
|
+
};
|
|
21
|
+
export declare function singleLevelSnapshotFromBreakendFeature({ feature, session, assemblyName, }: {
|
|
22
|
+
feature: Feature;
|
|
23
|
+
session: AbstractSessionModel;
|
|
24
|
+
assemblyName: string;
|
|
25
|
+
}): {
|
|
26
|
+
coverage: {
|
|
27
|
+
pos: number;
|
|
28
|
+
refName: string;
|
|
29
|
+
mateRefName: string;
|
|
30
|
+
matePos: any;
|
|
31
|
+
};
|
|
32
|
+
snap: {
|
|
33
|
+
type: string;
|
|
34
|
+
views: {
|
|
35
|
+
type: string;
|
|
36
|
+
displayedRegions: {
|
|
37
|
+
assemblyName: string;
|
|
38
|
+
start: number;
|
|
39
|
+
end: number;
|
|
40
|
+
refName: string;
|
|
41
|
+
}[];
|
|
42
|
+
}[];
|
|
43
|
+
displayName: string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
export declare function navToSingleLevelBreak({ stableViewId, feature, assemblyName, session, tracks, windowSize, }: {
|
|
47
|
+
stableViewId?: string;
|
|
48
|
+
feature: Feature;
|
|
49
|
+
assemblyName: string;
|
|
50
|
+
windowSize?: number;
|
|
51
|
+
session: AbstractSessionModel;
|
|
52
|
+
tracks?: any;
|
|
53
|
+
}): Promise<void>;
|
|
54
|
+
export declare function navToMultiLevelBreak({ stableViewId, feature, assemblyName, session, tracks, }: {
|
|
55
|
+
stableViewId?: string;
|
|
56
|
+
feature: Feature;
|
|
57
|
+
assemblyName: string;
|
|
58
|
+
windowSize?: number;
|
|
59
|
+
session: AbstractSessionModel;
|
|
60
|
+
tracks?: any;
|
|
61
|
+
}): Promise<void>;
|
package/dist/util.js
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getBreakendCoveringRegions = getBreakendCoveringRegions;
|
|
4
|
+
exports.singleLevelSnapshotFromBreakendFeature = singleLevelSnapshotFromBreakendFeature;
|
|
5
|
+
exports.navToSingleLevelBreak = navToSingleLevelBreak;
|
|
6
|
+
exports.navToMultiLevelBreak = navToMultiLevelBreak;
|
|
7
|
+
const vcf_1 = require("@gmod/vcf");
|
|
8
|
+
const util_1 = require("@jbrowse/core/util");
|
|
9
|
+
const mobx_1 = require("mobx");
|
|
10
|
+
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
11
|
+
function stripIds(arr) {
|
|
12
|
+
return arr.map(({ id, displays, ...rest }) => ({
|
|
13
|
+
...rest,
|
|
14
|
+
displays: displays.map(({ id, ...rest }) => rest),
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
function getBreakendCoveringRegions({ feature, assembly, }) {
|
|
18
|
+
var _a;
|
|
19
|
+
const alt = (_a = feature.get('ALT')) === null || _a === void 0 ? void 0 : _a[0];
|
|
20
|
+
const bnd = alt ? (0, vcf_1.parseBreakend)(alt) : undefined;
|
|
21
|
+
const startPos = feature.get('start');
|
|
22
|
+
const refName = feature.get('refName');
|
|
23
|
+
const f = (ref) => assembly.getCanonicalRefName(ref) || ref;
|
|
24
|
+
if (alt === '<TRA>') {
|
|
25
|
+
const INFO = feature.get('INFO');
|
|
26
|
+
return {
|
|
27
|
+
pos: startPos,
|
|
28
|
+
refName: f(refName),
|
|
29
|
+
mateRefName: f(INFO.CHR2[0]),
|
|
30
|
+
matePos: INFO.END[0] - 1,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
else if (bnd === null || bnd === void 0 ? void 0 : bnd.MatePosition) {
|
|
34
|
+
const matePosition = bnd.MatePosition.split(':');
|
|
35
|
+
return {
|
|
36
|
+
pos: startPos,
|
|
37
|
+
refName: f(refName),
|
|
38
|
+
mateRefName: f(matePosition[0]),
|
|
39
|
+
matePos: +matePosition[1] - 1,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
else if (feature.get('mate')) {
|
|
43
|
+
const mate = feature.get('mate');
|
|
44
|
+
return {
|
|
45
|
+
pos: startPos,
|
|
46
|
+
refName: f(refName),
|
|
47
|
+
mateRefName: f(mate.refName),
|
|
48
|
+
matePos: mate.start,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
return {
|
|
53
|
+
pos: startPos,
|
|
54
|
+
refName: f(refName),
|
|
55
|
+
mateRefName: f(refName),
|
|
56
|
+
matePos: feature.get('end'),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function singleLevelSnapshotFromBreakendFeature({ feature, session, assemblyName, }) {
|
|
61
|
+
const { assemblyManager } = session;
|
|
62
|
+
const assembly = assemblyManager.get(assemblyName);
|
|
63
|
+
if (!assembly) {
|
|
64
|
+
throw new Error(`assembly ${assemblyName} not found`);
|
|
65
|
+
}
|
|
66
|
+
if (!assembly.regions) {
|
|
67
|
+
throw new Error(`assembly ${assemblyName} regions not loaded`);
|
|
68
|
+
}
|
|
69
|
+
const coverage = getBreakendCoveringRegions({
|
|
70
|
+
feature,
|
|
71
|
+
assembly,
|
|
72
|
+
});
|
|
73
|
+
const { refName, mateRefName } = coverage;
|
|
74
|
+
const topRegion = assembly.regions.find(f => f.refName === refName);
|
|
75
|
+
const bottomRegion = assembly.regions.find(f => f.refName === mateRefName);
|
|
76
|
+
return {
|
|
77
|
+
coverage,
|
|
78
|
+
snap: {
|
|
79
|
+
type: 'BreakpointSplitView',
|
|
80
|
+
views: [
|
|
81
|
+
{
|
|
82
|
+
type: 'LinearGenomeView',
|
|
83
|
+
displayedRegions: (0, util_1.gatherOverlaps)([
|
|
84
|
+
{ ...topRegion, assemblyName },
|
|
85
|
+
{ ...bottomRegion, assemblyName },
|
|
86
|
+
]),
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
displayName: `${feature.get('name') || feature.get('id') || 'breakend'} split detail`,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async function navToSingleLevelBreak({ stableViewId, feature, assemblyName, session, tracks, windowSize = 0, }) {
|
|
94
|
+
var _a;
|
|
95
|
+
const { snap, coverage } = singleLevelSnapshotFromBreakendFeature({
|
|
96
|
+
feature,
|
|
97
|
+
assemblyName,
|
|
98
|
+
session,
|
|
99
|
+
});
|
|
100
|
+
const { refName, pos: startPos, mateRefName, matePos: endPos } = coverage;
|
|
101
|
+
let viewInStack = session.views.find(f => f.id === stableViewId);
|
|
102
|
+
if (!viewInStack) {
|
|
103
|
+
viewInStack = session.addView('BreakpointSplitView', {
|
|
104
|
+
...snap,
|
|
105
|
+
views: [
|
|
106
|
+
{
|
|
107
|
+
...snap.views[0],
|
|
108
|
+
tracks: tracks ? stripIds((0, mobx_state_tree_1.getSnapshot)(tracks)) : [],
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
(_a = viewInStack.views[0]) === null || _a === void 0 ? void 0 : _a.setDisplayedRegions(snap.views[0].displayedRegions);
|
|
115
|
+
viewInStack.setDisplayName(snap.displayName);
|
|
116
|
+
}
|
|
117
|
+
const lgv = viewInStack.views[0];
|
|
118
|
+
await (0, util_1.when)(() => lgv.initialized);
|
|
119
|
+
const l0 = lgv.bpToPx({
|
|
120
|
+
coord: Math.max(0, startPos - windowSize),
|
|
121
|
+
refName,
|
|
122
|
+
});
|
|
123
|
+
const r0 = lgv.bpToPx({
|
|
124
|
+
coord: endPos + windowSize,
|
|
125
|
+
refName: mateRefName,
|
|
126
|
+
});
|
|
127
|
+
if (l0 && r0) {
|
|
128
|
+
lgv.moveTo({ ...l0, offset: l0.offsetPx }, { ...r0, offset: r0.offsetPx });
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
(0, util_1.getSession)(lgv).notify('Unable to navigate to breakpoint');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function navToMultiLevelBreak({ stableViewId, feature, assemblyName, session, tracks, }) {
|
|
135
|
+
const bpPerPx = 10;
|
|
136
|
+
const { assemblyManager } = session;
|
|
137
|
+
const assembly = assemblyManager.get(assemblyName);
|
|
138
|
+
if (!assembly) {
|
|
139
|
+
throw new Error(`assembly ${assemblyName} not found`);
|
|
140
|
+
}
|
|
141
|
+
if (!assembly.regions) {
|
|
142
|
+
throw new Error(`assembly ${assemblyName} regions not loaded`);
|
|
143
|
+
}
|
|
144
|
+
const { refName, pos: startPos, mateRefName, matePos: endPos, } = getBreakendCoveringRegions({
|
|
145
|
+
feature,
|
|
146
|
+
assembly,
|
|
147
|
+
});
|
|
148
|
+
const topRegion = assembly.regions.find(f => f.refName === refName);
|
|
149
|
+
const bottomRegion = assembly.regions.find(f => f.refName === mateRefName);
|
|
150
|
+
const topMarkedRegion = [{ ...topRegion }, { ...topRegion }];
|
|
151
|
+
const bottomMarkedRegion = [{ ...bottomRegion }, { ...bottomRegion }];
|
|
152
|
+
topMarkedRegion[0].end = startPos;
|
|
153
|
+
topMarkedRegion[1].start = startPos;
|
|
154
|
+
bottomMarkedRegion[0].end = endPos;
|
|
155
|
+
bottomMarkedRegion[1].start = endPos;
|
|
156
|
+
const snap = {
|
|
157
|
+
type: 'BreakpointSplitView',
|
|
158
|
+
views: [
|
|
159
|
+
{
|
|
160
|
+
type: 'LinearGenomeView',
|
|
161
|
+
displayedRegions: topMarkedRegion,
|
|
162
|
+
hideHeader: true,
|
|
163
|
+
bpPerPx,
|
|
164
|
+
offsetPx: (topRegion.start + feature.get('start')) / bpPerPx,
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
type: 'LinearGenomeView',
|
|
168
|
+
displayedRegions: bottomMarkedRegion,
|
|
169
|
+
hideHeader: true,
|
|
170
|
+
bpPerPx,
|
|
171
|
+
tracks,
|
|
172
|
+
offsetPx: (bottomRegion.start + endPos) / bpPerPx,
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
displayName: `${feature.get('name') || feature.get('id') || 'breakend'} split detail`,
|
|
176
|
+
};
|
|
177
|
+
let viewInStack = session.views.find(f => f.id === stableViewId);
|
|
178
|
+
if (!viewInStack) {
|
|
179
|
+
viewInStack = session.addView('BreakpointSplitView', {
|
|
180
|
+
...snap,
|
|
181
|
+
id: stableViewId,
|
|
182
|
+
views: [
|
|
183
|
+
{
|
|
184
|
+
...snap.views[0],
|
|
185
|
+
tracks: tracks ? stripIds((0, mobx_state_tree_1.getSnapshot)(tracks)) : [],
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
...snap.views[1],
|
|
189
|
+
tracks: (tracks ? stripIds((0, mobx_state_tree_1.getSnapshot)(tracks)) : []).reverse(),
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
(0, mobx_1.transaction)(() => {
|
|
196
|
+
for (let i = 0; i < viewInStack.views.length; i++) {
|
|
197
|
+
const s = snap.views[i];
|
|
198
|
+
if (s) {
|
|
199
|
+
viewInStack.views[i].setDisplayedRegions(s.displayedRegions);
|
|
200
|
+
viewInStack.views[i].scrollTo(s.offsetPx - 800);
|
|
201
|
+
viewInStack.views[i].zoomTo(s.bpPerPx);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
viewInStack.setDisplayName(snap.displayName);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Feature } from '@jbrowse/core/util';
|
|
2
|
+
import type { AbstractSessionModel, Feature } from '@jbrowse/core/util';
|
|
3
3
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
model: unknown;
|
|
4
|
+
declare const BreakendMultiLevelOptionDialog: ({ session, handleClose, feature, assemblyName, stableViewId, view, }: {
|
|
5
|
+
session: AbstractSessionModel;
|
|
7
6
|
handleClose: () => void;
|
|
8
7
|
feature: Feature;
|
|
9
|
-
view
|
|
8
|
+
view?: LinearGenomeViewModel;
|
|
10
9
|
assemblyName: string;
|
|
11
|
-
|
|
12
|
-
getBreakendCoveringRegions: (arg: {
|
|
13
|
-
feature: Feature;
|
|
14
|
-
assembly: Assembly;
|
|
15
|
-
}) => {
|
|
16
|
-
pos: number;
|
|
17
|
-
refName: string;
|
|
18
|
-
mateRefName: string;
|
|
19
|
-
matePos: number;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
10
|
+
stableViewId?: string;
|
|
22
11
|
}) => React.JSX.Element;
|
|
23
12
|
export default BreakendMultiLevelOptionDialog;
|
|
@@ -1,68 +1,76 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { observer } from 'mobx-react';
|
|
3
|
-
import { Button, DialogActions, DialogContent } from '@mui/material';
|
|
4
|
-
import { getSnapshot } from 'mobx-state-tree';
|
|
5
2
|
import { Dialog } from '@jbrowse/core/ui';
|
|
3
|
+
import { Button, DialogActions, DialogContent } from '@mui/material';
|
|
6
4
|
import { when } from 'mobx';
|
|
7
|
-
import {
|
|
8
|
-
|
|
5
|
+
import { observer } from 'mobx-react';
|
|
6
|
+
import { getSnapshot } from 'mobx-state-tree';
|
|
9
7
|
import Checkbox2 from './Checkbox2';
|
|
8
|
+
import { getBreakendCoveringRegions } from './util';
|
|
10
9
|
function stripIds(arr) {
|
|
11
10
|
return arr.map(({ id, displays, ...rest }) => ({
|
|
12
11
|
...rest,
|
|
13
12
|
displays: displays.map(({ id, ...rest }) => rest),
|
|
14
13
|
}));
|
|
15
14
|
}
|
|
16
|
-
const BreakendMultiLevelOptionDialog = observer(function ({
|
|
15
|
+
const BreakendMultiLevelOptionDialog = observer(function ({ session, handleClose, feature, assemblyName, stableViewId, view, }) {
|
|
17
16
|
const [copyTracks, setCopyTracks] = useState(true);
|
|
18
17
|
const [mirror, setMirror] = useState(true);
|
|
19
18
|
return (React.createElement(Dialog, { open: true, onClose: handleClose, title: "Multi-level breakpoint split view options" },
|
|
20
19
|
React.createElement(DialogContent, null,
|
|
21
|
-
React.createElement(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
React.createElement("div", null, "Launch multi-level breakpoint split view"),
|
|
21
|
+
view ? (React.createElement(React.Fragment, null,
|
|
22
|
+
React.createElement(Checkbox2, { checked: copyTracks, label: "Copy tracks into the new view", onChange: event => {
|
|
23
|
+
setCopyTracks(event.target.checked);
|
|
24
|
+
} }),
|
|
25
|
+
copyTracks ? (React.createElement(Checkbox2, { checked: mirror, disabled: !copyTracks, label: "Mirror the copied tracks (only available if copying tracks and using two level)", onChange: event => {
|
|
26
|
+
setMirror(event.target.checked);
|
|
27
|
+
} })) : null)) : null),
|
|
27
28
|
React.createElement(DialogActions, null,
|
|
28
29
|
React.createElement(Button, { onClick: () => {
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
30
30
|
;
|
|
31
31
|
(async () => {
|
|
32
|
-
const session = getSession(model);
|
|
33
32
|
try {
|
|
34
|
-
const
|
|
35
|
-
|
|
33
|
+
const { assemblyManager } = session;
|
|
34
|
+
const assembly = await assemblyManager.waitForAssembly(assemblyName);
|
|
35
|
+
if (!assembly) {
|
|
36
36
|
throw new Error(`assembly ${assemblyName} not found`);
|
|
37
37
|
}
|
|
38
|
-
const { refName, pos, mateRefName, matePos } =
|
|
38
|
+
const { refName, pos, mateRefName, matePos } = getBreakendCoveringRegions({
|
|
39
39
|
feature,
|
|
40
|
-
assembly:
|
|
40
|
+
assembly: assembly,
|
|
41
41
|
});
|
|
42
|
-
const viewTracks =
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
42
|
+
const viewTracks = view
|
|
43
|
+
? getSnapshot(view.tracks)
|
|
44
|
+
: [];
|
|
45
|
+
let viewInStack = session.views.find(f => f.id === stableViewId);
|
|
46
|
+
const displayName = `${feature.get('name') || feature.get('id') || 'breakend'} split detail`;
|
|
47
|
+
if (!viewInStack) {
|
|
48
|
+
viewInStack = session.addView('BreakpointSplitView', {
|
|
49
|
+
id: stableViewId,
|
|
50
|
+
type: 'BreakpointSplitView',
|
|
51
|
+
displayName,
|
|
52
|
+
views: [
|
|
53
|
+
{
|
|
54
|
+
type: 'LinearGenomeView',
|
|
55
|
+
hideHeader: true,
|
|
56
|
+
tracks: stripIds(viewTracks),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'LinearGenomeView',
|
|
60
|
+
hideHeader: true,
|
|
61
|
+
tracks: stripIds(mirror ? [...viewTracks].reverse() : viewTracks),
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
viewInStack.setDisplayName(displayName);
|
|
67
|
+
const r1 = assembly.regions.find(r => r.refName === refName);
|
|
68
|
+
const r2 = assembly.regions.find(r => r.refName === mateRefName);
|
|
61
69
|
if (!r1 || !r2) {
|
|
62
70
|
throw new Error("can't find regions");
|
|
63
71
|
}
|
|
64
72
|
await Promise.all([
|
|
65
|
-
|
|
73
|
+
viewInStack.views[0].navToLocations([
|
|
66
74
|
{
|
|
67
75
|
refName,
|
|
68
76
|
start: r1.start,
|
|
@@ -76,7 +84,7 @@ const BreakendMultiLevelOptionDialog = observer(function ({ model, handleClose,
|
|
|
76
84
|
assemblyName,
|
|
77
85
|
},
|
|
78
86
|
]),
|
|
79
|
-
|
|
87
|
+
viewInStack.views[1].navToLocations([
|
|
80
88
|
{
|
|
81
89
|
refName: mateRefName,
|
|
82
90
|
start: r2.start,
|
|
@@ -91,16 +99,16 @@ const BreakendMultiLevelOptionDialog = observer(function ({ model, handleClose,
|
|
|
91
99
|
},
|
|
92
100
|
]),
|
|
93
101
|
]);
|
|
94
|
-
await when(() =>
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
await when(() => viewInStack.views[1].initialized &&
|
|
103
|
+
viewInStack.views[0].initialized);
|
|
104
|
+
viewInStack.views[1].zoomTo(10);
|
|
105
|
+
viewInStack.views[0].zoomTo(10);
|
|
106
|
+
viewInStack.views[1].centerAt(matePos, mateRefName);
|
|
107
|
+
viewInStack.views[0].centerAt(pos, refName);
|
|
100
108
|
}
|
|
101
109
|
catch (e) {
|
|
102
110
|
console.error(e);
|
|
103
|
-
session.
|
|
111
|
+
session.notifyError(`${e}`, e);
|
|
104
112
|
}
|
|
105
113
|
})();
|
|
106
114
|
handleClose();
|
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Feature } from '@jbrowse/core/util';
|
|
2
|
+
import type { AbstractSessionModel, Feature } from '@jbrowse/core/util';
|
|
3
3
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
model: unknown;
|
|
4
|
+
declare const BreakendSingleLevelOptionDialog: ({ session, handleClose, feature, stableViewId, assemblyName, view, }: {
|
|
5
|
+
session: AbstractSessionModel;
|
|
7
6
|
handleClose: () => void;
|
|
7
|
+
stableViewId?: string;
|
|
8
8
|
feature: Feature;
|
|
9
|
-
view
|
|
9
|
+
view?: LinearGenomeViewModel;
|
|
10
10
|
assemblyName: string;
|
|
11
|
-
viewType: {
|
|
12
|
-
getBreakendCoveringRegions: (arg: {
|
|
13
|
-
feature: Feature;
|
|
14
|
-
assembly: Assembly;
|
|
15
|
-
}) => {
|
|
16
|
-
pos: number;
|
|
17
|
-
refName: string;
|
|
18
|
-
mateRefName: string;
|
|
19
|
-
matePos: number;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
11
|
}) => React.JSX.Element;
|
|
23
12
|
export default BreakendSingleLevelOptionDialog;
|
|
@@ -1,69 +1,43 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { observer } from 'mobx-react';
|
|
3
|
-
import { Button, DialogActions, DialogContent, TextField } from '@mui/material';
|
|
4
|
-
import { getSnapshot } from 'mobx-state-tree';
|
|
5
2
|
import { Dialog } from '@jbrowse/core/ui';
|
|
6
|
-
import {
|
|
7
|
-
|
|
3
|
+
import { useLocalStorage } from '@jbrowse/core/util';
|
|
4
|
+
import { Button, DialogActions, DialogContent, TextField } from '@mui/material';
|
|
5
|
+
import { observer } from 'mobx-react';
|
|
8
6
|
import Checkbox2 from './Checkbox2';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
...rest,
|
|
12
|
-
displays: displays.map(({ id, ...rest }) => rest),
|
|
13
|
-
}));
|
|
14
|
-
}
|
|
15
|
-
const BreakendSingleLevelOptionDialog = observer(function ({ model, handleClose, feature, assemblyName, viewType, view, }) {
|
|
7
|
+
import { navToSingleLevelBreak } from './util';
|
|
8
|
+
const BreakendSingleLevelOptionDialog = observer(function ({ session, handleClose, feature, stableViewId, assemblyName, view, }) {
|
|
16
9
|
const [copyTracks, setCopyTracks] = useState(true);
|
|
17
10
|
const [windowSize, setWindowSize] = useLocalStorage('breakpointWindowSize', '5000');
|
|
18
11
|
return (React.createElement(Dialog, { open: true, onClose: handleClose, title: "Single-level breakpoint split view options" },
|
|
19
12
|
React.createElement(DialogContent, null,
|
|
20
|
-
React.createElement(Checkbox2, { checked: copyTracks, label: "Copy tracks into the new view", onChange: event => {
|
|
13
|
+
view ? (React.createElement(Checkbox2, { checked: copyTracks, label: "Copy tracks into the new view", onChange: event => {
|
|
21
14
|
setCopyTracks(event.target.checked);
|
|
22
|
-
} }),
|
|
15
|
+
} })) : null,
|
|
23
16
|
React.createElement(TextField, { label: "Window size (bp)", value: windowSize, onChange: event => {
|
|
24
17
|
setWindowSize(event.target.value);
|
|
25
18
|
} })),
|
|
26
19
|
React.createElement(DialogActions, null,
|
|
27
20
|
React.createElement(Button, { onClick: () => {
|
|
28
|
-
|
|
21
|
+
;
|
|
29
22
|
(async () => {
|
|
30
23
|
try {
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
34
|
-
throw new Error(
|
|
24
|
+
const { assemblyManager } = session;
|
|
25
|
+
const assembly = await assemblyManager.waitForAssembly(assemblyName);
|
|
26
|
+
if (!assembly) {
|
|
27
|
+
throw new Error(`assembly ${assemblyName} not found`);
|
|
35
28
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
{
|
|
44
|
-
type: 'LinearGenomeView',
|
|
45
|
-
tracks: stripIds(getSnapshot(view.tracks)),
|
|
46
|
-
},
|
|
47
|
-
],
|
|
29
|
+
await navToSingleLevelBreak({
|
|
30
|
+
feature,
|
|
31
|
+
assemblyName,
|
|
32
|
+
session,
|
|
33
|
+
stableViewId,
|
|
34
|
+
tracks: view === null || view === void 0 ? void 0 : view.tracks,
|
|
35
|
+
windowSize: +windowSize || 0,
|
|
48
36
|
});
|
|
49
|
-
await breakpointSplitView.views[0].navToLocations(gatherOverlaps([
|
|
50
|
-
{
|
|
51
|
-
refName,
|
|
52
|
-
start: Math.max(0, pos - w),
|
|
53
|
-
end: pos + w,
|
|
54
|
-
assemblyName,
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
refName: mateRefName,
|
|
58
|
-
start: Math.max(0, matePos - w),
|
|
59
|
-
end: matePos + w,
|
|
60
|
-
assemblyName,
|
|
61
|
-
},
|
|
62
|
-
], w));
|
|
63
37
|
}
|
|
64
38
|
catch (e) {
|
|
65
39
|
console.error(e);
|
|
66
|
-
session.
|
|
40
|
+
session.notifyError(`${e}`, e);
|
|
67
41
|
}
|
|
68
42
|
})();
|
|
69
43
|
handleClose();
|
package/esm/index.d.ts
CHANGED
package/esm/index.js
CHANGED
package/esm/util.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly';
|
|
2
|
+
import type { AbstractSessionModel, Feature } from '@jbrowse/core/util';
|
|
3
|
+
export interface Display {
|
|
4
|
+
id: string;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface Track {
|
|
8
|
+
id: string;
|
|
9
|
+
displays: Display[];
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export declare function getBreakendCoveringRegions({ feature, assembly, }: {
|
|
13
|
+
feature: Feature;
|
|
14
|
+
assembly: Assembly;
|
|
15
|
+
}): {
|
|
16
|
+
pos: number;
|
|
17
|
+
refName: string;
|
|
18
|
+
mateRefName: string;
|
|
19
|
+
matePos: any;
|
|
20
|
+
};
|
|
21
|
+
export declare function singleLevelSnapshotFromBreakendFeature({ feature, session, assemblyName, }: {
|
|
22
|
+
feature: Feature;
|
|
23
|
+
session: AbstractSessionModel;
|
|
24
|
+
assemblyName: string;
|
|
25
|
+
}): {
|
|
26
|
+
coverage: {
|
|
27
|
+
pos: number;
|
|
28
|
+
refName: string;
|
|
29
|
+
mateRefName: string;
|
|
30
|
+
matePos: any;
|
|
31
|
+
};
|
|
32
|
+
snap: {
|
|
33
|
+
type: string;
|
|
34
|
+
views: {
|
|
35
|
+
type: string;
|
|
36
|
+
displayedRegions: {
|
|
37
|
+
assemblyName: string;
|
|
38
|
+
start: number;
|
|
39
|
+
end: number;
|
|
40
|
+
refName: string;
|
|
41
|
+
}[];
|
|
42
|
+
}[];
|
|
43
|
+
displayName: string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
export declare function navToSingleLevelBreak({ stableViewId, feature, assemblyName, session, tracks, windowSize, }: {
|
|
47
|
+
stableViewId?: string;
|
|
48
|
+
feature: Feature;
|
|
49
|
+
assemblyName: string;
|
|
50
|
+
windowSize?: number;
|
|
51
|
+
session: AbstractSessionModel;
|
|
52
|
+
tracks?: any;
|
|
53
|
+
}): Promise<void>;
|
|
54
|
+
export declare function navToMultiLevelBreak({ stableViewId, feature, assemblyName, session, tracks, }: {
|
|
55
|
+
stableViewId?: string;
|
|
56
|
+
feature: Feature;
|
|
57
|
+
assemblyName: string;
|
|
58
|
+
windowSize?: number;
|
|
59
|
+
session: AbstractSessionModel;
|
|
60
|
+
tracks?: any;
|
|
61
|
+
}): Promise<void>;
|
package/esm/util.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { parseBreakend } from '@gmod/vcf';
|
|
2
|
+
import { gatherOverlaps, getSession, when } from '@jbrowse/core/util';
|
|
3
|
+
import { transaction } from 'mobx';
|
|
4
|
+
import { getSnapshot } from 'mobx-state-tree';
|
|
5
|
+
function stripIds(arr) {
|
|
6
|
+
return arr.map(({ id, displays, ...rest }) => ({
|
|
7
|
+
...rest,
|
|
8
|
+
displays: displays.map(({ id, ...rest }) => rest),
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
export function getBreakendCoveringRegions({ feature, assembly, }) {
|
|
12
|
+
var _a;
|
|
13
|
+
const alt = (_a = feature.get('ALT')) === null || _a === void 0 ? void 0 : _a[0];
|
|
14
|
+
const bnd = alt ? parseBreakend(alt) : undefined;
|
|
15
|
+
const startPos = feature.get('start');
|
|
16
|
+
const refName = feature.get('refName');
|
|
17
|
+
const f = (ref) => assembly.getCanonicalRefName(ref) || ref;
|
|
18
|
+
if (alt === '<TRA>') {
|
|
19
|
+
const INFO = feature.get('INFO');
|
|
20
|
+
return {
|
|
21
|
+
pos: startPos,
|
|
22
|
+
refName: f(refName),
|
|
23
|
+
mateRefName: f(INFO.CHR2[0]),
|
|
24
|
+
matePos: INFO.END[0] - 1,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
else if (bnd === null || bnd === void 0 ? void 0 : bnd.MatePosition) {
|
|
28
|
+
const matePosition = bnd.MatePosition.split(':');
|
|
29
|
+
return {
|
|
30
|
+
pos: startPos,
|
|
31
|
+
refName: f(refName),
|
|
32
|
+
mateRefName: f(matePosition[0]),
|
|
33
|
+
matePos: +matePosition[1] - 1,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
else if (feature.get('mate')) {
|
|
37
|
+
const mate = feature.get('mate');
|
|
38
|
+
return {
|
|
39
|
+
pos: startPos,
|
|
40
|
+
refName: f(refName),
|
|
41
|
+
mateRefName: f(mate.refName),
|
|
42
|
+
matePos: mate.start,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return {
|
|
47
|
+
pos: startPos,
|
|
48
|
+
refName: f(refName),
|
|
49
|
+
mateRefName: f(refName),
|
|
50
|
+
matePos: feature.get('end'),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function singleLevelSnapshotFromBreakendFeature({ feature, session, assemblyName, }) {
|
|
55
|
+
const { assemblyManager } = session;
|
|
56
|
+
const assembly = assemblyManager.get(assemblyName);
|
|
57
|
+
if (!assembly) {
|
|
58
|
+
throw new Error(`assembly ${assemblyName} not found`);
|
|
59
|
+
}
|
|
60
|
+
if (!assembly.regions) {
|
|
61
|
+
throw new Error(`assembly ${assemblyName} regions not loaded`);
|
|
62
|
+
}
|
|
63
|
+
const coverage = getBreakendCoveringRegions({
|
|
64
|
+
feature,
|
|
65
|
+
assembly,
|
|
66
|
+
});
|
|
67
|
+
const { refName, mateRefName } = coverage;
|
|
68
|
+
const topRegion = assembly.regions.find(f => f.refName === refName);
|
|
69
|
+
const bottomRegion = assembly.regions.find(f => f.refName === mateRefName);
|
|
70
|
+
return {
|
|
71
|
+
coverage,
|
|
72
|
+
snap: {
|
|
73
|
+
type: 'BreakpointSplitView',
|
|
74
|
+
views: [
|
|
75
|
+
{
|
|
76
|
+
type: 'LinearGenomeView',
|
|
77
|
+
displayedRegions: gatherOverlaps([
|
|
78
|
+
{ ...topRegion, assemblyName },
|
|
79
|
+
{ ...bottomRegion, assemblyName },
|
|
80
|
+
]),
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
displayName: `${feature.get('name') || feature.get('id') || 'breakend'} split detail`,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export async function navToSingleLevelBreak({ stableViewId, feature, assemblyName, session, tracks, windowSize = 0, }) {
|
|
88
|
+
var _a;
|
|
89
|
+
const { snap, coverage } = singleLevelSnapshotFromBreakendFeature({
|
|
90
|
+
feature,
|
|
91
|
+
assemblyName,
|
|
92
|
+
session,
|
|
93
|
+
});
|
|
94
|
+
const { refName, pos: startPos, mateRefName, matePos: endPos } = coverage;
|
|
95
|
+
let viewInStack = session.views.find(f => f.id === stableViewId);
|
|
96
|
+
if (!viewInStack) {
|
|
97
|
+
viewInStack = session.addView('BreakpointSplitView', {
|
|
98
|
+
...snap,
|
|
99
|
+
views: [
|
|
100
|
+
{
|
|
101
|
+
...snap.views[0],
|
|
102
|
+
tracks: tracks ? stripIds(getSnapshot(tracks)) : [],
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
(_a = viewInStack.views[0]) === null || _a === void 0 ? void 0 : _a.setDisplayedRegions(snap.views[0].displayedRegions);
|
|
109
|
+
viewInStack.setDisplayName(snap.displayName);
|
|
110
|
+
}
|
|
111
|
+
const lgv = viewInStack.views[0];
|
|
112
|
+
await when(() => lgv.initialized);
|
|
113
|
+
const l0 = lgv.bpToPx({
|
|
114
|
+
coord: Math.max(0, startPos - windowSize),
|
|
115
|
+
refName,
|
|
116
|
+
});
|
|
117
|
+
const r0 = lgv.bpToPx({
|
|
118
|
+
coord: endPos + windowSize,
|
|
119
|
+
refName: mateRefName,
|
|
120
|
+
});
|
|
121
|
+
if (l0 && r0) {
|
|
122
|
+
lgv.moveTo({ ...l0, offset: l0.offsetPx }, { ...r0, offset: r0.offsetPx });
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
getSession(lgv).notify('Unable to navigate to breakpoint');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export async function navToMultiLevelBreak({ stableViewId, feature, assemblyName, session, tracks, }) {
|
|
129
|
+
const bpPerPx = 10;
|
|
130
|
+
const { assemblyManager } = session;
|
|
131
|
+
const assembly = assemblyManager.get(assemblyName);
|
|
132
|
+
if (!assembly) {
|
|
133
|
+
throw new Error(`assembly ${assemblyName} not found`);
|
|
134
|
+
}
|
|
135
|
+
if (!assembly.regions) {
|
|
136
|
+
throw new Error(`assembly ${assemblyName} regions not loaded`);
|
|
137
|
+
}
|
|
138
|
+
const { refName, pos: startPos, mateRefName, matePos: endPos, } = getBreakendCoveringRegions({
|
|
139
|
+
feature,
|
|
140
|
+
assembly,
|
|
141
|
+
});
|
|
142
|
+
const topRegion = assembly.regions.find(f => f.refName === refName);
|
|
143
|
+
const bottomRegion = assembly.regions.find(f => f.refName === mateRefName);
|
|
144
|
+
const topMarkedRegion = [{ ...topRegion }, { ...topRegion }];
|
|
145
|
+
const bottomMarkedRegion = [{ ...bottomRegion }, { ...bottomRegion }];
|
|
146
|
+
topMarkedRegion[0].end = startPos;
|
|
147
|
+
topMarkedRegion[1].start = startPos;
|
|
148
|
+
bottomMarkedRegion[0].end = endPos;
|
|
149
|
+
bottomMarkedRegion[1].start = endPos;
|
|
150
|
+
const snap = {
|
|
151
|
+
type: 'BreakpointSplitView',
|
|
152
|
+
views: [
|
|
153
|
+
{
|
|
154
|
+
type: 'LinearGenomeView',
|
|
155
|
+
displayedRegions: topMarkedRegion,
|
|
156
|
+
hideHeader: true,
|
|
157
|
+
bpPerPx,
|
|
158
|
+
offsetPx: (topRegion.start + feature.get('start')) / bpPerPx,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
type: 'LinearGenomeView',
|
|
162
|
+
displayedRegions: bottomMarkedRegion,
|
|
163
|
+
hideHeader: true,
|
|
164
|
+
bpPerPx,
|
|
165
|
+
tracks,
|
|
166
|
+
offsetPx: (bottomRegion.start + endPos) / bpPerPx,
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
displayName: `${feature.get('name') || feature.get('id') || 'breakend'} split detail`,
|
|
170
|
+
};
|
|
171
|
+
let viewInStack = session.views.find(f => f.id === stableViewId);
|
|
172
|
+
if (!viewInStack) {
|
|
173
|
+
viewInStack = session.addView('BreakpointSplitView', {
|
|
174
|
+
...snap,
|
|
175
|
+
id: stableViewId,
|
|
176
|
+
views: [
|
|
177
|
+
{
|
|
178
|
+
...snap.views[0],
|
|
179
|
+
tracks: tracks ? stripIds(getSnapshot(tracks)) : [],
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
...snap.views[1],
|
|
183
|
+
tracks: (tracks ? stripIds(getSnapshot(tracks)) : []).reverse(),
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
transaction(() => {
|
|
190
|
+
for (let i = 0; i < viewInStack.views.length; i++) {
|
|
191
|
+
const s = snap.views[i];
|
|
192
|
+
if (s) {
|
|
193
|
+
viewInStack.views[i].setDisplayedRegions(s.displayedRegions);
|
|
194
|
+
viewInStack.views[i].scrollTo(s.offsetPx - 800);
|
|
195
|
+
viewInStack.views[i].zoomTo(s.bpPerPx);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
viewInStack.setDisplayName(snap.displayName);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/sv-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "JBrowse 2 code shared between sv type code",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -41,7 +41,9 @@
|
|
|
41
41
|
"useSrc": "node ../../scripts/useSrc.js"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@
|
|
44
|
+
"@gmod/vcf": "^6.0.0",
|
|
45
|
+
"@jbrowse/core": "^2.18.0",
|
|
46
|
+
"@jbrowse/plugin-linear-genome-view": "^2.18.0",
|
|
45
47
|
"@mui/icons-material": "^6.0.0",
|
|
46
48
|
"@mui/material": "^6.0.0"
|
|
47
49
|
},
|
|
@@ -57,5 +59,5 @@
|
|
|
57
59
|
"publishConfig": {
|
|
58
60
|
"access": "public"
|
|
59
61
|
},
|
|
60
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "c344ea60099cb7e460b77f15808946b24a7eee74"
|
|
61
63
|
}
|