@jbrowse/plugin-linear-comparative-view 2.15.3 → 2.16.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 (101) hide show
  1. package/dist/LaunchLinearSyntenyView.js +41 -11
  2. package/dist/LinearComparativeDisplay/stateModelFactory.d.ts +14 -9
  3. package/dist/LinearComparativeDisplay/stateModelFactory.js +8 -9
  4. package/dist/LinearComparativeView/components/Header.d.ts +2 -3
  5. package/dist/LinearComparativeView/components/Header.js +72 -62
  6. package/dist/LinearComparativeView/components/HeaderSearchBoxes.d.ts +6 -0
  7. package/dist/LinearComparativeView/components/HeaderSearchBoxes.js +34 -0
  8. package/dist/LinearComparativeView/components/LinearComparativeRenderArea.d.ts +6 -0
  9. package/dist/LinearComparativeView/components/LinearComparativeRenderArea.js +61 -0
  10. package/dist/LinearComparativeView/components/LinearComparativeView.d.ts +2 -4
  11. package/dist/LinearComparativeView/components/LinearComparativeView.js +3 -67
  12. package/dist/LinearComparativeView/components/Rubberband.js +1 -1
  13. package/dist/LinearComparativeView/index.js +3 -0
  14. package/dist/LinearComparativeView/model.d.ts +265 -12
  15. package/dist/LinearComparativeView/model.js +45 -75
  16. package/dist/LinearSyntenyDisplay/afterAttach.js +5 -3
  17. package/dist/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +32 -24
  18. package/dist/LinearSyntenyDisplay/components/SyntenyContextMenu.js +12 -6
  19. package/dist/LinearSyntenyDisplay/components/util.d.ts +2 -1
  20. package/dist/LinearSyntenyDisplay/components/util.js +5 -5
  21. package/dist/LinearSyntenyDisplay/drawSynteny.d.ts +1 -1
  22. package/dist/LinearSyntenyDisplay/drawSynteny.js +28 -22
  23. package/dist/LinearSyntenyDisplay/index.js +1 -1
  24. package/dist/LinearSyntenyDisplay/model.d.ts +12 -11
  25. package/dist/LinearSyntenyDisplay/model.js +7 -0
  26. package/dist/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.d.ts → AddCustomTrack.d.ts} +2 -3
  27. package/dist/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.js → AddCustomTrack.js} +3 -3
  28. package/dist/LinearSyntenyView/components/ImportForm/LinearSyntenyImportForm.js +195 -0
  29. package/dist/LinearSyntenyView/components/ImportForm/Spacer.d.ts +2 -0
  30. package/dist/LinearSyntenyView/components/ImportForm/Spacer.js +10 -0
  31. package/dist/LinearSyntenyView/components/ImportForm/TrackSelector.d.ts +10 -0
  32. package/dist/LinearSyntenyView/components/ImportForm/{ImportSyntenyTrackSelector.js → TrackSelector.js} +15 -20
  33. package/dist/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.d.ts +14 -0
  34. package/dist/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.js +52 -0
  35. package/dist/LinearSyntenyView/components/LinearSyntenyView.js +3 -3
  36. package/dist/LinearSyntenyView/index.js +1 -1
  37. package/dist/LinearSyntenyView/model.d.ts +267 -9
  38. package/dist/LinearSyntenyView/model.js +2 -2
  39. package/dist/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.d.ts +12 -0
  40. package/dist/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.js +19 -0
  41. package/dist/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.d.ts +1 -3
  42. package/dist/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +36 -27
  43. package/dist/LinearSyntenyViewHelper/index.d.ts +2 -0
  44. package/dist/LinearSyntenyViewHelper/index.js +25 -0
  45. package/dist/LinearSyntenyViewHelper/stateModelFactory.d.ts +30 -0
  46. package/dist/LinearSyntenyViewHelper/stateModelFactory.js +105 -0
  47. package/dist/index.js +2 -0
  48. package/esm/LaunchLinearSyntenyView.js +41 -11
  49. package/esm/LinearComparativeDisplay/stateModelFactory.d.ts +14 -9
  50. package/esm/LinearComparativeDisplay/stateModelFactory.js +9 -10
  51. package/esm/LinearComparativeView/components/Header.d.ts +2 -3
  52. package/esm/LinearComparativeView/components/Header.js +73 -63
  53. package/esm/LinearComparativeView/components/HeaderSearchBoxes.d.ts +6 -0
  54. package/esm/LinearComparativeView/components/HeaderSearchBoxes.js +29 -0
  55. package/esm/LinearComparativeView/components/LinearComparativeRenderArea.d.ts +6 -0
  56. package/esm/LinearComparativeView/components/LinearComparativeRenderArea.js +56 -0
  57. package/esm/LinearComparativeView/components/LinearComparativeView.d.ts +2 -4
  58. package/esm/LinearComparativeView/components/LinearComparativeView.js +3 -67
  59. package/esm/LinearComparativeView/components/Rubberband.js +1 -1
  60. package/esm/LinearComparativeView/index.js +3 -0
  61. package/esm/LinearComparativeView/model.d.ts +265 -12
  62. package/esm/LinearComparativeView/model.js +47 -77
  63. package/esm/LinearSyntenyDisplay/afterAttach.js +6 -4
  64. package/esm/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +33 -25
  65. package/esm/LinearSyntenyDisplay/components/SyntenyContextMenu.js +12 -6
  66. package/esm/LinearSyntenyDisplay/components/util.d.ts +2 -1
  67. package/esm/LinearSyntenyDisplay/components/util.js +5 -5
  68. package/esm/LinearSyntenyDisplay/drawSynteny.d.ts +1 -1
  69. package/esm/LinearSyntenyDisplay/drawSynteny.js +28 -22
  70. package/esm/LinearSyntenyDisplay/index.js +1 -1
  71. package/esm/LinearSyntenyDisplay/model.d.ts +12 -11
  72. package/esm/LinearSyntenyDisplay/model.js +8 -1
  73. package/esm/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.d.ts → AddCustomTrack.d.ts} +2 -3
  74. package/esm/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.js → AddCustomTrack.js} +3 -3
  75. package/esm/LinearSyntenyView/components/ImportForm/LinearSyntenyImportForm.js +167 -0
  76. package/esm/LinearSyntenyView/components/ImportForm/Spacer.d.ts +2 -0
  77. package/esm/LinearSyntenyView/components/ImportForm/Spacer.js +4 -0
  78. package/esm/LinearSyntenyView/components/ImportForm/TrackSelector.d.ts +10 -0
  79. package/esm/LinearSyntenyView/components/ImportForm/{ImportSyntenyTrackSelector.js → TrackSelector.js} +15 -20
  80. package/esm/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.d.ts +14 -0
  81. package/esm/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.js +23 -0
  82. package/esm/LinearSyntenyView/components/LinearSyntenyView.js +3 -3
  83. package/esm/LinearSyntenyView/index.js +1 -1
  84. package/esm/LinearSyntenyView/model.d.ts +267 -9
  85. package/esm/LinearSyntenyView/model.js +2 -2
  86. package/esm/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.d.ts +12 -0
  87. package/esm/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.js +13 -0
  88. package/esm/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.d.ts +1 -3
  89. package/esm/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +38 -29
  90. package/esm/LinearSyntenyViewHelper/index.d.ts +2 -0
  91. package/esm/LinearSyntenyViewHelper/index.js +19 -0
  92. package/esm/LinearSyntenyViewHelper/stateModelFactory.d.ts +30 -0
  93. package/esm/LinearSyntenyViewHelper/stateModelFactory.js +102 -0
  94. package/esm/index.js +2 -0
  95. package/package.json +2 -2
  96. package/dist/LinearSyntenyView/components/ImportForm/ImportSyntenyTrackSelector.d.ts +0 -9
  97. package/dist/LinearSyntenyView/components/ImportForm/index.js +0 -138
  98. package/esm/LinearSyntenyView/components/ImportForm/ImportSyntenyTrackSelector.d.ts +0 -9
  99. package/esm/LinearSyntenyView/components/ImportForm/index.js +0 -110
  100. /package/dist/LinearSyntenyView/components/ImportForm/{index.d.ts → LinearSyntenyImportForm.d.ts} +0 -0
  101. /package/esm/LinearSyntenyView/components/ImportForm/{index.d.ts → LinearSyntenyImportForm.d.ts} +0 -0
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { useTheme } from '@mui/material';
3
+ import { getFillProps } from '@jbrowse/core/util';
4
+ import { SVGTracks, SVGRuler, } from '@jbrowse/plugin-linear-genome-view';
5
+ export default function SVGLinearGenomeView({ trackLabelOffset, fontSize, textHeight, trackLabels, view, displayResults, rulerHeight, shift, }) {
6
+ const theme = useTheme();
7
+ return (React.createElement("g", { transform: `translate(${shift} ${fontSize})` },
8
+ React.createElement("g", { transform: `translate(${trackLabelOffset})` },
9
+ React.createElement("text", { x: 0, fontSize: fontSize, ...getFillProps(theme.palette.text.primary) }, view.assemblyNames.join(', ')),
10
+ React.createElement(SVGRuler, { model: displayResults.view, fontSize: fontSize })),
11
+ React.createElement("g", { transform: `translate(0 ${rulerHeight + fontSize})` },
12
+ React.createElement(SVGTracks, { textHeight: textHeight, trackLabels: trackLabels, fontSize: fontSize, model: displayResults.view, displayResults: displayResults.data, trackLabelOffset: trackLabelOffset }))));
13
+ }
@@ -1,4 +1,2 @@
1
1
  import { ExportSvgOptions, LinearSyntenyViewModel } from '../model';
2
- type LSV = LinearSyntenyViewModel;
3
- export declare function renderToSvg(model: LSV, opts: ExportSvgOptions): Promise<string>;
4
- export {};
2
+ export declare function renderToSvg(model: LinearSyntenyViewModel, opts: ExportSvgOptions): Promise<string>;
@@ -2,26 +2,27 @@ import React from 'react';
2
2
  import { ThemeProvider } from '@mui/material';
3
3
  import { getRoot } from 'mobx-state-tree';
4
4
  import { when } from 'mobx';
5
- import { getSession, getSerializedSvg, max, measureText, ReactRendering, renderToAbstractCanvas, renderToStaticMarkup, sum, getFillProps, } from '@jbrowse/core/util';
5
+ import { getSession, getSerializedSvg, max, measureText, ReactRendering, renderToAbstractCanvas, renderToStaticMarkup, sum, } from '@jbrowse/core/util';
6
6
  import { getTrackName } from '@jbrowse/core/util/tracks';
7
7
  import { createJBrowseTheme } from '@jbrowse/core/ui';
8
- import { SVGTracks, SVGRuler, totalHeight, } from '@jbrowse/plugin-linear-genome-view';
8
+ import { totalHeight } from '@jbrowse/plugin-linear-genome-view';
9
9
  // locals
10
10
  import SVGBackground from './SVGBackground';
11
+ import SVGLinearGenomeView from './SVGLinearGenomeView';
11
12
  import { drawRef } from '../../LinearSyntenyDisplay/drawSynteny';
12
13
  // render LGV to SVG
13
14
  export async function renderToSvg(model, opts) {
14
15
  var _a;
15
16
  await when(() => model.initialized);
16
- const { textHeight = 18, headerHeight = 30, rulerHeight = 30, fontSize = 13, trackLabels = 'offset', Wrapper = ({ children }) => children, themeName = 'default', } = opts;
17
+ const { textHeight = 18, rulerHeight = 30, fontSize = 13, trackLabels = 'offset', Wrapper = ({ children }) => children, themeName = 'default', } = opts;
17
18
  const session = getSession(model);
18
19
  const themeVar = (_a = session.allThemes) === null || _a === void 0 ? void 0 : _a.call(session)[themeName];
19
- const { width, views, middleComparativeHeight: synH, tracks } = model;
20
+ const { width, views, levels } = model;
20
21
  const shift = 50;
21
- const offset = headerHeight + rulerHeight;
22
+ const offset = rulerHeight;
22
23
  const { createRootFn } = getRoot(model);
23
24
  const heights = views.map(v => totalHeight(v.tracks, textHeight, trackLabels) + offset);
24
- const totalHeightSvg = sum(heights) + synH + 100;
25
+ const totalHeightSvg = sum(heights) + sum(levels.map(l => l.height)) + 100;
25
26
  const displayResults = await Promise.all(views.map(async (view) => ({
26
27
  view,
27
28
  data: await Promise.all(view.tracks.map(async (track) => {
@@ -33,50 +34,58 @@ export async function renderToSvg(model, opts) {
33
34
  };
34
35
  })),
35
36
  })));
36
- const renderings = await Promise.all(tracks.map(async (track) => {
37
+ const renderings = await Promise.all(levels.map(async (level) => await Promise.all(level.tracks.map(async (track) => {
37
38
  const d = track.displays[0];
38
39
  await when(() => (d.ready !== undefined ? d.ready : true));
39
- const r = await renderToAbstractCanvas(width, synH, { exportSVG: opts }, ctx => {
40
+ const r = await renderToAbstractCanvas(width, level.height, { exportSVG: opts }, ctx => {
40
41
  drawRef(d, ctx);
41
42
  return undefined;
42
43
  });
43
44
  if ('imageData' in r) {
44
45
  throw new Error('found a canvas in svg export, probably a bug');
45
46
  }
46
- if ('canvasRecordedData' in r) {
47
+ else if ('canvasRecordedData' in r) {
47
48
  return {
48
49
  html: await getSerializedSvg({
49
50
  ...r,
50
51
  width,
51
- height: synH,
52
+ height: level.height,
52
53
  }),
53
54
  };
54
55
  }
55
- return r;
56
- }));
57
- const trackLabelMaxLen = max(views.flatMap(view => view.tracks.map(t => measureText(getTrackName(t.configuration, session), fontSize))), 0) + 40;
56
+ else {
57
+ return r;
58
+ }
59
+ }))));
60
+ const trackLabelMaxLen = max(views.flatMap(view => view.tracks.map(track => measureText(getTrackName(track.configuration, session), fontSize))), 0) + 40;
58
61
  const trackLabelOffset = trackLabels === 'left' ? trackLabelMaxLen : 0;
59
62
  const w = width + trackLabelOffset;
60
63
  const theme = createJBrowseTheme(themeVar);
64
+ const RenderList = [
65
+ React.createElement(SVGLinearGenomeView, { rulerHeight: rulerHeight, trackLabelOffset: trackLabelOffset, shift: shift, textHeight: textHeight, trackLabels: trackLabels, displayResults: displayResults[0], key: views[0].id, view: views[0], fontSize: fontSize }),
66
+ ];
67
+ let currOffset = heights[0] + fontSize + rulerHeight;
68
+ for (let i = 1; i < views.length; i++) {
69
+ const view = views[i];
70
+ const level = levels[i - 1];
71
+ const rendering = renderings[i - 1];
72
+ const height = heights[i];
73
+ const levelHeight = level.height || 0;
74
+ RenderList.push(React.createElement("g", { key: view.id, transform: `translate(0 ${currOffset})` },
75
+ levelHeight ? (React.createElement("defs", null,
76
+ React.createElement("clipPath", { id: `synclip-${i}` },
77
+ React.createElement("rect", { x: 0, y: 0, width: width, height: levelHeight })))) : null,
78
+ React.createElement("g", { transform: `translate(${shift + trackLabelOffset} ${fontSize})`, clipPath: `url(#synclip-${i})` }, rendering === null || rendering === void 0 ? void 0 : rendering.map((r, i) => (
79
+ /* biome-ignore lint/suspicious/noArrayIndexKey: */
80
+ React.createElement(ReactRendering, { key: i, rendering: r })))),
81
+ React.createElement("g", { transform: `translate(0 ${levelHeight})` },
82
+ React.createElement(SVGLinearGenomeView, { rulerHeight: rulerHeight, shift: shift, trackLabelOffset: trackLabelOffset, textHeight: textHeight, trackLabels: trackLabels, displayResults: displayResults[i], key: view.id, view: view, fontSize: fontSize }))));
83
+ currOffset += height + fontSize + rulerHeight + levelHeight;
84
+ }
61
85
  // the xlink namespace is used for rendering <image> tag
62
86
  return renderToStaticMarkup(React.createElement(ThemeProvider, { theme: theme },
63
87
  React.createElement(Wrapper, null,
64
88
  React.createElement("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() },
65
89
  React.createElement(SVGBackground, { width: w, height: totalHeightSvg, shift: shift }),
66
- React.createElement("g", { transform: `translate(${shift} ${fontSize})` },
67
- React.createElement("g", { transform: `translate(${trackLabelOffset})` },
68
- React.createElement("text", { x: 0, fontSize: fontSize, ...getFillProps(theme.palette.text.primary) }, views[0].assemblyNames.join(', ')),
69
- React.createElement(SVGRuler, { model: displayResults[0].view, fontSize: fontSize })),
70
- React.createElement(SVGTracks, { textHeight: textHeight, trackLabels: trackLabels, fontSize: fontSize, model: displayResults[0].view, displayResults: displayResults[0].data, offset: offset, trackLabelOffset: trackLabelOffset })),
71
- React.createElement("defs", null,
72
- React.createElement("clipPath", { id: 'synclip' },
73
- React.createElement("rect", { x: 0, y: 0, width: width, height: synH }))),
74
- React.createElement("g", { transform: `translate(${shift + trackLabelOffset} ${fontSize + heights[0]})`, clipPath: 'url(#synclip)' }, renderings.map((r, i) => (
75
- /* biome-ignore lint/suspicious/noArrayIndexKey: */
76
- React.createElement(ReactRendering, { key: i, rendering: r })))),
77
- React.createElement("g", { transform: `translate(${shift} ${fontSize + heights[0] + synH})` },
78
- React.createElement("g", { transform: `translate(${trackLabelOffset})` },
79
- React.createElement("text", { x: 0, fontSize: fontSize, ...getFillProps(theme.palette.text.primary) }, views[1].assemblyNames.join(', ')),
80
- React.createElement(SVGRuler, { model: displayResults[1].view, fontSize: fontSize })),
81
- React.createElement(SVGTracks, { textHeight: textHeight, trackLabels: trackLabels, fontSize: fontSize, model: displayResults[1].view, displayResults: displayResults[1].data, offset: offset, trackLabelOffset: trackLabelOffset }))))), createRootFn);
90
+ RenderList))), createRootFn);
82
91
  }
@@ -0,0 +1,2 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager';
2
+ export default function LinearSyntenyViewF(pluginManager: PluginManager): void;
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import ViewType from '@jbrowse/core/pluggableElementTypes/ViewType';
3
+ import { linearSyntenyViewHelperModelFactory } from './stateModelFactory';
4
+ function UnusedComponent() {
5
+ return React.createElement("div", null);
6
+ }
7
+ export default function LinearSyntenyViewF(pluginManager) {
8
+ pluginManager.addViewType(() => {
9
+ return new ViewType({
10
+ name: 'LinearSyntenyViewHelper',
11
+ displayName: 'Linear synteny view (helper)',
12
+ viewMetadata: {
13
+ hiddenFromGUI: true,
14
+ },
15
+ stateModel: linearSyntenyViewHelperModelFactory(pluginManager),
16
+ ReactComponent: UnusedComponent,
17
+ });
18
+ });
19
+ }
@@ -0,0 +1,30 @@
1
+ import { Instance } from 'mobx-state-tree';
2
+ import PluginManager from '@jbrowse/core/PluginManager';
3
+ export declare function linearSyntenyViewHelperModelFactory(pluginManager: PluginManager): import("mobx-state-tree").IModelType<{
4
+ id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
5
+ type: import("mobx-state-tree").IType<string | undefined, string, string>;
6
+ tracks: import("mobx-state-tree").IArrayType<import("mobx-state-tree").IAnyType>;
7
+ height: import("mobx-state-tree").IType<number | undefined, number, number>;
8
+ level: import("mobx-state-tree").ISimpleType<number>;
9
+ }, {
10
+ /**
11
+ * #action
12
+ */
13
+ setHeight(n: number): number;
14
+ /**
15
+ * #action
16
+ */
17
+ showTrack(trackId: string, initialSnapshot?: {}): void;
18
+ /**
19
+ * #action
20
+ */
21
+ hideTrack(trackId: string): number;
22
+ /**
23
+ * #action
24
+ */
25
+ toggleTrack(trackId: string): boolean;
26
+ } & {
27
+ readonly assemblyNames: (string | undefined)[];
28
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>;
29
+ export type LinearSyntenyViewHelperStateModel = ReturnType<typeof linearSyntenyViewHelperModelFactory>;
30
+ export type LinearSyntenyViewHelperModel = Instance<LinearSyntenyViewHelperStateModel>;
@@ -0,0 +1,102 @@
1
+ import { getRoot, resolveIdentifier, types, getParent, } from 'mobx-state-tree';
2
+ import { transaction } from 'mobx';
3
+ import { ElementId } from '@jbrowse/core/util/types/mst';
4
+ export function linearSyntenyViewHelperModelFactory(pluginManager) {
5
+ return types
6
+ .model('LinearSyntenyViewHelper', {
7
+ /**
8
+ * #property
9
+ */
10
+ id: ElementId,
11
+ /**
12
+ * #property
13
+ */
14
+ type: 'LinearSyntenyViewHelper',
15
+ /**
16
+ * #property
17
+ */
18
+ tracks: types.array(pluginManager.pluggableMstType('track', 'stateModel')),
19
+ /**
20
+ * #property
21
+ */
22
+ height: 100,
23
+ /**
24
+ * #property
25
+ */
26
+ level: types.number,
27
+ })
28
+ .actions(self => ({
29
+ /**
30
+ * #action
31
+ */
32
+ setHeight(n) {
33
+ self.height = n;
34
+ return self.height;
35
+ },
36
+ /**
37
+ * #action
38
+ */
39
+ showTrack(trackId, initialSnapshot = {}) {
40
+ const schema = pluginManager.pluggableConfigSchemaType('track');
41
+ const configuration = resolveIdentifier(schema, getRoot(self), trackId);
42
+ if (!configuration) {
43
+ throw new Error(`track not found ${trackId}`);
44
+ }
45
+ const trackType = pluginManager.getTrackType(configuration.type);
46
+ if (!trackType) {
47
+ throw new Error(`unknown track type ${configuration.type}`);
48
+ }
49
+ const viewType = pluginManager.getViewType(self.type);
50
+ const supportedDisplays = new Set(viewType.displayTypes.map(d => d.name));
51
+ const displayConf = configuration.displays.find((d) => supportedDisplays.has(d.type));
52
+ if (!displayConf) {
53
+ throw new Error(`could not find a compatible display for view type ${self.type}`);
54
+ }
55
+ self.tracks.push(trackType.stateModel.create({
56
+ ...initialSnapshot,
57
+ type: configuration.type,
58
+ configuration,
59
+ displays: [
60
+ {
61
+ type: displayConf.type,
62
+ configuration: displayConf,
63
+ },
64
+ ],
65
+ }));
66
+ },
67
+ /**
68
+ * #action
69
+ */
70
+ hideTrack(trackId) {
71
+ const schema = pluginManager.pluggableConfigSchemaType('track');
72
+ const config = resolveIdentifier(schema, getRoot(self), trackId);
73
+ const shownTracks = self.tracks.filter(t => t.configuration === config);
74
+ transaction(() => {
75
+ shownTracks.forEach(t => {
76
+ self.tracks.remove(t);
77
+ });
78
+ });
79
+ return shownTracks.length;
80
+ },
81
+ /**
82
+ * #action
83
+ */
84
+ toggleTrack(trackId) {
85
+ const hiddenCount = this.hideTrack(trackId);
86
+ if (!hiddenCount) {
87
+ this.showTrack(trackId);
88
+ return true;
89
+ }
90
+ return false;
91
+ },
92
+ }))
93
+ .views(self => ({
94
+ get assemblyNames() {
95
+ const p = getParent(self, 2);
96
+ return [
97
+ p.views[self.level].assemblyNames[0],
98
+ p.views[self.level + 1].assemblyNames[0],
99
+ ];
100
+ },
101
+ }));
102
+ }
package/esm/index.js CHANGED
@@ -6,6 +6,7 @@ import LinearComparativeViewF from './LinearComparativeView';
6
6
  import LinearSyntenyDisplayF from './LinearSyntenyDisplay';
7
7
  import LGVSyntenyDisplayF from './LGVSyntenyDisplay';
8
8
  import LinearSyntenyViewF from './LinearSyntenyView';
9
+ import LinearSyntenyViewHelperF from './LinearSyntenyViewHelper';
9
10
  import LaunchLinearSyntenyViewF from './LaunchLinearSyntenyView';
10
11
  import SyntenyTrackF from './SyntenyTrack';
11
12
  import LinearReadVsRefMenuItemF from './LinearReadVsRef';
@@ -15,6 +16,7 @@ export default class LinearComparativeViewPlugin extends Plugin {
15
16
  this.name = 'LinearComparativeViewPlugin';
16
17
  }
17
18
  install(pluginManager) {
19
+ LinearSyntenyViewHelperF(pluginManager);
18
20
  LinearComparativeViewF(pluginManager);
19
21
  LinearSyntenyViewF(pluginManager);
20
22
  LinearComparativeDisplayF(pluginManager);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-linear-comparative-view",
3
- "version": "2.15.3",
3
+ "version": "2.16.0",
4
4
  "description": "JBrowse 2 linear comparative view",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -61,5 +61,5 @@
61
61
  "publishConfig": {
62
62
  "access": "public"
63
63
  },
64
- "gitHead": "c0f82fe7b210622dd462e702641cc6da01109c6e"
64
+ "gitHead": "1e6d4fbc27ce684eed19e3c217f34bd2da24ab75"
65
65
  }
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import { LinearSyntenyViewModel } from '../../model';
3
- declare const Selector: ({ model, assembly1, assembly2, setShowTrackId, }: {
4
- model: LinearSyntenyViewModel;
5
- assembly1: string;
6
- assembly2: string;
7
- setShowTrackId: (arg: string) => void;
8
- }) => React.JSX.Element;
9
- export default Selector;
@@ -1,138 +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 (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- const react_1 = __importStar(require("react"));
30
- const material_1 = require("@mui/material");
31
- const mui_1 = require("tss-react/mui");
32
- const mobx_react_1 = require("mobx-react");
33
- const util_1 = require("@jbrowse/core/util");
34
- const ui_1 = require("@jbrowse/core/ui");
35
- const ImportCustomTrack_1 = __importDefault(require("./ImportCustomTrack"));
36
- const ImportSyntenyTrackSelector_1 = __importDefault(require("./ImportSyntenyTrackSelector"));
37
- const useStyles = (0, mui_1.makeStyles)()(theme => ({
38
- importFormContainer: {
39
- padding: theme.spacing(4),
40
- margin: '0 auto',
41
- },
42
- assemblySelector: {
43
- width: '75%',
44
- margin: '0 auto',
45
- },
46
- }));
47
- function TrackSelector({ setSessionTrackData, setShowTrackId, sessionTrackData, assembly1, assembly2, model, }) {
48
- const [choice, setChoice] = (0, react_1.useState)('tracklist');
49
- (0, react_1.useEffect)(() => {
50
- if (choice === 'none') {
51
- setSessionTrackData(undefined);
52
- setShowTrackId(undefined);
53
- }
54
- }, [choice, setSessionTrackData, setShowTrackId]);
55
- return (react_1.default.createElement(react_1.default.Fragment, null,
56
- react_1.default.createElement(material_1.FormControl, null,
57
- react_1.default.createElement(material_1.FormLabel, { id: "group-label" }, "(Optional) Select or add a synteny track"),
58
- react_1.default.createElement(material_1.RadioGroup, { row: true, value: choice, onChange: event => {
59
- setChoice(event.target.value);
60
- }, "aria-labelledby": "group-label" },
61
- react_1.default.createElement(material_1.FormControlLabel, { value: "none", control: react_1.default.createElement(material_1.Radio, null), label: "None" }),
62
- react_1.default.createElement(material_1.FormControlLabel, { value: "tracklist", control: react_1.default.createElement(material_1.Radio, null), label: "Existing track" }),
63
- react_1.default.createElement(material_1.FormControlLabel, { value: "custom", control: react_1.default.createElement(material_1.Radio, null), label: "New track" }))),
64
- choice === 'custom' ? (react_1.default.createElement(ImportCustomTrack_1.default, { setSessionTrackData: setSessionTrackData, sessionTrackData: sessionTrackData, assembly2: assembly2, assembly1: assembly1 })) : null,
65
- choice === 'tracklist' ? (react_1.default.createElement(ImportSyntenyTrackSelector_1.default, { model: model, assembly1: assembly1, assembly2: assembly2, setShowTrackId: setShowTrackId })) : null));
66
- }
67
- const LinearSyntenyViewImportForm = (0, mobx_react_1.observer)(function ({ model, }) {
68
- const { classes } = useStyles();
69
- const session = (0, util_1.getSession)(model);
70
- const { assemblyNames } = session;
71
- const [assembly2, setAssembly2] = (0, react_1.useState)(assemblyNames[0] || '');
72
- const [assembly1, setAssembly1] = (0, react_1.useState)(assemblyNames[0] || '');
73
- const [error, setError] = (0, react_1.useState)();
74
- const [sessionTrackData, setSessionTrackData] = (0, react_1.useState)();
75
- const [showTrackId, setShowTrackId] = (0, react_1.useState)();
76
- async function onOpenClick() {
77
- try {
78
- if (!(0, util_1.isSessionWithAddTracks)(session)) {
79
- return;
80
- }
81
- setError(undefined);
82
- const { assemblyManager } = session;
83
- const assemblies = [assembly1, assembly2];
84
- model.setViews(await Promise.all(assemblies.map(async (sel) => {
85
- const asm = await assemblyManager.waitForAssembly(sel);
86
- if (!asm) {
87
- throw new Error(`Assembly ${sel} failed to load`);
88
- }
89
- return {
90
- type: 'LinearGenomeView',
91
- bpPerPx: 1,
92
- offsetPx: 0,
93
- hideHeader: true,
94
- displayedRegions: asm.regions,
95
- };
96
- })));
97
- model.views.forEach(view => {
98
- view.setWidth(model.width);
99
- });
100
- model.views.forEach(view => {
101
- view.showAllRegions();
102
- });
103
- if (sessionTrackData) {
104
- session.addTrackConf(sessionTrackData);
105
- model.toggleTrack(sessionTrackData.trackId);
106
- }
107
- else if (showTrackId) {
108
- model.showTrack(showTrackId);
109
- }
110
- }
111
- catch (e) {
112
- console.error(e);
113
- setError(e);
114
- }
115
- }
116
- // this is a combination of any displayed error message we have
117
- const displayError = error;
118
- return (react_1.default.createElement(material_1.Container, { className: classes.importFormContainer },
119
- displayError ? react_1.default.createElement(ui_1.ErrorMessage, { error: displayError }) : null,
120
- react_1.default.createElement(material_1.Grid, { container: true, spacing: 1, justifyContent: "center", alignItems: "center", className: classes.assemblySelector },
121
- react_1.default.createElement(material_1.Grid, { item: true },
122
- react_1.default.createElement(material_1.Paper, { style: { padding: 12 } },
123
- react_1.default.createElement("p", { style: { textAlign: 'center' } }, "Select assemblies for linear synteny view"),
124
- react_1.default.createElement(material_1.Grid, { container: true, spacing: 1, justifyContent: "center", alignItems: "center" },
125
- react_1.default.createElement(material_1.Grid, { item: true },
126
- react_1.default.createElement(ui_1.AssemblySelector, { selected: assembly1, onChange: val => {
127
- setAssembly1(val);
128
- }, session: session })),
129
- react_1.default.createElement(material_1.Grid, { item: true },
130
- react_1.default.createElement(ui_1.AssemblySelector, { selected: assembly2, onChange: val => {
131
- setAssembly2(val);
132
- }, session: session })),
133
- react_1.default.createElement(material_1.Grid, { item: true },
134
- react_1.default.createElement(material_1.FormControl, null,
135
- react_1.default.createElement(material_1.Button, { onClick: onOpenClick, variant: "contained", color: "primary" }, "Launch"))))),
136
- react_1.default.createElement(TrackSelector, { setShowTrackId: setShowTrackId, assembly2: assembly2, assembly1: assembly1, setSessionTrackData: setSessionTrackData, sessionTrackData: sessionTrackData, model: model })))));
137
- });
138
- exports.default = LinearSyntenyViewImportForm;
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import { LinearSyntenyViewModel } from '../../model';
3
- declare const Selector: ({ model, assembly1, assembly2, setShowTrackId, }: {
4
- model: LinearSyntenyViewModel;
5
- assembly1: string;
6
- assembly2: string;
7
- setShowTrackId: (arg: string) => void;
8
- }) => React.JSX.Element;
9
- export default Selector;
@@ -1,110 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { Button, Container, FormControl, FormLabel, FormControlLabel, Grid, Paper, Radio, RadioGroup, } from '@mui/material';
3
- import { makeStyles } from 'tss-react/mui';
4
- import { observer } from 'mobx-react';
5
- import { getSession, isSessionWithAddTracks } from '@jbrowse/core/util';
6
- import { ErrorMessage, AssemblySelector } from '@jbrowse/core/ui';
7
- import ImportCustomTrack from './ImportCustomTrack';
8
- import ImportSyntenyTrackSelector from './ImportSyntenyTrackSelector';
9
- const useStyles = makeStyles()(theme => ({
10
- importFormContainer: {
11
- padding: theme.spacing(4),
12
- margin: '0 auto',
13
- },
14
- assemblySelector: {
15
- width: '75%',
16
- margin: '0 auto',
17
- },
18
- }));
19
- function TrackSelector({ setSessionTrackData, setShowTrackId, sessionTrackData, assembly1, assembly2, model, }) {
20
- const [choice, setChoice] = useState('tracklist');
21
- useEffect(() => {
22
- if (choice === 'none') {
23
- setSessionTrackData(undefined);
24
- setShowTrackId(undefined);
25
- }
26
- }, [choice, setSessionTrackData, setShowTrackId]);
27
- return (React.createElement(React.Fragment, null,
28
- React.createElement(FormControl, null,
29
- React.createElement(FormLabel, { id: "group-label" }, "(Optional) Select or add a synteny track"),
30
- React.createElement(RadioGroup, { row: true, value: choice, onChange: event => {
31
- setChoice(event.target.value);
32
- }, "aria-labelledby": "group-label" },
33
- React.createElement(FormControlLabel, { value: "none", control: React.createElement(Radio, null), label: "None" }),
34
- React.createElement(FormControlLabel, { value: "tracklist", control: React.createElement(Radio, null), label: "Existing track" }),
35
- React.createElement(FormControlLabel, { value: "custom", control: React.createElement(Radio, null), label: "New track" }))),
36
- choice === 'custom' ? (React.createElement(ImportCustomTrack, { setSessionTrackData: setSessionTrackData, sessionTrackData: sessionTrackData, assembly2: assembly2, assembly1: assembly1 })) : null,
37
- choice === 'tracklist' ? (React.createElement(ImportSyntenyTrackSelector, { model: model, assembly1: assembly1, assembly2: assembly2, setShowTrackId: setShowTrackId })) : null));
38
- }
39
- const LinearSyntenyViewImportForm = observer(function ({ model, }) {
40
- const { classes } = useStyles();
41
- const session = getSession(model);
42
- const { assemblyNames } = session;
43
- const [assembly2, setAssembly2] = useState(assemblyNames[0] || '');
44
- const [assembly1, setAssembly1] = useState(assemblyNames[0] || '');
45
- const [error, setError] = useState();
46
- const [sessionTrackData, setSessionTrackData] = useState();
47
- const [showTrackId, setShowTrackId] = useState();
48
- async function onOpenClick() {
49
- try {
50
- if (!isSessionWithAddTracks(session)) {
51
- return;
52
- }
53
- setError(undefined);
54
- const { assemblyManager } = session;
55
- const assemblies = [assembly1, assembly2];
56
- model.setViews(await Promise.all(assemblies.map(async (sel) => {
57
- const asm = await assemblyManager.waitForAssembly(sel);
58
- if (!asm) {
59
- throw new Error(`Assembly ${sel} failed to load`);
60
- }
61
- return {
62
- type: 'LinearGenomeView',
63
- bpPerPx: 1,
64
- offsetPx: 0,
65
- hideHeader: true,
66
- displayedRegions: asm.regions,
67
- };
68
- })));
69
- model.views.forEach(view => {
70
- view.setWidth(model.width);
71
- });
72
- model.views.forEach(view => {
73
- view.showAllRegions();
74
- });
75
- if (sessionTrackData) {
76
- session.addTrackConf(sessionTrackData);
77
- model.toggleTrack(sessionTrackData.trackId);
78
- }
79
- else if (showTrackId) {
80
- model.showTrack(showTrackId);
81
- }
82
- }
83
- catch (e) {
84
- console.error(e);
85
- setError(e);
86
- }
87
- }
88
- // this is a combination of any displayed error message we have
89
- const displayError = error;
90
- return (React.createElement(Container, { className: classes.importFormContainer },
91
- displayError ? React.createElement(ErrorMessage, { error: displayError }) : null,
92
- React.createElement(Grid, { container: true, spacing: 1, justifyContent: "center", alignItems: "center", className: classes.assemblySelector },
93
- React.createElement(Grid, { item: true },
94
- React.createElement(Paper, { style: { padding: 12 } },
95
- React.createElement("p", { style: { textAlign: 'center' } }, "Select assemblies for linear synteny view"),
96
- React.createElement(Grid, { container: true, spacing: 1, justifyContent: "center", alignItems: "center" },
97
- React.createElement(Grid, { item: true },
98
- React.createElement(AssemblySelector, { selected: assembly1, onChange: val => {
99
- setAssembly1(val);
100
- }, session: session })),
101
- React.createElement(Grid, { item: true },
102
- React.createElement(AssemblySelector, { selected: assembly2, onChange: val => {
103
- setAssembly2(val);
104
- }, session: session })),
105
- React.createElement(Grid, { item: true },
106
- React.createElement(FormControl, null,
107
- React.createElement(Button, { onClick: onOpenClick, variant: "contained", color: "primary" }, "Launch"))))),
108
- React.createElement(TrackSelector, { setShowTrackId: setShowTrackId, assembly2: assembly2, assembly1: assembly1, setSessionTrackData: setSessionTrackData, sessionTrackData: sessionTrackData, model: model })))));
109
- });
110
- export default LinearSyntenyViewImportForm;