@jbrowse/plugin-breakpoint-split-view 3.6.5 → 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.
Files changed (99) hide show
  1. package/esm/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js +1 -1
  2. package/esm/BreakpointAlignmentsFeatureDetail/index.js +2 -2
  3. package/esm/BreakpointGetFeatures/BreakpointGetFeatures.d.ts +51 -0
  4. package/esm/BreakpointGetFeatures/BreakpointGetFeatures.js +57 -0
  5. package/esm/BreakpointGetFeatures/index.d.ts +2 -0
  6. package/esm/BreakpointGetFeatures/index.js +4 -0
  7. package/esm/BreakpointSplitView/BreakpointSplitView.js +33 -47
  8. package/esm/BreakpointSplitView/components/AlignmentConnections.d.ts +2 -7
  9. package/esm/BreakpointSplitView/components/AlignmentConnections.js +20 -25
  10. package/esm/BreakpointSplitView/components/Breakends.d.ts +2 -7
  11. package/esm/BreakpointSplitView/components/Breakends.js +28 -59
  12. package/esm/BreakpointSplitView/components/BreakpointSplitView.d.ts +1 -1
  13. package/esm/BreakpointSplitView/components/BreakpointSplitView.js +19 -5
  14. package/esm/BreakpointSplitView/components/BreakpointSplitViewOverlay.d.ts +1 -1
  15. package/esm/BreakpointSplitView/components/BreakpointSplitViewOverlay.js +3 -3
  16. package/esm/BreakpointSplitView/components/ExportSvgDialog.d.ts +1 -1
  17. package/esm/BreakpointSplitView/components/ExportSvgDialog.js +5 -1
  18. package/esm/BreakpointSplitView/components/Header.d.ts +5 -0
  19. package/esm/BreakpointSplitView/components/Header.js +47 -0
  20. package/esm/BreakpointSplitView/components/HeaderSearchBoxes.d.ts +5 -0
  21. package/esm/BreakpointSplitView/components/HeaderSearchBoxes.js +22 -0
  22. package/esm/BreakpointSplitView/components/Overlay.d.ts +1 -1
  23. package/esm/BreakpointSplitView/components/Overlay.js +8 -11
  24. package/esm/BreakpointSplitView/components/PairedFeatures.d.ts +2 -7
  25. package/esm/BreakpointSplitView/components/PairedFeatures.js +22 -47
  26. package/esm/BreakpointSplitView/components/Rubberband.d.ts +6 -0
  27. package/esm/BreakpointSplitView/components/Rubberband.js +27 -0
  28. package/esm/BreakpointSplitView/components/RubberbandSpan.d.ts +15 -0
  29. package/esm/BreakpointSplitView/components/RubberbandSpan.js +30 -0
  30. package/esm/BreakpointSplitView/components/RubberbandTooltip.d.ts +5 -0
  31. package/esm/BreakpointSplitView/components/RubberbandTooltip.js +17 -0
  32. package/esm/BreakpointSplitView/components/Translocations.d.ts +2 -7
  33. package/esm/BreakpointSplitView/components/Translocations.js +23 -58
  34. package/esm/BreakpointSplitView/components/VerticalGuide.d.ts +6 -0
  35. package/esm/BreakpointSplitView/components/VerticalGuide.js +24 -0
  36. package/esm/BreakpointSplitView/components/overlayUtils.d.ts +24 -0
  37. package/esm/BreakpointSplitView/components/overlayUtils.js +47 -0
  38. package/esm/BreakpointSplitView/components/rubberbandUtil.d.ts +4 -0
  39. package/esm/BreakpointSplitView/components/rubberbandUtil.js +3 -0
  40. package/esm/BreakpointSplitView/components/useRangeSelect.d.ts +59 -0
  41. package/esm/BreakpointSplitView/components/useRangeSelect.js +121 -0
  42. package/esm/BreakpointSplitView/components/util.js +1 -2
  43. package/esm/BreakpointSplitView/getClip.js +4 -4
  44. package/esm/BreakpointSplitView/index.js +2 -2
  45. package/esm/BreakpointSplitView/model.d.ts +403 -116
  46. package/esm/BreakpointSplitView/model.js +117 -41
  47. package/esm/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.d.ts +2 -2
  48. package/esm/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js +8 -8
  49. package/esm/BreakpointSplitView/types.d.ts +8 -0
  50. package/esm/BreakpointSplitView/util.d.ts +1 -1
  51. package/esm/BreakpointSplitView/util.js +8 -17
  52. package/esm/LaunchBreakpointSplitView/index.d.ts +2 -0
  53. package/esm/LaunchBreakpointSplitView/index.js +12 -0
  54. package/esm/index.js +7 -6
  55. package/package.json +28 -34
  56. package/dist/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.d.ts +0 -10
  57. package/dist/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js +0 -12
  58. package/dist/BreakpointAlignmentsFeatureDetail/index.d.ts +0 -2
  59. package/dist/BreakpointAlignmentsFeatureDetail/index.js +0 -67
  60. package/dist/BreakpointSplitView/BreakpointSplitView.d.ts +0 -34
  61. package/dist/BreakpointSplitView/BreakpointSplitView.js +0 -84
  62. package/dist/BreakpointSplitView/components/AlignmentConnections.d.ts +0 -8
  63. package/dist/BreakpointSplitView/components/AlignmentConnections.js +0 -133
  64. package/dist/BreakpointSplitView/components/Breakends.d.ts +0 -8
  65. package/dist/BreakpointSplitView/components/Breakends.js +0 -95
  66. package/dist/BreakpointSplitView/components/BreakpointSplitView.d.ts +0 -5
  67. package/dist/BreakpointSplitView/components/BreakpointSplitView.js +0 -45
  68. package/dist/BreakpointSplitView/components/BreakpointSplitViewOverlay.d.ts +0 -5
  69. package/dist/BreakpointSplitView/components/BreakpointSplitViewOverlay.js +0 -33
  70. package/dist/BreakpointSplitView/components/ExportSvgDialog.d.ts +0 -7
  71. package/dist/BreakpointSplitView/components/ExportSvgDialog.js +0 -57
  72. package/dist/BreakpointSplitView/components/Overlay.d.ts +0 -8
  73. package/dist/BreakpointSplitView/components/Overlay.js +0 -27
  74. package/dist/BreakpointSplitView/components/PairedFeatures.d.ts +0 -8
  75. package/dist/BreakpointSplitView/components/PairedFeatures.js +0 -75
  76. package/dist/BreakpointSplitView/components/Translocations.d.ts +0 -8
  77. package/dist/BreakpointSplitView/components/Translocations.js +0 -99
  78. package/dist/BreakpointSplitView/components/getOrientationColor.d.ts +0 -41
  79. package/dist/BreakpointSplitView/components/getOrientationColor.js +0 -103
  80. package/dist/BreakpointSplitView/components/util.d.ts +0 -8
  81. package/dist/BreakpointSplitView/components/util.js +0 -142
  82. package/dist/BreakpointSplitView/getClip.d.ts +0 -1
  83. package/dist/BreakpointSplitView/getClip.js +0 -10
  84. package/dist/BreakpointSplitView/index.d.ts +0 -2
  85. package/dist/BreakpointSplitView/index.js +0 -52
  86. package/dist/BreakpointSplitView/model.d.ts +0 -342
  87. package/dist/BreakpointSplitView/model.js +0 -244
  88. package/dist/BreakpointSplitView/svgcomponents/SVGBackground.d.ts +0 -5
  89. package/dist/BreakpointSplitView/svgcomponents/SVGBackground.js +0 -10
  90. package/dist/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.d.ts +0 -5
  91. package/dist/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js +0 -41
  92. package/dist/BreakpointSplitView/svgcomponents/util.d.ts +0 -4
  93. package/dist/BreakpointSplitView/svgcomponents/util.js +0 -18
  94. package/dist/BreakpointSplitView/types.d.ts +0 -22
  95. package/dist/BreakpointSplitView/types.js +0 -2
  96. package/dist/BreakpointSplitView/util.d.ts +0 -28
  97. package/dist/BreakpointSplitView/util.js +0 -67
  98. package/dist/index.d.ts +0 -7
  99. 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 { addDisposer, getPath, onAction, types } from 'mobx-state-tree';
9
- import { getClip } from './getClip';
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
@@ -19,19 +17,32 @@ export default function stateModelFactory(pluginManager) {
19
17
  showIntraviewLinks: true,
20
18
  linkViews: false,
21
19
  interactiveOverlay: true,
20
+ showHeader: false,
22
21
  views: types.array(pluginManager.getViewType('LinearGenomeView')
23
22
  .stateModel),
23
+ init: types.frozen(),
24
24
  }))
25
25
  .volatile(() => ({
26
26
  width: 800,
27
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
+ },
28
39
  }))
29
40
  .views(self => ({
30
41
  async exportSvg(opts = {}) {
31
- const { renderToSvg } = await import('./svgcomponents/SVGBreakpointSplitView');
42
+ const { renderToSvg } = await import("./svgcomponents/SVGBreakpointSplitView.js");
32
43
  const html = await renderToSvg(self, opts);
33
- const blob = new Blob([html], { type: 'image/svg+xml' });
34
- saveAs(blob, opts.filename || 'image.svg');
44
+ const { saveAs } = await import('file-saver-es');
45
+ saveAs(new Blob([html], { type: 'image/svg+xml' }), opts.filename || 'image.svg');
35
46
  },
36
47
  }))
37
48
  .views(self => ({
@@ -43,40 +54,44 @@ export default function stateModelFactory(pluginManager) {
43
54
  getMatchedTracks(trackConfigId) {
44
55
  return self.views
45
56
  .map(view => view.getTrack(trackConfigId))
46
- .filter(f => !!f);
57
+ .filter(notEmpty);
47
58
  },
48
59
  hasTranslocations(trackConfigId) {
49
- return [...this.getTrackFeatures(trackConfigId).values()].find(f => f.get('type') === 'translocation');
60
+ return [...this.getTrackFeatures(trackConfigId).values()].some(f => f.get('type') === 'translocation');
50
61
  },
51
62
  hasPairedFeatures(trackConfigId) {
52
- return [...this.getTrackFeatures(trackConfigId).values()].find(f => f.get('type') === 'paired_feature');
63
+ return [...this.getTrackFeatures(trackConfigId).values()].some(f => f.get('type') === 'paired_feature');
53
64
  },
54
65
  getTrackFeatures(trackConfigId) {
55
- var _a;
56
- return new Map((_a = self.matchedTrackFeatures[trackConfigId]) === null || _a === void 0 ? void 0 : _a.flat().map(f => [f.id(), f]));
66
+ return new Map(self.matchedTrackFeatures[trackConfigId]
67
+ ?.flat()
68
+ .map(f => [f.id(), f]));
57
69
  },
58
70
  getMatchedFeaturesInLayout(trackConfigId, features) {
59
71
  const tracks = this.getMatchedTracks(trackConfigId);
60
72
  return features.map(c => c
61
73
  .map(feature => {
62
- const level = tracks.findIndex(track => calc(track, feature));
63
- return level !== -1
64
- ? {
65
- feature,
66
- layout: calc(tracks[level], feature),
67
- level,
68
- clipPos: getClip(feature.get('CIGAR'), feature.get('strand')),
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
+ };
69
83
  }
70
- : undefined;
84
+ }
85
+ return undefined;
71
86
  })
72
87
  .filter(notEmpty));
73
88
  },
74
89
  }))
75
90
  .actions(self => ({
76
91
  afterAttach() {
77
- addDisposer(self, onAction(self, ({ name, path, args, }) => {
78
- if (self.linkViews) {
79
- const actions = [
92
+ addDisposer(self, addMiddleware(self, (rawCall, next) => {
93
+ if (rawCall.type === 'action' && rawCall.id === rawCall.rootId) {
94
+ const syncActions = [
80
95
  'horizontalScroll',
81
96
  'zoomTo',
82
97
  'setScaleFactor',
@@ -86,20 +101,21 @@ export default function stateModelFactory(pluginManager) {
86
101
  'setTrackLabels',
87
102
  'toggleCenterLine',
88
103
  ];
89
- if (actions.includes(name) && path) {
90
- this.onSubviewAction(name, path, args);
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;
91
114
  }
92
115
  }
116
+ next(rawCall);
93
117
  }));
94
118
  },
95
- onSubviewAction(actionName, path, args) {
96
- for (const view of self.views) {
97
- const ret = getPath(view);
98
- if (!ret.endsWith(path)) {
99
- view[actionName](args === null || args === void 0 ? void 0 : args[0]);
100
- }
101
- }
102
- },
103
119
  setWidth(newWidth) {
104
120
  self.width = newWidth;
105
121
  for (const v of self.views) {
@@ -115,21 +131,42 @@ export default function stateModelFactory(pluginManager) {
115
131
  setLinkViews(arg) {
116
132
  self.linkViews = arg;
117
133
  },
134
+ setShowHeader(arg) {
135
+ self.showHeader = arg;
136
+ },
118
137
  setMatchedTrackFeatures(obj) {
119
138
  self.matchedTrackFeatures = obj;
120
139
  },
121
140
  reverseViewOrder() {
122
141
  self.views.reverse();
123
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
+ },
124
153
  }))
125
154
  .actions(self => ({
126
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' }));
127
164
  addDisposer(self, autorun(async () => {
128
165
  try {
129
166
  if (!self.views.every(view => view.initialized)) {
130
167
  return;
131
168
  }
132
- if (self.matchedTracks.some(track => { var _a, _b; return (_b = (_a = track.displays[0]).notReady) === null || _b === void 0 ? void 0 : _b.call(_a); })) {
169
+ if (self.matchedTracks.some(track => track.displays[0].notReady?.())) {
133
170
  return;
134
171
  }
135
172
  self.setMatchedTrackFeatures(Object.fromEntries(await Promise.all(self.matchedTracks.map(async (track) => [
@@ -141,15 +178,16 @@ export default function stateModelFactory(pluginManager) {
141
178
  console.error(e);
142
179
  getSession(self).notifyError(`${e}`, e);
143
180
  }
181
+ }, {
182
+ name: 'BreakpointFeatureFetcher',
183
+ delay: 1000,
144
184
  }));
145
185
  },
146
186
  menuItems() {
147
187
  return [
148
- ...self.views
149
- .map((view, idx) => [idx, view.menuItems()])
150
- .map(f => ({
151
- label: `Row ${f[0] + 1} view menu`,
152
- subMenu: f[1],
188
+ ...self.views.map((view, idx) => ({
189
+ label: `Row ${idx + 1} view menu`,
190
+ subMenu: view.menuItems(),
153
191
  })),
154
192
  ...(self.views.length > 1
155
193
  ? [
@@ -161,6 +199,14 @@ export default function stateModelFactory(pluginManager) {
161
199
  },
162
200
  ]
163
201
  : []),
202
+ {
203
+ label: 'Show header',
204
+ type: 'checkbox',
205
+ checked: self.showHeader,
206
+ onClick: () => {
207
+ self.setShowHeader(!self.showHeader);
208
+ },
209
+ },
164
210
  {
165
211
  label: 'Show intra-view links',
166
212
  type: 'checkbox',
@@ -201,5 +247,35 @@ export default function stateModelFactory(pluginManager) {
201
247
  },
202
248
  ];
203
249
  },
204
- }));
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
+ });
205
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 './SVGBackground';
8
- import { getTrackNameMaxLen, getTrackOffsets } from './util';
9
- import Overlay from '../components/Overlay';
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
- var _a;
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 = (_a = session.allThemes) === null || _a === void 0 ? void 0 : _a.call(session)[themeName];
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
- 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 })] }), _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 })] }), _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))) })] }) }) }));
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
- : ((_a = views[level].trackRefs[trackId]) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().top) || 0;
12
+ : views[level].trackRefs[trackId]?.getBoundingClientRect().top || 0;
14
13
  }
15
14
  export function getPxFromCoordinate(view, refName, coord) {
16
- var _a;
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
- let offset = 0;
24
- const { SNPCoverageDisplay } = display;
25
- if (SNPCoverageDisplay) {
26
- offset = SNPCoverageDisplay.height;
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
- var _a, _b;
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, 'CoreGetFeatures', {
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,2 @@
1
+ import type PluginManager from '@jbrowse/core/PluginManager';
2
+ export default function LaunchBreakpointSplitViewF(pluginManager: PluginManager): void;
@@ -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 './BreakpointAlignmentsFeatureDetail';
3
- import BreakpointSplitViewF from './BreakpointSplitView';
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
- constructor() {
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.6.5",
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
- "distMain": "dist/index.js",
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.8",
40
- "@jbrowse/core": "^3.6.5",
41
- "@jbrowse/plugin-linear-genome-view": "^3.6.5",
42
- "@mui/icons-material": "^7.0.0",
43
- "@mui/material": "^7.0.0",
44
- "@types/file-saver": "^2.0.1",
45
- "file-saver": "^2.0.0",
46
- "mobx": "^6.0.0",
47
- "mobx-react": "^9.0.0",
48
- "mobx-state-tree": "^5.0.0",
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
- "gitHead": "354d0a87b757b4d84f824b47507662f6f3a1693f"
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,2 +0,0 @@
1
- import type PluginManager from '@jbrowse/core/PluginManager';
2
- export default function BreakpointAlignmentsFeatureDetailF(pluginManager: PluginManager): void;
@@ -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
- }