@jbrowse/plugin-breakpoint-split-view 3.7.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js +1 -1
- package/esm/BreakpointAlignmentsFeatureDetail/index.js +2 -2
- package/esm/BreakpointGetFeatures/BreakpointGetFeatures.d.ts +51 -0
- package/esm/BreakpointGetFeatures/BreakpointGetFeatures.js +57 -0
- package/esm/BreakpointGetFeatures/index.d.ts +2 -0
- package/esm/BreakpointGetFeatures/index.js +4 -0
- package/esm/BreakpointSplitView/BreakpointSplitView.js +33 -47
- package/esm/BreakpointSplitView/components/AlignmentConnections.d.ts +2 -7
- package/esm/BreakpointSplitView/components/AlignmentConnections.js +20 -25
- package/esm/BreakpointSplitView/components/Breakends.d.ts +2 -7
- package/esm/BreakpointSplitView/components/Breakends.js +28 -59
- package/esm/BreakpointSplitView/components/BreakpointSplitView.d.ts +1 -1
- package/esm/BreakpointSplitView/components/BreakpointSplitView.js +19 -6
- package/esm/BreakpointSplitView/components/BreakpointSplitViewOverlay.d.ts +1 -1
- package/esm/BreakpointSplitView/components/BreakpointSplitViewOverlay.js +3 -3
- package/esm/BreakpointSplitView/components/ExportSvgDialog.d.ts +1 -1
- package/esm/BreakpointSplitView/components/ExportSvgDialog.js +5 -1
- package/esm/BreakpointSplitView/components/Header.d.ts +2 -2
- package/esm/BreakpointSplitView/components/Header.js +4 -4
- package/esm/BreakpointSplitView/components/HeaderSearchBoxes.js +2 -2
- package/esm/BreakpointSplitView/components/Overlay.d.ts +1 -1
- package/esm/BreakpointSplitView/components/Overlay.js +8 -11
- package/esm/BreakpointSplitView/components/PairedFeatures.d.ts +2 -7
- package/esm/BreakpointSplitView/components/PairedFeatures.js +22 -47
- package/esm/BreakpointSplitView/components/Rubberband.d.ts +6 -0
- package/esm/BreakpointSplitView/components/Rubberband.js +27 -0
- package/esm/BreakpointSplitView/components/RubberbandSpan.d.ts +15 -0
- package/esm/BreakpointSplitView/components/RubberbandSpan.js +30 -0
- package/esm/BreakpointSplitView/components/RubberbandTooltip.d.ts +5 -0
- package/esm/BreakpointSplitView/components/RubberbandTooltip.js +17 -0
- package/esm/BreakpointSplitView/components/Translocations.d.ts +2 -7
- package/esm/BreakpointSplitView/components/Translocations.js +23 -58
- package/esm/BreakpointSplitView/components/VerticalGuide.d.ts +6 -0
- package/esm/BreakpointSplitView/components/VerticalGuide.js +24 -0
- package/esm/BreakpointSplitView/components/overlayUtils.d.ts +24 -0
- package/esm/BreakpointSplitView/components/overlayUtils.js +47 -0
- package/esm/BreakpointSplitView/components/rubberbandUtil.d.ts +4 -0
- package/esm/BreakpointSplitView/components/rubberbandUtil.js +3 -0
- package/esm/BreakpointSplitView/components/useRangeSelect.d.ts +59 -0
- package/esm/BreakpointSplitView/components/useRangeSelect.js +121 -0
- package/esm/BreakpointSplitView/components/util.js +1 -2
- package/esm/BreakpointSplitView/getClip.js +4 -4
- package/esm/BreakpointSplitView/index.js +2 -2
- package/esm/BreakpointSplitView/model.d.ts +402 -117
- package/esm/BreakpointSplitView/model.js +105 -41
- package/esm/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.d.ts +2 -2
- package/esm/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js +8 -8
- package/esm/BreakpointSplitView/types.d.ts +8 -0
- package/esm/BreakpointSplitView/util.d.ts +1 -1
- package/esm/BreakpointSplitView/util.js +8 -17
- package/esm/LaunchBreakpointSplitView/index.d.ts +2 -0
- package/esm/LaunchBreakpointSplitView/index.js +12 -0
- package/esm/index.js +7 -6
- package/package.json +28 -34
- package/dist/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.d.ts +0 -10
- package/dist/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js +0 -12
- package/dist/BreakpointAlignmentsFeatureDetail/index.d.ts +0 -2
- package/dist/BreakpointAlignmentsFeatureDetail/index.js +0 -67
- package/dist/BreakpointSplitView/BreakpointSplitView.d.ts +0 -34
- package/dist/BreakpointSplitView/BreakpointSplitView.js +0 -84
- package/dist/BreakpointSplitView/components/AlignmentConnections.d.ts +0 -8
- package/dist/BreakpointSplitView/components/AlignmentConnections.js +0 -133
- package/dist/BreakpointSplitView/components/Breakends.d.ts +0 -8
- package/dist/BreakpointSplitView/components/Breakends.js +0 -95
- package/dist/BreakpointSplitView/components/BreakpointSplitView.d.ts +0 -5
- package/dist/BreakpointSplitView/components/BreakpointSplitView.js +0 -46
- package/dist/BreakpointSplitView/components/BreakpointSplitViewOverlay.d.ts +0 -5
- package/dist/BreakpointSplitView/components/BreakpointSplitViewOverlay.js +0 -33
- package/dist/BreakpointSplitView/components/ExportSvgDialog.d.ts +0 -7
- package/dist/BreakpointSplitView/components/ExportSvgDialog.js +0 -57
- package/dist/BreakpointSplitView/components/Header.d.ts +0 -5
- package/dist/BreakpointSplitView/components/Header.js +0 -52
- package/dist/BreakpointSplitView/components/HeaderSearchBoxes.d.ts +0 -5
- package/dist/BreakpointSplitView/components/HeaderSearchBoxes.js +0 -24
- package/dist/BreakpointSplitView/components/Overlay.d.ts +0 -8
- package/dist/BreakpointSplitView/components/Overlay.js +0 -27
- package/dist/BreakpointSplitView/components/PairedFeatures.d.ts +0 -8
- package/dist/BreakpointSplitView/components/PairedFeatures.js +0 -75
- package/dist/BreakpointSplitView/components/Translocations.d.ts +0 -8
- package/dist/BreakpointSplitView/components/Translocations.js +0 -99
- package/dist/BreakpointSplitView/components/getOrientationColor.d.ts +0 -41
- package/dist/BreakpointSplitView/components/getOrientationColor.js +0 -103
- package/dist/BreakpointSplitView/components/util.d.ts +0 -8
- package/dist/BreakpointSplitView/components/util.js +0 -142
- package/dist/BreakpointSplitView/getClip.d.ts +0 -1
- package/dist/BreakpointSplitView/getClip.js +0 -10
- package/dist/BreakpointSplitView/index.d.ts +0 -2
- package/dist/BreakpointSplitView/index.js +0 -52
- package/dist/BreakpointSplitView/model.d.ts +0 -344
- package/dist/BreakpointSplitView/model.js +0 -256
- package/dist/BreakpointSplitView/svgcomponents/SVGBackground.d.ts +0 -5
- package/dist/BreakpointSplitView/svgcomponents/SVGBackground.js +0 -10
- package/dist/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.d.ts +0 -5
- package/dist/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js +0 -41
- package/dist/BreakpointSplitView/svgcomponents/util.d.ts +0 -4
- package/dist/BreakpointSplitView/svgcomponents/util.js +0 -18
- package/dist/BreakpointSplitView/types.d.ts +0 -22
- package/dist/BreakpointSplitView/types.js +0 -2
- package/dist/BreakpointSplitView/util.d.ts +0 -28
- package/dist/BreakpointSplitView/util.js +0 -67
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -20
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { lazy } from 'react';
|
|
2
2
|
import { BaseViewModel } from '@jbrowse/core/pluggableElementTypes/models';
|
|
3
3
|
import { getSession, notEmpty } from '@jbrowse/core/util';
|
|
4
|
+
import { addDisposer, addMiddleware, cast, getPath, types, } from '@jbrowse/mobx-state-tree';
|
|
4
5
|
import LinkIcon from '@mui/icons-material/Link';
|
|
5
6
|
import PhotoCamera from '@mui/icons-material/PhotoCamera';
|
|
6
|
-
import { saveAs } from 'file-saver';
|
|
7
7
|
import { autorun } from 'mobx';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
import { calc, getBlockFeatures, intersect } from './util';
|
|
11
|
-
const ExportSvgDialog = lazy(() => import('./components/ExportSvgDialog'));
|
|
8
|
+
import { calc, getBlockFeatures, intersect } from "./util.js";
|
|
9
|
+
const ExportSvgDialog = lazy(() => import("./components/ExportSvgDialog.js"));
|
|
12
10
|
export default function stateModelFactory(pluginManager) {
|
|
13
11
|
const defaultHeight = 400;
|
|
14
12
|
return types
|
|
@@ -22,17 +20,29 @@ export default function stateModelFactory(pluginManager) {
|
|
|
22
20
|
showHeader: false,
|
|
23
21
|
views: types.array(pluginManager.getViewType('LinearGenomeView')
|
|
24
22
|
.stateModel),
|
|
23
|
+
init: types.frozen(),
|
|
25
24
|
}))
|
|
26
25
|
.volatile(() => ({
|
|
27
26
|
width: 800,
|
|
28
27
|
matchedTrackFeatures: {},
|
|
28
|
+
}))
|
|
29
|
+
.views(self => ({
|
|
30
|
+
get hasSomethingToShow() {
|
|
31
|
+
return self.views.length > 0 || !!self.init;
|
|
32
|
+
},
|
|
33
|
+
get initialized() {
|
|
34
|
+
return self.views.length > 0 && self.views.every(v => v.initialized);
|
|
35
|
+
},
|
|
36
|
+
get showImportForm() {
|
|
37
|
+
return !this.hasSomethingToShow;
|
|
38
|
+
},
|
|
29
39
|
}))
|
|
30
40
|
.views(self => ({
|
|
31
41
|
async exportSvg(opts = {}) {
|
|
32
|
-
const { renderToSvg } = await import(
|
|
42
|
+
const { renderToSvg } = await import("./svgcomponents/SVGBreakpointSplitView.js");
|
|
33
43
|
const html = await renderToSvg(self, opts);
|
|
34
|
-
const
|
|
35
|
-
saveAs(
|
|
44
|
+
const { saveAs } = await import('file-saver-es');
|
|
45
|
+
saveAs(new Blob([html], { type: 'image/svg+xml' }), opts.filename || 'image.svg');
|
|
36
46
|
},
|
|
37
47
|
}))
|
|
38
48
|
.views(self => ({
|
|
@@ -44,40 +54,44 @@ export default function stateModelFactory(pluginManager) {
|
|
|
44
54
|
getMatchedTracks(trackConfigId) {
|
|
45
55
|
return self.views
|
|
46
56
|
.map(view => view.getTrack(trackConfigId))
|
|
47
|
-
.filter(
|
|
57
|
+
.filter(notEmpty);
|
|
48
58
|
},
|
|
49
59
|
hasTranslocations(trackConfigId) {
|
|
50
|
-
return [...this.getTrackFeatures(trackConfigId).values()].
|
|
60
|
+
return [...this.getTrackFeatures(trackConfigId).values()].some(f => f.get('type') === 'translocation');
|
|
51
61
|
},
|
|
52
62
|
hasPairedFeatures(trackConfigId) {
|
|
53
|
-
return [...this.getTrackFeatures(trackConfigId).values()].
|
|
63
|
+
return [...this.getTrackFeatures(trackConfigId).values()].some(f => f.get('type') === 'paired_feature');
|
|
54
64
|
},
|
|
55
65
|
getTrackFeatures(trackConfigId) {
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
return new Map(self.matchedTrackFeatures[trackConfigId]
|
|
67
|
+
?.flat()
|
|
68
|
+
.map(f => [f.id(), f]));
|
|
58
69
|
},
|
|
59
70
|
getMatchedFeaturesInLayout(trackConfigId, features) {
|
|
60
71
|
const tracks = this.getMatchedTracks(trackConfigId);
|
|
61
72
|
return features.map(c => c
|
|
62
73
|
.map(feature => {
|
|
63
|
-
const level
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
for (const [level, track] of tracks.entries()) {
|
|
75
|
+
const layout = calc(track, feature);
|
|
76
|
+
if (layout) {
|
|
77
|
+
return {
|
|
78
|
+
feature,
|
|
79
|
+
layout,
|
|
80
|
+
level,
|
|
81
|
+
clipLengthAtStartOfRead: feature.get('clipLengthAtStartOfRead') ?? 0,
|
|
82
|
+
};
|
|
70
83
|
}
|
|
71
|
-
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
72
86
|
})
|
|
73
87
|
.filter(notEmpty));
|
|
74
88
|
},
|
|
75
89
|
}))
|
|
76
90
|
.actions(self => ({
|
|
77
91
|
afterAttach() {
|
|
78
|
-
addDisposer(self,
|
|
79
|
-
if (
|
|
80
|
-
const
|
|
92
|
+
addDisposer(self, addMiddleware(self, (rawCall, next) => {
|
|
93
|
+
if (rawCall.type === 'action' && rawCall.id === rawCall.rootId) {
|
|
94
|
+
const syncActions = [
|
|
81
95
|
'horizontalScroll',
|
|
82
96
|
'zoomTo',
|
|
83
97
|
'setScaleFactor',
|
|
@@ -87,20 +101,21 @@ export default function stateModelFactory(pluginManager) {
|
|
|
87
101
|
'setTrackLabels',
|
|
88
102
|
'toggleCenterLine',
|
|
89
103
|
];
|
|
90
|
-
if (
|
|
91
|
-
|
|
104
|
+
if (self.linkViews && syncActions.includes(rawCall.name)) {
|
|
105
|
+
const sourcePath = getPath(rawCall.context);
|
|
106
|
+
next(rawCall);
|
|
107
|
+
for (const view of self.views) {
|
|
108
|
+
const viewPath = getPath(view);
|
|
109
|
+
if (viewPath !== sourcePath) {
|
|
110
|
+
view[rawCall.name](rawCall.args[0]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
92
114
|
}
|
|
93
115
|
}
|
|
116
|
+
next(rawCall);
|
|
94
117
|
}));
|
|
95
118
|
},
|
|
96
|
-
onSubviewAction(actionName, path, args) {
|
|
97
|
-
for (const view of self.views) {
|
|
98
|
-
const ret = getPath(view);
|
|
99
|
-
if (!ret.endsWith(path)) {
|
|
100
|
-
view[actionName](args === null || args === void 0 ? void 0 : args[0]);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
119
|
setWidth(newWidth) {
|
|
105
120
|
self.width = newWidth;
|
|
106
121
|
for (const v of self.views) {
|
|
@@ -125,15 +140,33 @@ export default function stateModelFactory(pluginManager) {
|
|
|
125
140
|
reverseViewOrder() {
|
|
126
141
|
self.views.reverse();
|
|
127
142
|
},
|
|
143
|
+
setInit(init) {
|
|
144
|
+
self.init = init;
|
|
145
|
+
},
|
|
146
|
+
setViews(viewInits) {
|
|
147
|
+
self.views = cast(viewInits.map(viewInit => ({
|
|
148
|
+
type: 'LinearGenomeView',
|
|
149
|
+
hideHeader: true,
|
|
150
|
+
init: viewInit,
|
|
151
|
+
})));
|
|
152
|
+
},
|
|
128
153
|
}))
|
|
129
154
|
.actions(self => ({
|
|
130
155
|
afterAttach() {
|
|
156
|
+
addDisposer(self, autorun(function breakpointSplitViewInitAutorun() {
|
|
157
|
+
const { init, width } = self;
|
|
158
|
+
if (!width || !init) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
self.setViews(init.views);
|
|
162
|
+
self.setInit(undefined);
|
|
163
|
+
}, { name: 'BreakpointSplitViewInit' }));
|
|
131
164
|
addDisposer(self, autorun(async () => {
|
|
132
165
|
try {
|
|
133
166
|
if (!self.views.every(view => view.initialized)) {
|
|
134
167
|
return;
|
|
135
168
|
}
|
|
136
|
-
if (self.matchedTracks.some(track =>
|
|
169
|
+
if (self.matchedTracks.some(track => track.displays[0].notReady?.())) {
|
|
137
170
|
return;
|
|
138
171
|
}
|
|
139
172
|
self.setMatchedTrackFeatures(Object.fromEntries(await Promise.all(self.matchedTracks.map(async (track) => [
|
|
@@ -145,15 +178,16 @@ export default function stateModelFactory(pluginManager) {
|
|
|
145
178
|
console.error(e);
|
|
146
179
|
getSession(self).notifyError(`${e}`, e);
|
|
147
180
|
}
|
|
181
|
+
}, {
|
|
182
|
+
name: 'BreakpointFeatureFetcher',
|
|
183
|
+
delay: 1000,
|
|
148
184
|
}));
|
|
149
185
|
},
|
|
150
186
|
menuItems() {
|
|
151
187
|
return [
|
|
152
|
-
...self.views
|
|
153
|
-
|
|
154
|
-
.
|
|
155
|
-
label: `Row ${f[0] + 1} view menu`,
|
|
156
|
-
subMenu: f[1],
|
|
188
|
+
...self.views.map((view, idx) => ({
|
|
189
|
+
label: `Row ${idx + 1} view menu`,
|
|
190
|
+
subMenu: view.menuItems(),
|
|
157
191
|
})),
|
|
158
192
|
...(self.views.length > 1
|
|
159
193
|
? [
|
|
@@ -213,5 +247,35 @@ export default function stateModelFactory(pluginManager) {
|
|
|
213
247
|
},
|
|
214
248
|
];
|
|
215
249
|
},
|
|
216
|
-
|
|
250
|
+
rubberBandMenuItems() {
|
|
251
|
+
return [
|
|
252
|
+
{
|
|
253
|
+
label: 'Zoom to region(s)',
|
|
254
|
+
onClick: () => {
|
|
255
|
+
for (const view of self.views) {
|
|
256
|
+
const { leftOffset, rightOffset } = view;
|
|
257
|
+
if (leftOffset && rightOffset) {
|
|
258
|
+
view.moveTo(leftOffset, rightOffset);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
];
|
|
264
|
+
},
|
|
265
|
+
}))
|
|
266
|
+
.postProcessSnapshot(snap => {
|
|
267
|
+
if (!snap) {
|
|
268
|
+
return snap;
|
|
269
|
+
}
|
|
270
|
+
const { init, height, trackSelectorType, showIntraviewLinks, linkViews, interactiveOverlay, showHeader, ...rest } = snap;
|
|
271
|
+
return {
|
|
272
|
+
...rest,
|
|
273
|
+
...(height !== 400 ? { height } : {}),
|
|
274
|
+
...(trackSelectorType !== 'hierarchical' ? { trackSelectorType } : {}),
|
|
275
|
+
...(!showIntraviewLinks ? { showIntraviewLinks } : {}),
|
|
276
|
+
...(linkViews ? { linkViews } : {}),
|
|
277
|
+
...(!interactiveOverlay ? { interactiveOverlay } : {}),
|
|
278
|
+
...(showHeader ? { showHeader } : {}),
|
|
279
|
+
};
|
|
280
|
+
});
|
|
217
281
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { BreakpointViewModel } from '../model';
|
|
2
|
-
import type { ExportSvgOptions } from '../types';
|
|
1
|
+
import type { BreakpointViewModel } from '../model.ts';
|
|
2
|
+
import type { ExportSvgOptions } from '../types.ts';
|
|
3
3
|
type BSV = BreakpointViewModel;
|
|
4
4
|
export declare function renderToSvg(model: BSV, opts: ExportSvgOptions): Promise<string>;
|
|
5
5
|
export {};
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { createJBrowseTheme } from '@jbrowse/core/ui';
|
|
3
3
|
import { getSession, renderToStaticMarkup, sum } from '@jbrowse/core/util';
|
|
4
|
-
import { SVGRuler, SVGTracks, totalHeight, } from '@jbrowse/plugin-linear-genome-view';
|
|
4
|
+
import { SVGGridlines, SVGRuler, SVGTracks, totalHeight, } from '@jbrowse/plugin-linear-genome-view';
|
|
5
5
|
import { ThemeProvider } from '@mui/material';
|
|
6
6
|
import { when } from 'mobx';
|
|
7
|
-
import SVGBackground from
|
|
8
|
-
import { getTrackNameMaxLen, getTrackOffsets } from
|
|
9
|
-
import Overlay from
|
|
7
|
+
import SVGBackground from "./SVGBackground.js";
|
|
8
|
+
import { getTrackNameMaxLen, getTrackOffsets } from "./util.js";
|
|
9
|
+
import Overlay from "../components/Overlay.js";
|
|
10
10
|
export async function renderToSvg(model, opts) {
|
|
11
|
-
|
|
12
|
-
const { textHeight = 18, headerHeight = 30, rulerHeight = 30, fontSize = 13, trackLabels = 'offset', Wrapper = ({ children }) => children, themeName = 'default', } = opts;
|
|
11
|
+
const { textHeight = 18, headerHeight = 30, rulerHeight = 30, fontSize = 13, trackLabels = 'offset', showGridlines = false, Wrapper = ({ children }) => children, themeName = 'default', } = opts;
|
|
13
12
|
const session = getSession(model);
|
|
14
|
-
const theme =
|
|
13
|
+
const theme = session.allThemes?.()[themeName];
|
|
15
14
|
const { width, views } = model;
|
|
16
15
|
const shift = 50;
|
|
17
16
|
const offset = headerHeight + rulerHeight;
|
|
@@ -31,5 +30,6 @@ export async function renderToSvg(model, opts) {
|
|
|
31
30
|
const trackOffsets = views.map((view, idx) => getTrackOffsets(view, textOffset, fontSize + (idx > 0 ? heights[idx - 1] : 0) + offset));
|
|
32
31
|
const w = width + trackLabelOffset;
|
|
33
32
|
const t = createJBrowseTheme(theme);
|
|
34
|
-
|
|
33
|
+
const tracksHeights = views.map(v => totalHeight(v.tracks, textHeight, trackLabels));
|
|
34
|
+
return renderToStaticMarkup(_jsx(ThemeProvider, { theme: t, children: _jsx(Wrapper, { children: _jsxs("svg", { width: width, height: totalHeightSvg, xmlns: "http://www.w3.org/2000/svg", xmlnsXlink: "http://www.w3.org/1999/xlink", viewBox: [0, 0, w + shift * 2, totalHeightSvg].toString(), children: [_jsx(SVGBackground, { width: w, height: totalHeightSvg, shift: shift }), views[0] ? (_jsxs("g", { transform: `translate(${shift} ${fontSize})`, children: [_jsxs("g", { transform: `translate(${trackLabelOffset})`, children: [_jsx("text", { x: 0, fontSize: fontSize, fill: t.palette.text.primary, children: views[0].assemblyNames.join(', ') }), _jsx(SVGRuler, { model: displayResults[0].view, fontSize: fontSize })] }), showGridlines ? (_jsx("g", { transform: `translate(${trackLabelOffset} ${offset})`, children: _jsx(SVGGridlines, { model: displayResults[0].view, height: tracksHeights[0] }) })) : null, _jsx("g", { transform: `translate(0 ${offset})`, children: _jsx(SVGTracks, { textHeight: textHeight, trackLabels: trackLabels, fontSize: fontSize, model: displayResults[0].view, displayResults: displayResults[0].data, trackLabelOffset: trackLabelOffset }) })] })) : null, views[1] ? (_jsxs("g", { transform: `translate(${shift} ${fontSize + heights[0]})`, children: [_jsxs("g", { transform: `translate(${trackLabelOffset})`, children: [_jsx("text", { x: 0, fontSize: fontSize, fill: t.palette.text.primary, children: views[1].assemblyNames.join(', ') }), _jsx(SVGRuler, { model: displayResults[1].view, fontSize: fontSize })] }), showGridlines ? (_jsx("g", { transform: `translate(${trackLabelOffset} ${offset})`, children: _jsx(SVGGridlines, { model: displayResults[1].view, height: tracksHeights[1] }) })) : null, _jsx("g", { transform: `translate(0 ${offset})`, children: _jsx(SVGTracks, { textHeight: textHeight, trackLabels: trackLabels, fontSize: fontSize, model: displayResults[1].view, displayResults: displayResults[1].data, trackLabelOffset: trackLabelOffset }) })] })) : null, _jsx("defs", { children: _jsx("clipPath", { id: "clip-bsv", children: _jsx("rect", { x: 0, y: 0, width: width, height: totalHeightSvg }) }) }), _jsx("g", { transform: `translate(${trackLabelOffset + shift})`, clipPath: "url(#clip-bsv)", children: model.matchedTracks.map(track => (_jsx(Overlay, { parentRef: { current: null }, model: model, trackId: track.configuration.trackId, getTrackYPosOverride: (id, level) => trackOffsets[level][id] }, track.configuration.trackId))) })] }) }) }));
|
|
35
35
|
}
|
|
@@ -12,6 +12,14 @@ export interface ExportSvgOptions {
|
|
|
12
12
|
cytobandHeight?: number;
|
|
13
13
|
trackLabels?: string;
|
|
14
14
|
themeName?: string;
|
|
15
|
+
showGridlines?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface BreakpointSplitViewInit {
|
|
18
|
+
views: {
|
|
19
|
+
loc?: string;
|
|
20
|
+
assembly: string;
|
|
21
|
+
tracks?: string[];
|
|
22
|
+
}[];
|
|
15
23
|
}
|
|
16
24
|
export interface Breakend {
|
|
17
25
|
MateDirection: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LayoutRecord } from './types';
|
|
1
|
+
import type { LayoutRecord } from './types.ts';
|
|
2
2
|
import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
3
3
|
import type { Feature } from '@jbrowse/core/util';
|
|
4
4
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
|
|
@@ -7,28 +7,20 @@ function cheight(chunk) {
|
|
|
7
7
|
return chunk[BOTTOM] - chunk[TOP];
|
|
8
8
|
}
|
|
9
9
|
export function heightFromSpecificLevel(views, trackId, level, getYPosOverride) {
|
|
10
|
-
var _a;
|
|
11
10
|
return getYPosOverride
|
|
12
11
|
? getYPosOverride(trackId, level)
|
|
13
|
-
:
|
|
12
|
+
: views[level].trackRefs[trackId]?.getBoundingClientRect().top || 0;
|
|
14
13
|
}
|
|
15
14
|
export function getPxFromCoordinate(view, refName, coord) {
|
|
16
|
-
|
|
17
|
-
return (((_a = view.bpToPx({ refName, coord })) === null || _a === void 0 ? void 0 : _a.offsetPx) || 0) - view.offsetPx;
|
|
15
|
+
return (view.bpToPx({ refName, coord })?.offsetPx || 0) - view.offsetPx;
|
|
18
16
|
}
|
|
19
17
|
export function yPos(trackId, level, views, tracks, c, getYPosOverride) {
|
|
20
18
|
const display = tracks[level].displays[0];
|
|
21
|
-
const min = 0;
|
|
22
19
|
const max = display.height;
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
const yPos = getYPosOverride ? 0 : display.scrollTop;
|
|
29
|
-
return (clamp(c[TOP] - yPos + cheight(c) / 2 + offset, min, max) +
|
|
30
|
-
heightFromSpecificLevel(views, trackId, level, getYPosOverride) +
|
|
31
|
-
display.scrollTop);
|
|
20
|
+
const offset = display.SNPCoverageDisplay?.height ?? 0;
|
|
21
|
+
const scrollTop = getYPosOverride ? 0 : display.scrollTop;
|
|
22
|
+
return (clamp(c[TOP] - scrollTop + cheight(c) / 2 + offset, offset, max) +
|
|
23
|
+
heightFromSpecificLevel(views, trackId, level, getYPosOverride));
|
|
32
24
|
}
|
|
33
25
|
export const useNextFrame = (variable) => {
|
|
34
26
|
const [, setNextFrameState] = useState();
|
|
@@ -42,14 +34,13 @@ export function intersect(cb, a1 = [], a2 = [], ...rest) {
|
|
|
42
34
|
return rest.length === 0 ? a12 : intersect(cb, a12, ...rest);
|
|
43
35
|
}
|
|
44
36
|
export function calc(track, f) {
|
|
45
|
-
|
|
46
|
-
return (_b = (_a = track.displays[0]).searchFeatureByID) === null || _b === void 0 ? void 0 : _b.call(_a, f.id());
|
|
37
|
+
return track.displays[0].searchFeatureByID?.(f.id());
|
|
47
38
|
}
|
|
48
39
|
export async function getBlockFeatures(model, track) {
|
|
49
40
|
const { views } = model;
|
|
50
41
|
const { rpcManager } = getSession(model);
|
|
51
42
|
const sessionId = getRpcSessionId(track);
|
|
52
|
-
return Promise.all(views.flatMap(async (view) => (await rpcManager.call(sessionId, '
|
|
43
|
+
return Promise.all(views.flatMap(async (view) => (await rpcManager.call(sessionId, 'BreakpointGetFeatures', {
|
|
53
44
|
adapterConfig: getConf(track, ['adapter']),
|
|
54
45
|
sessionId,
|
|
55
46
|
regions: view.staticBlocks.contentBlocks,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default function LaunchBreakpointSplitViewF(pluginManager) {
|
|
2
|
+
pluginManager.addToExtensionPoint('LaunchView-BreakpointSplitView', async ({ session, views, }) => {
|
|
3
|
+
if (views.length < 2) {
|
|
4
|
+
throw new Error('BreakpointSplitView requires at least 2 views to be specified');
|
|
5
|
+
}
|
|
6
|
+
session.addView('BreakpointSplitView', {
|
|
7
|
+
init: {
|
|
8
|
+
views,
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
}
|
package/esm/index.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import Plugin from '@jbrowse/core/Plugin';
|
|
2
|
-
import BreakpointAlignmentsWidgetF from
|
|
3
|
-
import
|
|
2
|
+
import BreakpointAlignmentsWidgetF from "./BreakpointAlignmentsFeatureDetail/index.js";
|
|
3
|
+
import BreakpointGetFeaturesF from "./BreakpointGetFeatures/index.js";
|
|
4
|
+
import BreakpointSplitViewF from "./BreakpointSplitView/index.js";
|
|
5
|
+
import LaunchBreakpointSplitViewF from "./LaunchBreakpointSplitView/index.js";
|
|
4
6
|
export default class BreakpointSplitViewPlugin extends Plugin {
|
|
5
|
-
|
|
6
|
-
super(...arguments);
|
|
7
|
-
this.name = 'BreakpointSplitViewPlugin';
|
|
8
|
-
}
|
|
7
|
+
name = 'BreakpointSplitViewPlugin';
|
|
9
8
|
install(pluginManager) {
|
|
10
9
|
BreakpointSplitViewF(pluginManager);
|
|
11
10
|
BreakpointAlignmentsWidgetF(pluginManager);
|
|
11
|
+
LaunchBreakpointSplitViewF(pluginManager);
|
|
12
|
+
BreakpointGetFeaturesF(pluginManager);
|
|
12
13
|
}
|
|
13
14
|
configure() { }
|
|
14
15
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-breakpoint-split-view",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "JBrowse 2 breakpoint detail split view",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -15,48 +15,42 @@
|
|
|
15
15
|
"directory": "plugins/breakpoint-split-view"
|
|
16
16
|
},
|
|
17
17
|
"author": "JBrowse Team",
|
|
18
|
-
"
|
|
19
|
-
"srcMain": "src/index.ts",
|
|
20
|
-
"main": "dist/index.js",
|
|
18
|
+
"main": "esm/index.js",
|
|
21
19
|
"files": [
|
|
22
|
-
"dist",
|
|
23
20
|
"esm"
|
|
24
21
|
],
|
|
25
|
-
"scripts": {
|
|
26
|
-
"build": "npm-run-all build:*",
|
|
27
|
-
"test": "cd ../..; jest --passWithNoTests plugins/breakpoint-split-view",
|
|
28
|
-
"prepublishOnly": "yarn test",
|
|
29
|
-
"prepack": "yarn build && yarn useDist",
|
|
30
|
-
"postpack": "yarn useSrc",
|
|
31
|
-
"useDist": "node ../../scripts/useDist.js",
|
|
32
|
-
"useSrc": "node ../../scripts/useSrc.js",
|
|
33
|
-
"prebuild": "npm run clean",
|
|
34
|
-
"build:esm": "tsc --build tsconfig.build.esm.json",
|
|
35
|
-
"build:commonjs": "tsc --build tsconfig.build.commonjs.json",
|
|
36
|
-
"clean": "rimraf dist esm *.tsbuildinfo"
|
|
37
|
-
},
|
|
38
22
|
"dependencies": {
|
|
39
|
-
"@gmod/vcf": "^6.0
|
|
40
|
-
"@jbrowse/
|
|
41
|
-
"@
|
|
42
|
-
"@mui/
|
|
43
|
-
"@
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"mobx": "^
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"tss-react": "^4.0.0"
|
|
23
|
+
"@gmod/vcf": "^6.1.0",
|
|
24
|
+
"@jbrowse/mobx-state-tree": "^5.5.0",
|
|
25
|
+
"@mui/icons-material": "^7.3.6",
|
|
26
|
+
"@mui/material": "^7.3.6",
|
|
27
|
+
"@types/file-saver-es": "^2.0.3",
|
|
28
|
+
"file-saver-es": "^2.0.5",
|
|
29
|
+
"mobx": "^6.15.0",
|
|
30
|
+
"mobx-react": "^9.2.1",
|
|
31
|
+
"@jbrowse/core": "^4.0.0",
|
|
32
|
+
"@jbrowse/plugin-linear-genome-view": "^4.0.0"
|
|
50
33
|
},
|
|
51
34
|
"peerDependencies": {
|
|
52
35
|
"react": ">=16.8.4",
|
|
53
36
|
"react-dom": ">=16.8.4"
|
|
54
37
|
},
|
|
55
|
-
"distModule": "esm/index.js",
|
|
56
|
-
"srcModule": "src/index.ts",
|
|
57
|
-
"module": "esm/index.js",
|
|
58
38
|
"publishConfig": {
|
|
59
39
|
"access": "public"
|
|
60
40
|
},
|
|
61
|
-
"
|
|
62
|
-
|
|
41
|
+
"sideEffects": false,
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "pnpm run /^build:/",
|
|
44
|
+
"test": "cd ../..; jest --passWithNoTests plugins/breakpoint-split-view",
|
|
45
|
+
"prebuild": "pnpm clean",
|
|
46
|
+
"build:esm": "tsc -p tsconfig.build.esm.json",
|
|
47
|
+
"clean": "rimraf esm *.tsbuildinfo"
|
|
48
|
+
},
|
|
49
|
+
"types": "esm/index.d.ts",
|
|
50
|
+
"exports": {
|
|
51
|
+
".": {
|
|
52
|
+
"types": "./esm/index.d.ts",
|
|
53
|
+
"import": "./esm/index.js"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { SimpleFeatureSerialized } from '@jbrowse/core/util';
|
|
2
|
-
declare const BreakpointAlignmentsFeatureDetail: ({ model, }: {
|
|
3
|
-
model: {
|
|
4
|
-
featureData: {
|
|
5
|
-
feature1: SimpleFeatureSerialized;
|
|
6
|
-
feature2: SimpleFeatureSerialized;
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
|
-
}) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
-
export default BreakpointAlignmentsFeatureDetail;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
|
-
const BaseFeatureDetail_1 = require("@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail");
|
|
5
|
-
const material_1 = require("@mui/material");
|
|
6
|
-
const mobx_react_1 = require("mobx-react");
|
|
7
|
-
const BreakpointAlignmentsFeatureDetail = (0, mobx_react_1.observer)(function ({ model, }) {
|
|
8
|
-
const { featureData } = model;
|
|
9
|
-
const { feature1, feature2 } = structuredClone(featureData);
|
|
10
|
-
return ((0, jsx_runtime_1.jsxs)(material_1.Paper, { children: [(0, jsx_runtime_1.jsx)(BaseFeatureDetail_1.BaseCoreDetails, { title: "Feature 1", feature: feature1 }), (0, jsx_runtime_1.jsx)(BaseFeatureDetail_1.BaseCoreDetails, { title: "Feature 2", feature: feature2 }), (0, jsx_runtime_1.jsx)(BaseFeatureDetail_1.BaseAttributes, { title: "Feature 1 attributes", feature: feature1 }), (0, jsx_runtime_1.jsx)(BaseFeatureDetail_1.BaseAttributes, { title: "Feature 2 attributes", feature: feature2 })] }));
|
|
11
|
-
});
|
|
12
|
-
exports.default = BreakpointAlignmentsFeatureDetail;
|
|
@@ -1,67 +0,0 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.default = BreakpointAlignmentsFeatureDetailF;
|
|
37
|
-
const react_1 = require("react");
|
|
38
|
-
const configuration_1 = require("@jbrowse/core/configuration");
|
|
39
|
-
const pluggableElementTypes_1 = require("@jbrowse/core/pluggableElementTypes");
|
|
40
|
-
const mst_1 = require("@jbrowse/core/util/types/mst");
|
|
41
|
-
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
42
|
-
const configSchema = (0, configuration_1.ConfigurationSchema)('BreakpointAlignmentsWidget', {});
|
|
43
|
-
const stateModel = mobx_state_tree_1.types
|
|
44
|
-
.model('BreakpointAlignmentsWidget', {
|
|
45
|
-
id: mst_1.ElementId,
|
|
46
|
-
type: mobx_state_tree_1.types.literal('BreakpointAlignmentsWidget'),
|
|
47
|
-
featureData: mobx_state_tree_1.types.frozen(),
|
|
48
|
-
})
|
|
49
|
-
.actions(self => ({
|
|
50
|
-
setFeatureData(data) {
|
|
51
|
-
self.featureData = data;
|
|
52
|
-
},
|
|
53
|
-
clearFeatureData() {
|
|
54
|
-
self.featureData = undefined;
|
|
55
|
-
},
|
|
56
|
-
}));
|
|
57
|
-
function BreakpointAlignmentsFeatureDetailF(pluginManager) {
|
|
58
|
-
pluginManager.addWidgetType(() => {
|
|
59
|
-
return new pluggableElementTypes_1.WidgetType({
|
|
60
|
-
name: 'BreakpointAlignmentsWidget',
|
|
61
|
-
heading: 'Breakpoint feature details',
|
|
62
|
-
configSchema,
|
|
63
|
-
stateModel,
|
|
64
|
-
ReactComponent: (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./BreakpointAlignmentsFeatureDetail')))),
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import ViewType from '@jbrowse/core/pluggableElementTypes/ViewType';
|
|
2
|
-
import { type AbstractSessionModel, type Feature } from '@jbrowse/core/util';
|
|
3
|
-
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly';
|
|
4
|
-
export default class BreakpointSplitViewType extends ViewType {
|
|
5
|
-
getBreakendCoveringRegions({ feature, assembly, }: {
|
|
6
|
-
feature: Feature;
|
|
7
|
-
assembly: Assembly;
|
|
8
|
-
}): {
|
|
9
|
-
pos: number;
|
|
10
|
-
refName: string;
|
|
11
|
-
mateRefName: string;
|
|
12
|
-
matePos: any;
|
|
13
|
-
};
|
|
14
|
-
singleLevelSnapshotFromBreakendFeature({ feature, session, assemblyName, }: {
|
|
15
|
-
feature: Feature;
|
|
16
|
-
session: AbstractSessionModel;
|
|
17
|
-
assemblyName: string;
|
|
18
|
-
}): {
|
|
19
|
-
coverage: {
|
|
20
|
-
pos: number;
|
|
21
|
-
refName: string;
|
|
22
|
-
mateRefName: string;
|
|
23
|
-
matePos: any;
|
|
24
|
-
};
|
|
25
|
-
snap: {
|
|
26
|
-
type: string;
|
|
27
|
-
views: {
|
|
28
|
-
type: string;
|
|
29
|
-
displayedRegions: import("@jbrowse/core/assemblyManager/assembly").BasicRegion[];
|
|
30
|
-
}[];
|
|
31
|
-
displayName: string;
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
}
|