@jbrowse/sv-core 2.17.0 → 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.
@@ -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
- import type { Assembly } from '@jbrowse/core/assemblyManager/assembly';
5
- declare const BreakendMultiLevelOptionDialog: ({ model, handleClose, feature, assemblyName, viewType, view, }: {
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: LinearGenomeViewModel;
8
+ view?: LinearGenomeViewModel;
10
9
  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
- };
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 util_1 = require("@jbrowse/core/util");
36
- // locals
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 ({ model, handleClose, feature, assemblyName, viewType, view, }) {
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(Checkbox2_1.default, { checked: copyTracks, label: "Copy tracks into the new view", onChange: event => {
50
- setCopyTracks(event.target.checked);
51
- } }),
52
- 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 => {
53
- setMirror(event.target.checked);
54
- } })) : null),
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 asm = await session.assemblyManager.waitForAssembly(assemblyName);
63
- if (!asm) {
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 } = viewType.getBreakendCoveringRegions({
66
+ const { refName, pos, mateRefName, matePos } = (0, util_1.getBreakendCoveringRegions)({
67
67
  feature,
68
- assembly: asm,
68
+ assembly: assembly,
69
69
  });
70
- const viewTracks = (0, mobx_state_tree_1.getSnapshot)(view.tracks);
71
- const breakpointSplitView = session.addView('BreakpointSplitView', {
72
- type: 'BreakpointSplitView',
73
- displayName: `${feature.get('name') || feature.get('id') || 'breakend'} split detail`,
74
- views: [
75
- {
76
- type: 'LinearGenomeView',
77
- hideHeader: true,
78
- tracks: stripIds((0, mobx_state_tree_1.getSnapshot)(view.tracks)),
79
- },
80
- {
81
- type: 'LinearGenomeView',
82
- hideHeader: true,
83
- tracks: stripIds(mirror ? [...viewTracks].reverse() : viewTracks),
84
- },
85
- ],
86
- });
87
- const r1 = asm.regions.find(r => r.refName === refName);
88
- const r2 = asm.regions.find(r => r.refName === mateRefName);
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
- breakpointSplitView.views[0].navToLocations([
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
- breakpointSplitView.views[1].navToLocations([
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)(() => breakpointSplitView.views[1].initialized &&
123
- breakpointSplitView.views[0].initialized);
124
- breakpointSplitView.views[1].zoomTo(10);
125
- breakpointSplitView.views[0].zoomTo(10);
126
- breakpointSplitView.views[1].centerAt(matePos, mateRefName);
127
- breakpointSplitView.views[0].centerAt(pos, refName);
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.notify(`${e}`);
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
- import type { Assembly } from '@jbrowse/core/assemblyManager/assembly';
5
- declare const BreakendSingleLevelOptionDialog: ({ model, handleClose, feature, assemblyName, viewType, view, }: {
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: LinearGenomeViewModel;
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
- // locals
32
+ const material_1 = require("@mui/material");
33
+ const mobx_react_1 = require("mobx-react");
36
34
  const Checkbox2_1 = __importDefault(require("./Checkbox2"));
37
- function stripIds(arr) {
38
- return arr.map(({ id, displays, ...rest }) => ({
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
- const session = (0, util_1.getSession)(model);
49
+ ;
57
50
  (async () => {
58
51
  try {
59
- const assembly = session.assemblyManager.get(assemblyName);
60
- const w = +windowSize;
61
- if (Number.isNaN(w)) {
62
- throw new Error('windowSize not a number');
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
- const { refName, pos, mateRefName, matePos } =
65
- // @ts-expect-error
66
- viewType.getBreakendCoveringRegions({ feature, assembly });
67
- const breakpointSplitView = session.addView('BreakpointSplitView', {
68
- type: 'BreakpointSplitView',
69
- displayName: `${feature.get('name') || feature.get('id') || 'breakend'} split detail`,
70
- views: [
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.notify(`${e}`);
68
+ session.notifyError(`${e}`, e);
95
69
  }
96
70
  })();
97
71
  handleClose();
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { default as BreakendMultiLevelOptionDialog } from './BreakendMultiLevelOptionDialog';
2
2
  export { default as BreakendSingleLevelOptionDialog } from './BreakendSingleLevelOptionDialog';
3
+ export * from './util';
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
- import type { Assembly } from '@jbrowse/core/assemblyManager/assembly';
5
- declare const BreakendMultiLevelOptionDialog: ({ model, handleClose, feature, assemblyName, viewType, view, }: {
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: LinearGenomeViewModel;
8
+ view?: LinearGenomeViewModel;
10
9
  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
- };
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 { getSession } from '@jbrowse/core/util';
8
- // locals
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 ({ model, handleClose, feature, assemblyName, viewType, view, }) {
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(Checkbox2, { checked: copyTracks, label: "Copy tracks into the new view", onChange: event => {
22
- setCopyTracks(event.target.checked);
23
- } }),
24
- copyTracks ? (React.createElement(Checkbox2, { checked: mirror, disabled: !copyTracks, label: "Mirror the copied tracks (only available if copying tracks and using two level)", onChange: event => {
25
- setMirror(event.target.checked);
26
- } })) : null),
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 asm = await session.assemblyManager.waitForAssembly(assemblyName);
35
- if (!asm) {
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 } = viewType.getBreakendCoveringRegions({
38
+ const { refName, pos, mateRefName, matePos } = getBreakendCoveringRegions({
39
39
  feature,
40
- assembly: asm,
40
+ assembly: assembly,
41
41
  });
42
- const viewTracks = getSnapshot(view.tracks);
43
- const breakpointSplitView = session.addView('BreakpointSplitView', {
44
- type: 'BreakpointSplitView',
45
- displayName: `${feature.get('name') || feature.get('id') || 'breakend'} split detail`,
46
- views: [
47
- {
48
- type: 'LinearGenomeView',
49
- hideHeader: true,
50
- tracks: stripIds(getSnapshot(view.tracks)),
51
- },
52
- {
53
- type: 'LinearGenomeView',
54
- hideHeader: true,
55
- tracks: stripIds(mirror ? [...viewTracks].reverse() : viewTracks),
56
- },
57
- ],
58
- });
59
- const r1 = asm.regions.find(r => r.refName === refName);
60
- const r2 = asm.regions.find(r => r.refName === mateRefName);
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
- breakpointSplitView.views[0].navToLocations([
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
- breakpointSplitView.views[1].navToLocations([
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(() => breakpointSplitView.views[1].initialized &&
95
- breakpointSplitView.views[0].initialized);
96
- breakpointSplitView.views[1].zoomTo(10);
97
- breakpointSplitView.views[0].zoomTo(10);
98
- breakpointSplitView.views[1].centerAt(matePos, mateRefName);
99
- breakpointSplitView.views[0].centerAt(pos, refName);
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.notify(`${e}`);
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
- import type { Assembly } from '@jbrowse/core/assemblyManager/assembly';
5
- declare const BreakendSingleLevelOptionDialog: ({ model, handleClose, feature, assemblyName, viewType, view, }: {
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: LinearGenomeViewModel;
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 { getSession, gatherOverlaps, useLocalStorage, } from '@jbrowse/core/util';
7
- // locals
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
- function stripIds(arr) {
10
- return arr.map(({ id, displays, ...rest }) => ({
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
- const session = getSession(model);
21
+ ;
29
22
  (async () => {
30
23
  try {
31
- const assembly = session.assemblyManager.get(assemblyName);
32
- const w = +windowSize;
33
- if (Number.isNaN(w)) {
34
- throw new Error('windowSize not a number');
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
- const { refName, pos, mateRefName, matePos } =
37
- // @ts-expect-error
38
- viewType.getBreakendCoveringRegions({ feature, assembly });
39
- const breakpointSplitView = session.addView('BreakpointSplitView', {
40
- type: 'BreakpointSplitView',
41
- displayName: `${feature.get('name') || feature.get('id') || 'breakend'} split detail`,
42
- views: [
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.notify(`${e}`);
40
+ session.notifyError(`${e}`, e);
67
41
  }
68
42
  })();
69
43
  handleClose();
package/esm/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { default as BreakendMultiLevelOptionDialog } from './BreakendMultiLevelOptionDialog';
2
2
  export { default as BreakendSingleLevelOptionDialog } from './BreakendSingleLevelOptionDialog';
3
+ export * from './util';
package/esm/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { default as BreakendMultiLevelOptionDialog } from './BreakendMultiLevelOptionDialog';
2
2
  export { default as BreakendSingleLevelOptionDialog } from './BreakendSingleLevelOptionDialog';
3
+ export * from './util';
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.17.0",
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
- "@jbrowse/plugin-linear-genome-view": "^2.17.0",
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": "eed30b5e671f8f7823652d7cecc51aa89226de46"
62
+ "gitHead": "c344ea60099cb7e460b77f15808946b24a7eee74"
61
63
  }